├── .gitignore ├── .metadata ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── flutter_bloc_architecture │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── fonts │ ├── ArialRoundedMTBold.ttf │ ├── Muli-Bold.ttf │ ├── OpenSans-Bold.ttf │ ├── OpenSans-Light.ttf │ ├── OpenSans-Regular.ttf │ └── OpenSans-Semibold.ttf └── images │ ├── logo.png │ └── powered_by.png ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ └── contents.xcworkspacedata └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── main.dart └── src │ ├── bloc │ ├── bottom_nav │ │ ├── bottom_nav_cubit.dart │ │ └── checkbox_cubit.dart │ └── login │ │ ├── login.dart │ │ ├── login_bloc.dart │ │ ├── login_event.dart │ │ └── login_state.dart │ ├── bloc_delegate │ └── simple_bloc_delegate.dart │ ├── constants │ ├── font_constants.dart │ ├── page_route_constants.dart │ ├── regex_constant.dart │ ├── string_constant.dart │ └── url_constant.dart │ ├── di │ └── app_config.dart │ ├── localization │ └── app_localizations.dart │ ├── models │ ├── local_data_models │ │ └── login_user_details.dart │ └── network_data_models │ │ └── login │ │ ├── request │ │ ├── login_request.dart │ │ └── login_request.g.dart │ │ └── response │ │ ├── data.dart │ │ ├── data.g.dart │ │ ├── login_response.dart │ │ ├── login_response.g.dart │ │ ├── result.dart │ │ └── result.g.dart │ ├── my_app.dart │ ├── network │ ├── api_client │ │ ├── api_rest_client.dart │ │ └── api_rest_client.g.dart │ └── repository │ │ └── api_repository.dart │ ├── resources │ ├── app_colors.dart │ ├── app_localization.dart │ ├── app_theme.dart │ ├── dimens.dart │ ├── font_family.dart │ ├── hex_color.dart │ └── text_styles.dart │ ├── sharedpref │ ├── constants │ │ └── preferences.dart │ └── preference_connector.dart │ ├── ui │ ├── common │ │ └── ui_helpers.dart │ ├── custom_widgets │ │ └── custom_text_field.dart │ └── screens │ │ ├── home │ │ └── home_screen.dart │ │ ├── login │ │ └── login_screen.dart │ │ └── splash │ │ └── splash_screen.dart │ └── utils │ ├── date_time_util.dart │ ├── device_utils.dart │ ├── helper.dart │ ├── navigation_service.dart │ ├── screen_router.dart │ ├── url_launcher.dart │ ├── utils.dart │ └── validator.dart ├── pubspec.lock ├── pubspec.yaml └── test └── widget_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Exceptions to above rules. 37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 38 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 0b8abb4724aa590dd0f429683339b1e045a1594d 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter Bloc Architecture 2 | 3 | 4 | # flutter_bloc [![pub package](https://img.shields.io/pub/v/flutter_bloc)](https://pub.dev/packages/flutter_bloc) 5 | 6 | Flutter Widgets that make it easy to implement the BLoC (Business Logic Component) design pattern. Built to be used with the bloc state management package. 7 | 8 | ## *Why Bloc?* 9 | Bloc makes it easy to separate presentation from business logic, making your code fast, easy to test, and reusable. 10 | 11 | 12 | When building production quality applications, managing state becomes critical. 13 | 14 | As developers we want to: 15 | 16 | - know what state our application is in at any point in time. 17 | - easily test every case to make sure our app is responding appropriately. 18 | - record every single user interaction in our application so that we can make data-driven decisions. 19 | - work as efficiently as possible and reuse components both within our application and across other applications. 20 | - have many developers seamlessly working within a single code base following the same patterns and conventions. 21 | - develop fast and reactive apps. 22 | 23 | There are many state management solutions and deciding which one to use can be a daunting task. 24 | 25 | Bloc was designed with three core values in mind: 26 | 27 | - Simple 28 | 29 | - Easy to understand & can be used by developers with varying skill levels. 30 | - Powerful 31 | 32 | - Help make amazing, complex applications by composing them of smaller components. 33 | 34 | - Testable 35 | 36 | - Easily test every aspect of an application so that we can iterate with confidence. 37 | 38 | Bloc attempts to make state changes predictable by regulating when a state change can occur and enforcing a single way to change state throughout an entire application. 39 | 40 | ## *Architecture* 41 | 42 | 43 | Bloc Architecture 44 | 45 | Using Bloc allows us to separate our application into three layers: 46 | 47 | - Data 48 | 49 | - Data Provider 50 | 51 | - Repository 52 | 53 | - Business Logic 54 | - Presentation 55 | 56 | We're going to start at the lowest level layer (farthest from the user interface) and work our way up to the presentation layer. 57 | 58 | ## *Data Layer* 59 | The data layer's responsibility is to retrieve/manipulate data from one or more sources. 60 | 61 | The data layer can be split into two parts: 62 | 63 | - Repository 64 | - Data Provide 65 | 66 | This layer is the lowest level of the application and interacts with databases, network requests, and other asynchronous data sources. 67 | 68 | ## *Data Provider* 69 | 70 | The data provider's responsibility is to provide raw data. The data provider should be generic and versatile. 71 | 72 | The data provider will usually expose simple APIs to perform CRUD operations. We might have a createData, readData, updateData, and deleteData method as part of our data layer. 73 | 74 | ```dart 75 | #Login Request 76 | 77 | @JsonSerializable() 78 | class LoginRequest { 79 | String email; 80 | String password; 81 | 82 | LoginRequest({ 83 | this.email, 84 | this.password, 85 | }); 86 | 87 | factory LoginRequest.fromJson(Map json) => 88 | _$LoginRequestFromJson(json); 89 | 90 | Map toJson() => _$LoginRequestToJson(this); 91 | } 92 | 93 | #Login Response 94 | 95 | @JsonSerializable() 96 | class LoginResponse { 97 | String status; 98 | int code; 99 | String message; 100 | Result result; 101 | 102 | LoginResponse({ 103 | this.status, 104 | this.code, 105 | this.message, 106 | this.result, 107 | }); 108 | 109 | factory LoginResponse.fromJson(Map json) => 110 | _$LoginResponseFromJson(json); 111 | 112 | Map toJson() => _$LoginResponseToJson(this); 113 | } 114 | 115 | ``` 116 | ## *Repository* 117 | 118 | The repository layer is a wrapper around one or more data providers with which the Bloc Layer communicates. 119 | 120 | ```dart 121 | class ApiRepository { 122 | ApiRestClient apiRestClient; 123 | 124 | ApiRepository() { 125 | Dio _dio = Dio(); 126 | _dio.options.headers["Content-Type"] = "application/json"; 127 | apiRestClient = ApiRestClient(_dio); 128 | } 129 | 130 | Future login({ 131 | @required String email, 132 | @required String password, 133 | }) async { 134 | LoginRequest loginRequest = LoginRequest( 135 | email: email, 136 | password: password, 137 | ); 138 | return await ApiRestClient(Dio()).login(loginRequest); 139 | } 140 | } 141 | ``` 142 | As you can see, our repository layer can interact with multiple data providers and perform transformations on the data before handing the result to the business logic Layer. 143 | 144 | ## *Bloc (Business Logic) Layer* 145 | 146 | The bloc layer's responsibility is to respond to events from the presentation layer with new states. The bloc layer can depend on one or more repositories to retrieve data needed to build up the application state. 147 | 148 | Think of the bloc layer as the bridge between the user interface (presentation layer) and the data layer. The bloc layer takes events generated by user input and then communicates with repository in order to build a new state for the presentation layer to consume. 149 | 150 | ```dart 151 | class LoginBloc extends Bloc { 152 | final ApiRepository apiRepository; 153 | final Validator validator = Validator(); 154 | 155 | LoginBloc({@required this.apiRepository}); 156 | 157 | @override 158 | LoginState get initialState => UserUnavailable(); 159 | 160 | @override 161 | Stream mapEventToState(LoginEvent event) async* { 162 | if (event is SignInUser) { 163 | yield LoginLoading(); 164 | try { 165 | LoginResponse loginResponse = await apiRepository.login( 166 | email: event.email, 167 | password: event.password, 168 | ); 169 | if (loginResponse != null) { 170 | Helper.printLogValue("UserLoggedIn"); 171 | yield UserLoggedIn(); 172 | } else { 173 | Helper.printLogValue("UserLoggedOut"); 174 | yield UserLoggedOut(); 175 | } 176 | } catch (error) { 177 | Helper.printLogValue("LoginFailure"); 178 | yield LoginFailure(error: error.toString()); 179 | } 180 | } 181 | if (event is PasswordChanged) { 182 | yield state.copyWith( 183 | isPasswordValid: _isPasswordValid(event.password), 184 | ); 185 | } 186 | 187 | if (event is EmailChanged) { 188 | yield state.copyWith( 189 | isEmailValid: _isEmailValid(event.email), 190 | ); 191 | } 192 | } 193 | 194 | bool _isEmailValid(String email) { 195 | return validator.validateEmail(email); 196 | } 197 | 198 | bool _isPasswordValid(String password) { 199 | return validator.validatePassword(password); 200 | } 201 | } 202 | 203 | ``` 204 | ## *Presentation Layer* 205 | 206 | The presentation layer's responsibility is to figure out how to render itself based on one or more bloc states. In addition, it should handle user input and application lifecycle events. 207 | 208 | ```dart 209 | Container( 210 | width: size.width, 211 | height: kBottomNavigationBarHeight, 212 | child: BlocListener( 213 | listener: (context, state) { 214 | if (state is UserLoggedIn) { 215 | Navigator.of(context).pushNamedAndRemoveUntil( 216 | PageRouteConstants.home_screen, 217 | (Route route) => false); 218 | } else if (state is LoginFailure) { 219 | Helper.showAlert(context, StringConstant.error_message, 220 | StringConstant.invalid_user_credentials); 221 | } 222 | }, 223 | child: BlocBuilder( 224 | builder: (context, state) { 225 | if (state is LoginLoading) { 226 | return Helper.progressWidget(progressKey); 227 | } else { 228 | return RaisedButton( 229 | child: Text( 230 | StringConstant.sign_in, 231 | style: AppTextStyles.getMediumText( 232 | size.width, AppColors.white, FontConstant.kSemiBold), 233 | ), 234 | onPressed: () { 235 | if (!(_emailController.text.length > 0) || 236 | !state.isEmailValid) { 237 | showInSnackBar(StringConstant.invalid_email); 238 | } else if (!(_passwordController.text.length > 0) || 239 | !state.isPasswordValid) { 240 | showInSnackBar(StringConstant.invalid_password); 241 | } else { 242 | Helper.checkConnectivity().then((internetStatus) { 243 | if (internetStatus) { 244 | if (progressKey.currentWidget == null) { 245 | BlocProvider.of(context).add( 246 | SignInUser( 247 | email: _emailController.text, 248 | password: _passwordController.text, 249 | ), 250 | ); 251 | } 252 | } else { 253 | Helper.showAlert(context, StringConstant.internet_alert, 254 | StringConstant.please_check_internet_connectivity); 255 | } 256 | }); 257 | } 258 | }, 259 | color: Theme.of(context).primaryColor, 260 | shape: RoundedRectangleBorder( 261 | borderRadius: BorderRadius.circular(Dimens.px28), 262 | ), 263 | ); 264 | } 265 | }, 266 | ), 267 | ), 268 | ); 269 | ``` 270 | ## *Pros of BLoC* 271 | 272 | - Easy to separate UI from logic 273 | - Easy to test code 274 | - Easy to reuse code 275 | - Good performance 276 | 277 | ## *Cons of BLoC* 278 | 279 | - Technically, you need to use streams in both directions, creating a lot of boilerplate. However, many people cheat this by using streams only from the backend to the UI, but when events occur they’re simply calling functions directly instead of feeding those events into a sink. 280 | 281 | - More boilerplate for small app, but it can be worth it for anything larger than a small app. 282 | 283 | ## *Refrences* 284 | 1. https://bloclibrary.dev 285 | 2. https://pub.dev/packages/bloc 286 | 3. https://flutter.dev/ 287 | 4. https://blog.codemagic.io/flutter-tutorial-pros-and-cons-of-state-management-approaches/ 288 | 289 | ## *User login credentials* 290 | ```json 291 | { 292 | "email":"paras@aeologic.com", 293 | "password":"Paras@123" 294 | } 295 | ``` 296 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.example.flutter_bloc_architecture" 42 | minSdkVersion 16 43 | targetSdkVersion 28 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 47 | } 48 | 49 | buildTypes { 50 | release { 51 | // TODO: Add your own signing config for the release build. 52 | // Signing with the debug keys for now, so `flutter run --release` works. 53 | signingConfig signingConfigs.debug 54 | } 55 | } 56 | } 57 | 58 | flutter { 59 | source '../..' 60 | } 61 | 62 | dependencies { 63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 64 | testImplementation 'junit:junit:4.12' 65 | androidTestImplementation 'androidx.test:runner:1.1.1' 66 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 67 | } 68 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/flutter_bloc_architecture/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.flutter_bloc_architecture 2 | 3 | import androidx.annotation.NonNull; 4 | import io.flutter.embedding.android.FlutterActivity 5 | import io.flutter.embedding.engine.FlutterEngine 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 10 | GeneratedPluginRegistrant.registerWith(flutterEngine); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /assets/fonts/ArialRoundedMTBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/assets/fonts/ArialRoundedMTBold.ttf -------------------------------------------------------------------------------- /assets/fonts/Muli-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/assets/fonts/Muli-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/OpenSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/assets/fonts/OpenSans-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/OpenSans-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/assets/fonts/OpenSans-Light.ttf -------------------------------------------------------------------------------- /assets/fonts/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/assets/fonts/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/OpenSans-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/assets/fonts/OpenSans-Semibold.ttf -------------------------------------------------------------------------------- /assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/assets/images/logo.png -------------------------------------------------------------------------------- /assets/images/powered_by.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/assets/images/powered_by.png -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | generated_key_values = {} 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) do |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | generated_key_values[podname] = podpath 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | end 32 | generated_key_values 33 | end 34 | 35 | target 'Runner' do 36 | use_frameworks! 37 | use_modular_headers! 38 | 39 | # Flutter Pod 40 | 41 | copied_flutter_dir = File.join(__dir__, 'Flutter') 42 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') 43 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') 44 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) 45 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. 46 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. 47 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. 48 | 49 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') 50 | unless File.exist?(generated_xcode_build_settings_path) 51 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" 52 | end 53 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) 54 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; 55 | 56 | unless File.exist?(copied_framework_path) 57 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) 58 | end 59 | unless File.exist?(copied_podspec_path) 60 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) 61 | end 62 | end 63 | 64 | # Keep pod path relative so it can be checked into Podfile.lock. 65 | pod 'Flutter', :path => 'Flutter' 66 | 67 | # Plugin Pods 68 | 69 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 70 | # referring to absolute paths on developers' machines. 71 | system('rm -rf .symlinks') 72 | system('mkdir -p .symlinks/plugins') 73 | plugin_pods = parse_KV_file('../.flutter-plugins') 74 | plugin_pods.each do |name, path| 75 | symlink = File.join('.symlinks', 'plugins', name) 76 | File.symlink(path, symlink) 77 | pod name, :path => File.join(symlink, 'ios') 78 | end 79 | end 80 | 81 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. 82 | install! 'cocoapods', :disable_input_output_paths => true 83 | 84 | post_install do |installer| 85 | installer.pods_project.targets.each do |target| 86 | target.build_configurations.each do |config| 87 | config.build_settings['ENABLE_BITCODE'] = 'NO' 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - path_provider (0.0.1): 4 | - Flutter 5 | - path_provider_macos (0.0.1): 6 | - Flutter 7 | - shared_preferences (0.0.1): 8 | - Flutter 9 | - shared_preferences_macos (0.0.1): 10 | - Flutter 11 | - shared_preferences_web (0.0.1): 12 | - Flutter 13 | - url_launcher (0.0.1): 14 | - Flutter 15 | - url_launcher_macos (0.0.1): 16 | - Flutter 17 | - url_launcher_web (0.0.1): 18 | - Flutter 19 | 20 | DEPENDENCIES: 21 | - Flutter (from `Flutter`) 22 | - path_provider (from `.symlinks/plugins/path_provider/ios`) 23 | - path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`) 24 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) 25 | - shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`) 26 | - shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`) 27 | - url_launcher (from `.symlinks/plugins/url_launcher/ios`) 28 | - url_launcher_macos (from `.symlinks/plugins/url_launcher_macos/ios`) 29 | - url_launcher_web (from `.symlinks/plugins/url_launcher_web/ios`) 30 | 31 | EXTERNAL SOURCES: 32 | Flutter: 33 | :path: Flutter 34 | path_provider: 35 | :path: ".symlinks/plugins/path_provider/ios" 36 | path_provider_macos: 37 | :path: ".symlinks/plugins/path_provider_macos/ios" 38 | shared_preferences: 39 | :path: ".symlinks/plugins/shared_preferences/ios" 40 | shared_preferences_macos: 41 | :path: ".symlinks/plugins/shared_preferences_macos/ios" 42 | shared_preferences_web: 43 | :path: ".symlinks/plugins/shared_preferences_web/ios" 44 | url_launcher: 45 | :path: ".symlinks/plugins/url_launcher/ios" 46 | url_launcher_macos: 47 | :path: ".symlinks/plugins/url_launcher_macos/ios" 48 | url_launcher_web: 49 | :path: ".symlinks/plugins/url_launcher_web/ios" 50 | 51 | SPEC CHECKSUMS: 52 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec 53 | path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d 54 | path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0 55 | shared_preferences: 430726339841afefe5142b9c1f50cb6bd7793e01 56 | shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087 57 | shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9 58 | url_launcher: a1c0cc845906122c4784c542523d8cacbded5626 59 | url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313 60 | url_launcher_web: e5527357f037c87560776e36436bf2b0288b965c 61 | 62 | PODFILE CHECKSUM: 1b66dae606f75376c5f2135a8290850eeb09ae83 63 | 64 | COCOAPODS: 1.8.4 65 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 15 | 8C19605C9CD80196A2A080A7 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAFCC0DB5DD9156BCE4FBB4B /* Pods_Runner.framework */; }; 16 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 17 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 18 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 19 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 20 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXCopyFilesBuildPhase section */ 24 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 25 | isa = PBXCopyFilesBuildPhase; 26 | buildActionMask = 2147483647; 27 | dstPath = ""; 28 | dstSubfolderSpec = 10; 29 | files = ( 30 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 31 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 32 | ); 33 | name = "Embed Frameworks"; 34 | runOnlyForDeploymentPostprocessing = 0; 35 | }; 36 | /* End PBXCopyFilesBuildPhase section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 0BC3DEF66F606C30C298C59E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 40 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 41 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 42 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 43 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 44 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 45 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 47 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 48 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 49 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 50 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 52 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 53 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 54 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | AAFCC0DB5DD9156BCE4FBB4B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | ABFBF0F6C0BB453E818F25B3 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 57 | B73E8A5028C8A5587D0F9C34 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 66 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 67 | 8C19605C9CD80196A2A080A7 /* Pods_Runner.framework in Frameworks */, 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | /* End PBXFrameworksBuildPhase section */ 72 | 73 | /* Begin PBXGroup section */ 74 | 53C1D23CFA3EC158D337C074 /* Pods */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | ABFBF0F6C0BB453E818F25B3 /* Pods-Runner.debug.xcconfig */, 78 | B73E8A5028C8A5587D0F9C34 /* Pods-Runner.release.xcconfig */, 79 | 0BC3DEF66F606C30C298C59E /* Pods-Runner.profile.xcconfig */, 80 | ); 81 | name = Pods; 82 | path = Pods; 83 | sourceTree = ""; 84 | }; 85 | 9740EEB11CF90186004384FC /* Flutter */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | 3B80C3931E831B6300D905FE /* App.framework */, 89 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 90 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 91 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 92 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 93 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 94 | ); 95 | name = Flutter; 96 | sourceTree = ""; 97 | }; 98 | 97C146E51CF9000F007C117D = { 99 | isa = PBXGroup; 100 | children = ( 101 | 9740EEB11CF90186004384FC /* Flutter */, 102 | 97C146F01CF9000F007C117D /* Runner */, 103 | 97C146EF1CF9000F007C117D /* Products */, 104 | 53C1D23CFA3EC158D337C074 /* Pods */, 105 | F6BB80108ED49A1A7112BC4A /* Frameworks */, 106 | ); 107 | sourceTree = ""; 108 | }; 109 | 97C146EF1CF9000F007C117D /* Products */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 97C146EE1CF9000F007C117D /* Runner.app */, 113 | ); 114 | name = Products; 115 | sourceTree = ""; 116 | }; 117 | 97C146F01CF9000F007C117D /* Runner */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 121 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 122 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 123 | 97C147021CF9000F007C117D /* Info.plist */, 124 | 97C146F11CF9000F007C117D /* Supporting Files */, 125 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 126 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 127 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 128 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 129 | ); 130 | path = Runner; 131 | sourceTree = ""; 132 | }; 133 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | ); 137 | name = "Supporting Files"; 138 | sourceTree = ""; 139 | }; 140 | F6BB80108ED49A1A7112BC4A /* Frameworks */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | AAFCC0DB5DD9156BCE4FBB4B /* Pods_Runner.framework */, 144 | ); 145 | name = Frameworks; 146 | sourceTree = ""; 147 | }; 148 | /* End PBXGroup section */ 149 | 150 | /* Begin PBXNativeTarget section */ 151 | 97C146ED1CF9000F007C117D /* Runner */ = { 152 | isa = PBXNativeTarget; 153 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 154 | buildPhases = ( 155 | B28BD5474FCCE4212C19425B /* [CP] Check Pods Manifest.lock */, 156 | 9740EEB61CF901F6004384FC /* Run Script */, 157 | 97C146EA1CF9000F007C117D /* Sources */, 158 | 97C146EB1CF9000F007C117D /* Frameworks */, 159 | 97C146EC1CF9000F007C117D /* Resources */, 160 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 161 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 162 | D5B293E27F4C0C09E9C34420 /* [CP] Embed Pods Frameworks */, 163 | ); 164 | buildRules = ( 165 | ); 166 | dependencies = ( 167 | ); 168 | name = Runner; 169 | productName = Runner; 170 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 171 | productType = "com.apple.product-type.application"; 172 | }; 173 | /* End PBXNativeTarget section */ 174 | 175 | /* Begin PBXProject section */ 176 | 97C146E61CF9000F007C117D /* Project object */ = { 177 | isa = PBXProject; 178 | attributes = { 179 | LastUpgradeCheck = 1020; 180 | ORGANIZATIONNAME = "The Chromium Authors"; 181 | TargetAttributes = { 182 | 97C146ED1CF9000F007C117D = { 183 | CreatedOnToolsVersion = 7.3.1; 184 | LastSwiftMigration = 1100; 185 | }; 186 | }; 187 | }; 188 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 189 | compatibilityVersion = "Xcode 3.2"; 190 | developmentRegion = en; 191 | hasScannedForEncodings = 0; 192 | knownRegions = ( 193 | en, 194 | Base, 195 | ); 196 | mainGroup = 97C146E51CF9000F007C117D; 197 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 198 | projectDirPath = ""; 199 | projectRoot = ""; 200 | targets = ( 201 | 97C146ED1CF9000F007C117D /* Runner */, 202 | ); 203 | }; 204 | /* End PBXProject section */ 205 | 206 | /* Begin PBXResourcesBuildPhase section */ 207 | 97C146EC1CF9000F007C117D /* Resources */ = { 208 | isa = PBXResourcesBuildPhase; 209 | buildActionMask = 2147483647; 210 | files = ( 211 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 212 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 213 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 214 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 215 | ); 216 | runOnlyForDeploymentPostprocessing = 0; 217 | }; 218 | /* End PBXResourcesBuildPhase section */ 219 | 220 | /* Begin PBXShellScriptBuildPhase section */ 221 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 222 | isa = PBXShellScriptBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | ); 226 | inputPaths = ( 227 | ); 228 | name = "Thin Binary"; 229 | outputPaths = ( 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | shellPath = /bin/sh; 233 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 234 | }; 235 | 9740EEB61CF901F6004384FC /* Run Script */ = { 236 | isa = PBXShellScriptBuildPhase; 237 | buildActionMask = 2147483647; 238 | files = ( 239 | ); 240 | inputPaths = ( 241 | ); 242 | name = "Run Script"; 243 | outputPaths = ( 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | shellPath = /bin/sh; 247 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 248 | }; 249 | B28BD5474FCCE4212C19425B /* [CP] Check Pods Manifest.lock */ = { 250 | isa = PBXShellScriptBuildPhase; 251 | buildActionMask = 2147483647; 252 | files = ( 253 | ); 254 | inputFileListPaths = ( 255 | ); 256 | inputPaths = ( 257 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 258 | "${PODS_ROOT}/Manifest.lock", 259 | ); 260 | name = "[CP] Check Pods Manifest.lock"; 261 | outputFileListPaths = ( 262 | ); 263 | outputPaths = ( 264 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 265 | ); 266 | runOnlyForDeploymentPostprocessing = 0; 267 | shellPath = /bin/sh; 268 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 269 | showEnvVarsInLog = 0; 270 | }; 271 | D5B293E27F4C0C09E9C34420 /* [CP] Embed Pods Frameworks */ = { 272 | isa = PBXShellScriptBuildPhase; 273 | buildActionMask = 2147483647; 274 | files = ( 275 | ); 276 | inputPaths = ( 277 | ); 278 | name = "[CP] Embed Pods Frameworks"; 279 | outputPaths = ( 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | shellPath = /bin/sh; 283 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 284 | showEnvVarsInLog = 0; 285 | }; 286 | /* End PBXShellScriptBuildPhase section */ 287 | 288 | /* Begin PBXSourcesBuildPhase section */ 289 | 97C146EA1CF9000F007C117D /* Sources */ = { 290 | isa = PBXSourcesBuildPhase; 291 | buildActionMask = 2147483647; 292 | files = ( 293 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 294 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 295 | ); 296 | runOnlyForDeploymentPostprocessing = 0; 297 | }; 298 | /* End PBXSourcesBuildPhase section */ 299 | 300 | /* Begin PBXVariantGroup section */ 301 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 302 | isa = PBXVariantGroup; 303 | children = ( 304 | 97C146FB1CF9000F007C117D /* Base */, 305 | ); 306 | name = Main.storyboard; 307 | sourceTree = ""; 308 | }; 309 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 310 | isa = PBXVariantGroup; 311 | children = ( 312 | 97C147001CF9000F007C117D /* Base */, 313 | ); 314 | name = LaunchScreen.storyboard; 315 | sourceTree = ""; 316 | }; 317 | /* End PBXVariantGroup section */ 318 | 319 | /* Begin XCBuildConfiguration section */ 320 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 321 | isa = XCBuildConfiguration; 322 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 323 | buildSettings = { 324 | ALWAYS_SEARCH_USER_PATHS = NO; 325 | CLANG_ANALYZER_NONNULL = YES; 326 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 327 | CLANG_CXX_LIBRARY = "libc++"; 328 | CLANG_ENABLE_MODULES = YES; 329 | CLANG_ENABLE_OBJC_ARC = YES; 330 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 331 | CLANG_WARN_BOOL_CONVERSION = YES; 332 | CLANG_WARN_COMMA = YES; 333 | CLANG_WARN_CONSTANT_CONVERSION = YES; 334 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 335 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 336 | CLANG_WARN_EMPTY_BODY = YES; 337 | CLANG_WARN_ENUM_CONVERSION = YES; 338 | CLANG_WARN_INFINITE_RECURSION = YES; 339 | CLANG_WARN_INT_CONVERSION = YES; 340 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 341 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 342 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 343 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 344 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 345 | CLANG_WARN_STRICT_PROTOTYPES = YES; 346 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 347 | CLANG_WARN_UNREACHABLE_CODE = YES; 348 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 349 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 350 | COPY_PHASE_STRIP = NO; 351 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 352 | ENABLE_NS_ASSERTIONS = NO; 353 | ENABLE_STRICT_OBJC_MSGSEND = YES; 354 | GCC_C_LANGUAGE_STANDARD = gnu99; 355 | GCC_NO_COMMON_BLOCKS = YES; 356 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 357 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 358 | GCC_WARN_UNDECLARED_SELECTOR = YES; 359 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 360 | GCC_WARN_UNUSED_FUNCTION = YES; 361 | GCC_WARN_UNUSED_VARIABLE = YES; 362 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 363 | MTL_ENABLE_DEBUG_INFO = NO; 364 | SDKROOT = iphoneos; 365 | SUPPORTED_PLATFORMS = iphoneos; 366 | TARGETED_DEVICE_FAMILY = "1,2"; 367 | VALIDATE_PRODUCT = YES; 368 | }; 369 | name = Profile; 370 | }; 371 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 372 | isa = XCBuildConfiguration; 373 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 374 | buildSettings = { 375 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 376 | CLANG_ENABLE_MODULES = YES; 377 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 378 | ENABLE_BITCODE = NO; 379 | FRAMEWORK_SEARCH_PATHS = ( 380 | "$(inherited)", 381 | "$(PROJECT_DIR)/Flutter", 382 | ); 383 | INFOPLIST_FILE = Runner/Info.plist; 384 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 385 | LIBRARY_SEARCH_PATHS = ( 386 | "$(inherited)", 387 | "$(PROJECT_DIR)/Flutter", 388 | ); 389 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterBlocArchitecture; 390 | PRODUCT_NAME = "$(TARGET_NAME)"; 391 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 392 | SWIFT_VERSION = 5.0; 393 | VERSIONING_SYSTEM = "apple-generic"; 394 | }; 395 | name = Profile; 396 | }; 397 | 97C147031CF9000F007C117D /* Debug */ = { 398 | isa = XCBuildConfiguration; 399 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 400 | buildSettings = { 401 | ALWAYS_SEARCH_USER_PATHS = NO; 402 | CLANG_ANALYZER_NONNULL = YES; 403 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 404 | CLANG_CXX_LIBRARY = "libc++"; 405 | CLANG_ENABLE_MODULES = YES; 406 | CLANG_ENABLE_OBJC_ARC = YES; 407 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 408 | CLANG_WARN_BOOL_CONVERSION = YES; 409 | CLANG_WARN_COMMA = YES; 410 | CLANG_WARN_CONSTANT_CONVERSION = YES; 411 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 412 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 413 | CLANG_WARN_EMPTY_BODY = YES; 414 | CLANG_WARN_ENUM_CONVERSION = YES; 415 | CLANG_WARN_INFINITE_RECURSION = YES; 416 | CLANG_WARN_INT_CONVERSION = YES; 417 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 418 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 419 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 420 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 421 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 422 | CLANG_WARN_STRICT_PROTOTYPES = YES; 423 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 424 | CLANG_WARN_UNREACHABLE_CODE = YES; 425 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 426 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 427 | COPY_PHASE_STRIP = NO; 428 | DEBUG_INFORMATION_FORMAT = dwarf; 429 | ENABLE_STRICT_OBJC_MSGSEND = YES; 430 | ENABLE_TESTABILITY = YES; 431 | GCC_C_LANGUAGE_STANDARD = gnu99; 432 | GCC_DYNAMIC_NO_PIC = NO; 433 | GCC_NO_COMMON_BLOCKS = YES; 434 | GCC_OPTIMIZATION_LEVEL = 0; 435 | GCC_PREPROCESSOR_DEFINITIONS = ( 436 | "DEBUG=1", 437 | "$(inherited)", 438 | ); 439 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 440 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 441 | GCC_WARN_UNDECLARED_SELECTOR = YES; 442 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 443 | GCC_WARN_UNUSED_FUNCTION = YES; 444 | GCC_WARN_UNUSED_VARIABLE = YES; 445 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 446 | MTL_ENABLE_DEBUG_INFO = YES; 447 | ONLY_ACTIVE_ARCH = YES; 448 | SDKROOT = iphoneos; 449 | TARGETED_DEVICE_FAMILY = "1,2"; 450 | }; 451 | name = Debug; 452 | }; 453 | 97C147041CF9000F007C117D /* Release */ = { 454 | isa = XCBuildConfiguration; 455 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 456 | buildSettings = { 457 | ALWAYS_SEARCH_USER_PATHS = NO; 458 | CLANG_ANALYZER_NONNULL = YES; 459 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 460 | CLANG_CXX_LIBRARY = "libc++"; 461 | CLANG_ENABLE_MODULES = YES; 462 | CLANG_ENABLE_OBJC_ARC = YES; 463 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 464 | CLANG_WARN_BOOL_CONVERSION = YES; 465 | CLANG_WARN_COMMA = YES; 466 | CLANG_WARN_CONSTANT_CONVERSION = YES; 467 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 468 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 469 | CLANG_WARN_EMPTY_BODY = YES; 470 | CLANG_WARN_ENUM_CONVERSION = YES; 471 | CLANG_WARN_INFINITE_RECURSION = YES; 472 | CLANG_WARN_INT_CONVERSION = YES; 473 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 474 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 475 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 476 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 477 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 478 | CLANG_WARN_STRICT_PROTOTYPES = YES; 479 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 480 | CLANG_WARN_UNREACHABLE_CODE = YES; 481 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 482 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 483 | COPY_PHASE_STRIP = NO; 484 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 485 | ENABLE_NS_ASSERTIONS = NO; 486 | ENABLE_STRICT_OBJC_MSGSEND = YES; 487 | GCC_C_LANGUAGE_STANDARD = gnu99; 488 | GCC_NO_COMMON_BLOCKS = YES; 489 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 490 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 491 | GCC_WARN_UNDECLARED_SELECTOR = YES; 492 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 493 | GCC_WARN_UNUSED_FUNCTION = YES; 494 | GCC_WARN_UNUSED_VARIABLE = YES; 495 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 496 | MTL_ENABLE_DEBUG_INFO = NO; 497 | SDKROOT = iphoneos; 498 | SUPPORTED_PLATFORMS = iphoneos; 499 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 500 | TARGETED_DEVICE_FAMILY = "1,2"; 501 | VALIDATE_PRODUCT = YES; 502 | }; 503 | name = Release; 504 | }; 505 | 97C147061CF9000F007C117D /* Debug */ = { 506 | isa = XCBuildConfiguration; 507 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 508 | buildSettings = { 509 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 510 | CLANG_ENABLE_MODULES = YES; 511 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 512 | ENABLE_BITCODE = NO; 513 | FRAMEWORK_SEARCH_PATHS = ( 514 | "$(inherited)", 515 | "$(PROJECT_DIR)/Flutter", 516 | ); 517 | INFOPLIST_FILE = Runner/Info.plist; 518 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 519 | LIBRARY_SEARCH_PATHS = ( 520 | "$(inherited)", 521 | "$(PROJECT_DIR)/Flutter", 522 | ); 523 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterBlocArchitecture; 524 | PRODUCT_NAME = "$(TARGET_NAME)"; 525 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 526 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 527 | SWIFT_VERSION = 5.0; 528 | VERSIONING_SYSTEM = "apple-generic"; 529 | }; 530 | name = Debug; 531 | }; 532 | 97C147071CF9000F007C117D /* Release */ = { 533 | isa = XCBuildConfiguration; 534 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 535 | buildSettings = { 536 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 537 | CLANG_ENABLE_MODULES = YES; 538 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 539 | ENABLE_BITCODE = NO; 540 | FRAMEWORK_SEARCH_PATHS = ( 541 | "$(inherited)", 542 | "$(PROJECT_DIR)/Flutter", 543 | ); 544 | INFOPLIST_FILE = Runner/Info.plist; 545 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 546 | LIBRARY_SEARCH_PATHS = ( 547 | "$(inherited)", 548 | "$(PROJECT_DIR)/Flutter", 549 | ); 550 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterBlocArchitecture; 551 | PRODUCT_NAME = "$(TARGET_NAME)"; 552 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 553 | SWIFT_VERSION = 5.0; 554 | VERSIONING_SYSTEM = "apple-generic"; 555 | }; 556 | name = Release; 557 | }; 558 | /* End XCBuildConfiguration section */ 559 | 560 | /* Begin XCConfigurationList section */ 561 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 562 | isa = XCConfigurationList; 563 | buildConfigurations = ( 564 | 97C147031CF9000F007C117D /* Debug */, 565 | 97C147041CF9000F007C117D /* Release */, 566 | 249021D3217E4FDB00AE95B9 /* Profile */, 567 | ); 568 | defaultConfigurationIsVisible = 0; 569 | defaultConfigurationName = Release; 570 | }; 571 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 572 | isa = XCConfigurationList; 573 | buildConfigurations = ( 574 | 97C147061CF9000F007C117D /* Debug */, 575 | 97C147071CF9000F007C117D /* Release */, 576 | 249021D4217E4FDB00AE95B9 /* Profile */, 577 | ); 578 | defaultConfigurationIsVisible = 0; 579 | defaultConfigurationName = Release; 580 | }; 581 | /* End XCConfigurationList section */ 582 | }; 583 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 584 | } 585 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flutter-devs/Flutter-BlocArchitecture/49701125dc9c86cb19e8d0bb3d331447833636dc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_bloc_architecture 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:flutter_bloc_architecture/src/bloc_delegate/simple_bloc_delegate.dart'; 4 | import 'package:flutter_bloc_architecture/src/di/app_config.dart'; 5 | import 'package:flutter_bloc_architecture/src/my_app.dart'; 6 | 7 | void main() { 8 | Bloc.observer = SimpleBlocDelegate(); 9 | setupAppConfig(); 10 | runApp(MyApp()); 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/bloc/bottom_nav/bottom_nav_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | 3 | class BottomNavCubit extends Cubit { 4 | BottomNavCubit() : super(0); 5 | 6 | void selectTab(int index) { 7 | emit(index); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/src/bloc/bottom_nav/checkbox_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | 3 | class CheckboxCubit extends Cubit { 4 | CheckboxCubit() : super(false); 5 | void selectCheckBox(bool value) { 6 | emit(value); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lib/src/bloc/login/login.dart: -------------------------------------------------------------------------------- 1 | export 'login_bloc.dart'; 2 | export 'login_event.dart'; 3 | export 'login_state.dart'; 4 | -------------------------------------------------------------------------------- /lib/src/bloc/login/login_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc_architecture/src/di/app_config.dart'; 4 | import 'package:flutter_bloc_architecture/src/models/network_data_models/login/response/login_response.dart'; 5 | import 'package:flutter_bloc_architecture/src/network/repository/api_repository.dart'; 6 | import 'package:flutter_bloc_architecture/src/utils/helper.dart'; 7 | import 'package:flutter_bloc_architecture/src/utils/validator.dart'; 8 | 9 | import 'login.dart'; 10 | 11 | class LoginBloc extends Bloc { 12 | final Validator validator = Validator(); 13 | 14 | LoginBloc() : super(UserUnavailable()); 15 | 16 | @override 17 | LoginState get initialState => UserUnavailable(); 18 | 19 | @override 20 | Stream mapEventToState(LoginEvent event) async* { 21 | if (event is SignInUser) { 22 | yield LoginLoading(); 23 | try { 24 | LoginResponse loginResponse = await appConfig().login( 25 | email: event.email, 26 | password: event.password, 27 | ); 28 | if (loginResponse != null) { 29 | Helper.printLogValue("UserLoggedIn"); 30 | yield UserLoggedIn(); 31 | } else { 32 | Helper.printLogValue("UserLoggedOut"); 33 | yield UserLoggedOut(); 34 | } 35 | } catch (error) { 36 | Helper.printLogValue("LoginFailure"); 37 | yield LoginFailure(error: error.toString()); 38 | } 39 | } 40 | if (event is PasswordChanged) { 41 | yield state.copyWith( 42 | isPasswordValid: _isPasswordValid(event.password), 43 | ); 44 | } 45 | 46 | if (event is EmailChanged) { 47 | yield state.copyWith( 48 | isEmailValid: _isEmailValid(event.email), 49 | ); 50 | } 51 | } 52 | bool _isEmailValid(String email) { 53 | return validator.validateEmail(email); 54 | } 55 | 56 | bool _isPasswordValid(String password) { 57 | return validator.validatePassword(password); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/src/bloc/login/login_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | 3 | abstract class LoginEvent { 4 | LoginEvent(); 5 | } 6 | 7 | class EmailChanged extends LoginEvent { 8 | final String email; 9 | 10 | EmailChanged({@required this.email}); 11 | } 12 | 13 | class PasswordChanged extends LoginEvent { 14 | final String password; 15 | 16 | PasswordChanged({@required this.password}); 17 | } 18 | 19 | class SignInUser extends LoginEvent { 20 | final String email; 21 | final String password; 22 | 23 | SignInUser({ 24 | this.email, 25 | @required this.password, 26 | }); 27 | } 28 | 29 | class SignOutUser extends LoginEvent {} 30 | 31 | class AppStarted extends LoginEvent {} 32 | 33 | class AppRestarted extends LoginEvent {} 34 | 35 | class AppClose extends LoginEvent {} 36 | 37 | class CheckScreenStatus extends LoginEvent {} 38 | 39 | class HitRefreshApi extends LoginEvent {} 40 | -------------------------------------------------------------------------------- /lib/src/bloc/login/login_state.dart: -------------------------------------------------------------------------------- 1 | class LoginState { 2 | final bool isEmailValid; 3 | final bool isPasswordValid; 4 | 5 | const LoginState({ 6 | this.isEmailValid = true, 7 | this.isPasswordValid = true, 8 | }); 9 | 10 | factory LoginState.initial() { 11 | return LoginState( 12 | isEmailValid: true, 13 | isPasswordValid: true, 14 | ); 15 | } 16 | 17 | LoginState copyWith({ 18 | bool isEmailValid, 19 | bool isPasswordValid, 20 | }) { 21 | return LoginState( 22 | isEmailValid: isEmailValid ?? this.isEmailValid, 23 | isPasswordValid: isPasswordValid ?? this.isPasswordValid, 24 | ); 25 | } 26 | 27 | @override 28 | String toString() { 29 | return '''LoginState { 30 | isEmailValid: $isEmailValid, 31 | isPasswordValid: $isPasswordValid, 32 | }'''; 33 | } 34 | } 35 | 36 | class LoginLoading extends LoginState {} 37 | 38 | class LoginFailure extends LoginState { 39 | var error; 40 | 41 | LoginFailure({this.error}); 42 | } 43 | 44 | class UserLoggedIn extends LoginState {} 45 | 46 | class UserLoggedOut extends LoginState {} 47 | 48 | class UserUnavailable extends LoginState {} 49 | -------------------------------------------------------------------------------- /lib/src/bloc_delegate/simple_bloc_delegate.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | class SimpleBlocDelegate extends BlocObserver { 4 | final bool verbose = false; 5 | 6 | @override 7 | void onEvent(Bloc bloc, Object event) { 8 | super.onEvent(bloc, event); 9 | print(event.toString()); 10 | } 11 | 12 | @override 13 | void onTransition(Bloc bloc, Transition transition) { 14 | super.onTransition(bloc, transition); 15 | print(''' 16 | ${bloc.runtimeType} - Transition { 17 | event: ${transition.event.runtimeType} 18 | currentState: ${transition.currentState.runtimeType} 19 | nextState: ${transition.nextState.runtimeType} 20 | } 21 | '''); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/src/constants/font_constants.dart: -------------------------------------------------------------------------------- 1 | class FontConstant { 2 | static const String open_sans_semi_bold = 'OpenSans-Semibold'; 3 | static const String open_sans_regular = 'OpenSans-Regular'; 4 | static const String open_sans_light = 'OpenSans-Light'; 5 | static const String open_sans_bold = 'OpenSans-Bold'; 6 | static const String open_sans_muli_bold = 'Muli-Bold'; 7 | static const String arial_rounded_mt_bold = 'ArialRoundedMTBold'; 8 | 9 | static const int kBold = 1; 10 | static const int kSemiBold = 2; 11 | static const int kRegular = 3; 12 | static const int kLight = 4; 13 | static const int kArialRoundedMTBold = 5; 14 | } 15 | -------------------------------------------------------------------------------- /lib/src/constants/page_route_constants.dart: -------------------------------------------------------------------------------- 1 | class PageRouteConstants { 2 | static const String home_screen = '/HomeScreeen'; 3 | static const String splash_screen = '/SplashScreen'; 4 | static const String login_screen = '/LoginScreen'; 5 | } 6 | -------------------------------------------------------------------------------- /lib/src/constants/regex_constant.dart: -------------------------------------------------------------------------------- 1 | class RegexConstant { 2 | static const valid_email = 3 | r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'; 4 | } 5 | -------------------------------------------------------------------------------- /lib/src/constants/string_constant.dart: -------------------------------------------------------------------------------- 1 | class StringConstant { 2 | /*Validator class*/ 3 | 4 | static const String empty_email = 'Email is Required'; 5 | static const String invalid_email = 'Invalid Email'; 6 | static const String empty_user_name = 'User-Name is Required'; 7 | static const String invalid_user_name = 'Invalid User-Name'; 8 | static const String password_hint = '**************'; 9 | static const String invalid_password = 'Invalid Password'; 10 | static const String error_message = 'Error Message'; 11 | static const String empty_first_name = 'First Name is Required'; 12 | static const String sign_in = 'Sign in'; 13 | static const String invalid_user_credentials = "Invalid user credentials"; 14 | static const app_name = "AppName"; 15 | static const String email = 'Email'; 16 | static const String welcome_to_home_screen = 'Welocome to Home Screen'; 17 | static const String password = 'Password'; 18 | static const String type_email = 'Type email'; 19 | static const String no = 'No'; 20 | static const String yes = 'Yes'; 21 | static const String ok = 'Ok'; 22 | static const String home = 'Home'; 23 | static const String help = 'Self Help'; 24 | static const String profile = 'Profile'; 25 | static const String please_enter_email_address = "Please enter email address"; 26 | 27 | static const String please_check_internet_connectivity = 28 | "Please check internet connectivity."; 29 | static const String internet_alert = "Internet Alert"; 30 | } 31 | -------------------------------------------------------------------------------- /lib/src/constants/url_constant.dart: -------------------------------------------------------------------------------- 1 | class UrlConstant { 2 | static const String BASE_URL = 3 | "http://phplaravel-358955-1115224.cloudwaysapps.com/api"; 4 | 5 | //Login 6 | static const String LOGIN = "/login"; 7 | } 8 | -------------------------------------------------------------------------------- /lib/src/di/app_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_bloc_architecture/src/network/repository/api_repository.dart'; 2 | import 'package:flutter_bloc_architecture/src/sharedpref/preference_connector.dart'; 3 | import 'package:flutter_bloc_architecture/src/utils/navigation_service.dart'; 4 | import 'package:get_it/get_it.dart'; 5 | 6 | GetIt appConfig = GetIt.I; 7 | 8 | void setupAppConfig() { 9 | appConfig.registerFactory(() => ApiRepository()); 10 | appConfig.registerFactory(() => NavigationService()); 11 | appConfig.registerFactory(() => PreferenceConnector()); 12 | } 13 | -------------------------------------------------------------------------------- /lib/src/localization/app_localizations.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/foundation.dart' show SynchronousFuture; 4 | import 'package:flutter/material.dart'; 5 | 6 | class AppLocalizations { 7 | AppLocalizations(this.locale); 8 | 9 | final Locale locale; 10 | 11 | static AppLocalizations of(BuildContext context) { 12 | return Localizations.of(context, AppLocalizations); 13 | } 14 | 15 | static Map> _localizedValues = { 16 | "en": { 17 | "app_name": "SampleApp", 18 | } 19 | }; 20 | 21 | String get appName => _localizedValues[locale.languageCode]['app_name']; 22 | } 23 | 24 | class AppLocalizationsDelegate extends LocalizationsDelegate { 25 | const AppLocalizationsDelegate(); 26 | 27 | @override 28 | bool isSupported(Locale locale) => ['en'].contains(locale.languageCode); 29 | 30 | @override 31 | Future load(Locale locale) { 32 | return SynchronousFuture(AppLocalizations(locale)); 33 | } 34 | 35 | @override 36 | bool shouldReload(AppLocalizationsDelegate old) => false; 37 | } 38 | -------------------------------------------------------------------------------- /lib/src/models/local_data_models/login_user_details.dart: -------------------------------------------------------------------------------- 1 | class LoginUserDetails { 2 | String userEmail; 3 | String password; 4 | } 5 | -------------------------------------------------------------------------------- /lib/src/models/network_data_models/login/request/login_request.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'login_request.g.dart'; 4 | 5 | @JsonSerializable() 6 | class LoginRequest { 7 | String email; 8 | String password; 9 | 10 | LoginRequest({ 11 | this.email, 12 | this.password, 13 | }); 14 | 15 | factory LoginRequest.fromJson(Map json) => 16 | _$LoginRequestFromJson(json); 17 | 18 | Map toJson() => _$LoginRequestToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/models/network_data_models/login/request/login_request.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'login_request.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | LoginRequest _$LoginRequestFromJson(Map json) { 10 | return LoginRequest( 11 | email: json['email'] as String, 12 | password: json['password'] as String, 13 | ); 14 | } 15 | 16 | Map _$LoginRequestToJson(LoginRequest instance) => 17 | { 18 | 'email': instance.email, 19 | 'password': instance.password, 20 | }; 21 | -------------------------------------------------------------------------------- /lib/src/models/network_data_models/login/response/data.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'data.g.dart'; 4 | 5 | @JsonSerializable() 6 | class Data { 7 | String name; 8 | int id; 9 | String email; 10 | String gender; 11 | String region; 12 | String contact1; 13 | String contact2; 14 | String contact3; 15 | String contact4; 16 | String contact5; 17 | DateTime dob; 18 | String type; 19 | 20 | Data({ 21 | this.name, 22 | this.id, 23 | this.email, 24 | this.gender, 25 | this.region, 26 | this.contact1, 27 | this.contact2, 28 | this.contact3, 29 | this.contact4, 30 | this.contact5, 31 | this.dob, 32 | this.type, 33 | }); 34 | 35 | factory Data.fromJson(Map json) => _$DataFromJson(json); 36 | 37 | Map toJson() => _$DataToJson(this); 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/models/network_data_models/login/response/data.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'data.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Data _$DataFromJson(Map json) { 10 | return Data( 11 | name: json['name'] as String, 12 | id: json['id'] as int, 13 | email: json['email'] as String, 14 | gender: json['gender'] as String, 15 | region: json['region'] as String, 16 | contact1: json['contact1'] as String, 17 | contact2: json['contact2'] as String, 18 | contact3: json['contact3'] as String, 19 | contact4: json['contact4'] as String, 20 | contact5: json['contact5'] as String, 21 | dob: json['dob'] == null ? null : DateTime.parse(json['dob'] as String), 22 | type: json['type'] as String, 23 | ); 24 | } 25 | 26 | Map _$DataToJson(Data instance) => { 27 | 'name': instance.name, 28 | 'id': instance.id, 29 | 'email': instance.email, 30 | 'gender': instance.gender, 31 | 'region': instance.region, 32 | 'contact1': instance.contact1, 33 | 'contact2': instance.contact2, 34 | 'contact3': instance.contact3, 35 | 'contact4': instance.contact4, 36 | 'contact5': instance.contact5, 37 | 'dob': instance.dob?.toIso8601String(), 38 | 'type': instance.type, 39 | }; 40 | -------------------------------------------------------------------------------- /lib/src/models/network_data_models/login/response/login_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_bloc_architecture/src/models/network_data_models/login/response/result.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'login_response.g.dart'; 5 | 6 | @JsonSerializable() 7 | class LoginResponse { 8 | String status; 9 | int code; 10 | String message; 11 | Result result; 12 | 13 | LoginResponse({ 14 | this.status, 15 | this.code, 16 | this.message, 17 | this.result, 18 | }); 19 | 20 | factory LoginResponse.fromJson(Map json) => 21 | _$LoginResponseFromJson(json); 22 | 23 | Map toJson() => _$LoginResponseToJson(this); 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/models/network_data_models/login/response/login_response.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'login_response.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | LoginResponse _$LoginResponseFromJson(Map json) { 10 | return LoginResponse( 11 | status: json['status'] as String, 12 | code: json['code'] as int, 13 | message: json['message'] as String, 14 | result: json['result'] == null 15 | ? null 16 | : Result.fromJson(json['result'] as Map), 17 | ); 18 | } 19 | 20 | Map _$LoginResponseToJson(LoginResponse instance) => 21 | { 22 | 'status': instance.status, 23 | 'code': instance.code, 24 | 'message': instance.message, 25 | 'result': instance.result, 26 | }; 27 | -------------------------------------------------------------------------------- /lib/src/models/network_data_models/login/response/result.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_bloc_architecture/src/models/network_data_models/login/response/data.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'result.g.dart'; 5 | 6 | @JsonSerializable() 7 | class Result { 8 | String accessToken; 9 | String tokenType; 10 | int expiresIn; 11 | Data data; 12 | 13 | Result({ 14 | this.accessToken, 15 | this.tokenType, 16 | this.expiresIn, 17 | this.data, 18 | }); 19 | 20 | factory Result.fromJson(Map json) => _$ResultFromJson(json); 21 | 22 | Map toJson() => _$ResultToJson(this); 23 | } 24 | -------------------------------------------------------------------------------- /lib/src/models/network_data_models/login/response/result.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'result.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Result _$ResultFromJson(Map json) { 10 | return Result( 11 | accessToken: json['accessToken'] as String, 12 | tokenType: json['tokenType'] as String, 13 | expiresIn: json['expiresIn'] as int, 14 | data: json['data'] == null 15 | ? null 16 | : Data.fromJson(json['data'] as Map), 17 | ); 18 | } 19 | 20 | Map _$ResultToJson(Result instance) => { 21 | 'accessToken': instance.accessToken, 22 | 'tokenType': instance.tokenType, 23 | 'expiresIn': instance.expiresIn, 24 | 'data': instance.data, 25 | }; 26 | -------------------------------------------------------------------------------- /lib/src/my_app.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:flutter_bloc_architecture/src/bloc/bottom_nav/checkbox_cubit.dart'; 5 | import 'package:flutter_bloc_architecture/src/constants/string_constant.dart'; 6 | import 'package:flutter_bloc_architecture/src/network/repository/api_repository.dart'; 7 | import 'package:flutter_bloc_architecture/src/resources/app_theme.dart'; 8 | import 'package:flutter_bloc_architecture/src/utils/navigation_service.dart'; 9 | import 'package:flutter_bloc_architecture/src/utils/screen_router.dart'; 10 | 11 | import 'bloc/bottom_nav/bottom_nav_cubit.dart'; 12 | import 'bloc/login/login_bloc.dart'; 13 | import 'di/app_config.dart'; 14 | import 'ui/screens/splash/splash_screen.dart'; 15 | 16 | class MyApp extends StatelessWidget { 17 | @override 18 | Widget build(BuildContext context) { 19 | return MultiBlocProvider( 20 | providers: [ 21 | BlocProvider( 22 | create: (context) { 23 | return LoginBloc( 24 | ); 25 | }, 26 | ), 27 | BlocProvider( 28 | create: (context) => BottomNavCubit(), 29 | ), 30 | BlocProvider( 31 | create: (context) => CheckboxCubit(), 32 | ), 33 | ], 34 | child: MaterialApp( 35 | title: StringConstant.app_name, 36 | theme: AppTheme.appTheme(), 37 | navigatorKey: appConfig().navigatorKey, 38 | onGenerateRoute: ScreenRouter.generateRoute, 39 | debugShowCheckedModeBanner: false, 40 | home: SplashScreen())); 41 | } 42 | } -------------------------------------------------------------------------------- /lib/src/network/api_client/api_rest_client.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart' hide Headers; 2 | import 'package:flutter_bloc_architecture/src/constants/url_constant.dart'; 3 | import 'package:flutter_bloc_architecture/src/models/network_data_models/login/request/login_request.dart'; 4 | import 'package:flutter_bloc_architecture/src/models/network_data_models/login/response/login_response.dart'; 5 | import 'package:retrofit/retrofit.dart'; 6 | 7 | part 'api_rest_client.g.dart'; 8 | 9 | @RestApi(baseUrl: "") 10 | abstract class ApiRestClient { 11 | factory ApiRestClient(Dio dio) = _ApiRestClient; 12 | 13 | /*Login Api*/ 14 | @POST(UrlConstant.BASE_URL + UrlConstant.LOGIN) 15 | @FormUrlEncoded() 16 | Future login(@Body() LoginRequest loginRequest); 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/network/api_client/api_rest_client.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'api_rest_client.dart'; 4 | 5 | // ************************************************************************** 6 | // RetrofitGenerator 7 | // ************************************************************************** 8 | 9 | class _ApiRestClient implements ApiRestClient { 10 | _ApiRestClient(this._dio, {this.baseUrl}) { 11 | ArgumentError.checkNotNull(_dio, '_dio'); 12 | } 13 | 14 | final Dio _dio; 15 | 16 | String baseUrl; 17 | 18 | @override 19 | Future login(loginRequest) async { 20 | ArgumentError.checkNotNull(loginRequest, 'loginRequest'); 21 | const _extra = {}; 22 | final queryParameters = {}; 23 | final _data = {}; 24 | _data.addAll(loginRequest?.toJson() ?? {}); 25 | final _result = await _dio.request>( 26 | 'http://phplaravel-358955-1115224.cloudwaysapps.com/api/login', 27 | queryParameters: queryParameters, 28 | options: RequestOptions( 29 | method: 'POST', 30 | headers: {}, 31 | extra: _extra, 32 | contentType: 'application/x-www-form-urlencoded', 33 | baseUrl: baseUrl), 34 | data: _data); 35 | final value = LoginResponse.fromJson(_result.data); 36 | return value; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/network/repository/api_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc_architecture/src/models/network_data_models/login/request/login_request.dart'; 4 | import 'package:flutter_bloc_architecture/src/models/network_data_models/login/response/login_response.dart'; 5 | import 'package:flutter_bloc_architecture/src/network/api_client/api_rest_client.dart'; 6 | 7 | class ApiRepository { 8 | ApiRestClient apiRestClient; 9 | 10 | ApiRepository() { 11 | Dio _dio = Dio(); 12 | _dio.options.headers["Content-Type"] = "application/json"; 13 | apiRestClient = ApiRestClient(_dio); 14 | } 15 | 16 | Future login({ 17 | @required String email, 18 | @required String password, 19 | }) async { 20 | LoginRequest loginRequest = LoginRequest( 21 | email: email, 22 | password: password, 23 | ); 24 | return await apiRestClient.login(loginRequest); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/resources/app_colors.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter_bloc_architecture/src/resources/hex_color.dart'; 4 | 5 | class AppColors { 6 | //Todo 7 | static Color get primaryColor => HexColor("#6998e4"); 8 | 9 | static Color get black => HexColor("#000000"); 10 | 11 | static Color get darkModeBlack => HexColor("#424242"); 12 | 13 | static Color get white => HexColor("#FFFFFF"); 14 | 15 | static Color get cardWhite => HexColor("#F5F5F5"); 16 | 17 | static Color get dividerColor => HexColor("#BDBDBD"); 18 | 19 | static Color get yellow => HexColor("#FFEB3B"); 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/resources/app_localization.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/services.dart'; 6 | 7 | class AppLocalizations { 8 | // localization variables 9 | final Locale locale; 10 | Map localizedStrings; 11 | 12 | // Static member to have a simple access to the delegate from the MaterialApp 13 | static const LocalizationsDelegate delegate = 14 | _AppLocalizationsDelegate(); 15 | 16 | // constructor 17 | AppLocalizations(this.locale); 18 | 19 | // Helper method to keep the code in the widgets concise 20 | // Localizations are accessed using an InheritedWidget "of" syntax 21 | static AppLocalizations of(BuildContext context) { 22 | return Localizations.of(context, AppLocalizations); 23 | } 24 | 25 | // This is a helper method that will load local specific strings from file 26 | // present in lang folder 27 | Future load() async { 28 | // Load the language JSON file from the "lang" folder 29 | String jsonString = 30 | await rootBundle.loadString('assets/lang/${locale.languageCode}.json'); 31 | Map jsonMap = json.decode(jsonString); 32 | 33 | localizedStrings = jsonMap.map((key, value) { 34 | return MapEntry( 35 | key, value.toString().replaceAll(r"\'", "'").replaceAll(r"\t", " ")); 36 | }); 37 | 38 | return true; 39 | } 40 | 41 | // This method will be called from every widget which needs a localized text 42 | String translate(String key) { 43 | return localizedStrings[key]; 44 | } 45 | } 46 | 47 | // LocalizationsDelegate is a factory for a set of localized resources 48 | // In this case, the localized strings will be gotten in an AppLocalizations object 49 | class _AppLocalizationsDelegate 50 | extends LocalizationsDelegate { 51 | // ignore: non_constant_identifier_names 52 | final String TAG = "AppLocalizations"; 53 | 54 | // This delegate instance will never change (it doesn't even have fields!) 55 | // It can provide a constant constructor. 56 | const _AppLocalizationsDelegate(); 57 | 58 | @override 59 | bool isSupported(Locale locale) { 60 | // Include all of your supported language codes here 61 | return ['en', 'es', 'da'].contains(locale.languageCode); 62 | } 63 | 64 | @override 65 | Future load(Locale locale) async { 66 | // AppLocalizations class is where the JSON loading actually runs 67 | AppLocalizations localizations = new AppLocalizations(locale); 68 | await localizations.load(); 69 | return localizations; 70 | } 71 | 72 | @override 73 | bool shouldReload(_AppLocalizationsDelegate old) => false; 74 | } 75 | -------------------------------------------------------------------------------- /lib/src/resources/app_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc_architecture/src/resources/app_colors.dart'; 3 | 4 | class AppTheme { 5 | static ThemeData appTheme() { 6 | return ThemeData( 7 | primaryColor: Colors.red, 8 | backgroundColor: Colors.red, 9 | textTheme: TextTheme( 10 | title: TextStyle(color: AppColors.black), 11 | caption: TextStyle(color: AppColors.white)), 12 | brightness: Brightness.light, 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/resources/dimens.dart: -------------------------------------------------------------------------------- 1 | class Dimens { 2 | Dimens._(); 3 | 4 | //for all screens 5 | static const double horizontal_padding = 12.0; 6 | static const double vertical_padding = 12.0; 7 | static const double px1 = 1; 8 | static const double px150 = 150; 9 | static const double px16 = 16; 10 | static const double px12 = 12; 11 | static const double px22 = 22; 12 | static const double px13 = 13; 13 | static const double px14 = 14; 14 | static const double px21 = 21; 15 | static const double px18 = 18; 16 | static const double px17 = 17; 17 | static const double px25 = 25; 18 | static const double px26 = 26; 19 | static const double px29 = 29; 20 | static const double px30 = 30; 21 | static const double px20 = 20; 22 | static const double px56 = 56; 23 | static const double px8 = 8; 24 | static const double px10 = 10; 25 | static const double px28 = 28; 26 | static const double px4 = 4; 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/resources/font_family.dart: -------------------------------------------------------------------------------- 1 | class FontFamily { 2 | FontFamily._(); 3 | 4 | static String productSans = "ProductSans"; 5 | static String roboto = "Roboto"; 6 | } 7 | -------------------------------------------------------------------------------- /lib/src/resources/hex_color.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | class HexColor extends Color { 4 | static int _getColorFromHex(String hexColor) { 5 | hexColor = hexColor.toUpperCase().replaceAll("#", ""); 6 | if (hexColor.length == 6) { 7 | hexColor = "FF" + hexColor; 8 | } 9 | return int.parse(hexColor, radix: 16); 10 | } 11 | 12 | HexColor(final String hexColor) : super(_getColorFromHex(hexColor)); 13 | } 14 | -------------------------------------------------------------------------------- /lib/src/resources/text_styles.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc_architecture/src/constants/font_constants.dart'; 3 | import 'package:flutter_bloc_architecture/src/resources/app_colors.dart'; 4 | import 'package:flutter_bloc_architecture/src/resources/dimens.dart'; 5 | 6 | class AppTextStyles { 7 | static TextStyle appBarTextStyleTheme(bool isDark) => 8 | TextStyle(color: isDark ? AppColors.white : AppColors.black); 9 | 10 | /*-----------------------Text Style BOLD -----------------------*/ 11 | static TextStyle getExtraSmallText(double width, Color color, int fontType) { 12 | return TextStyle( 13 | fontFamily: (fontType == FontConstant.kBold 14 | ? FontConstant.open_sans_bold 15 | : (fontType == FontConstant.kSemiBold 16 | ? FontConstant.open_sans_semi_bold 17 | : (fontType == FontConstant.kRegular 18 | ? FontConstant.open_sans_regular 19 | : FontConstant.open_sans_light))), 20 | color: color, 21 | fontSize: (width * 0.025 < Dimens.px14 ? width * 0.025 : Dimens.px13), 22 | ); 23 | } 24 | 25 | static TextStyle getSmallText(double width, Color color, int fontType) { 26 | return TextStyle( 27 | fontFamily: (fontType == FontConstant.kBold 28 | ? FontConstant.open_sans_bold 29 | : (fontType == FontConstant.kSemiBold 30 | ? FontConstant.open_sans_bold 31 | : (fontType == FontConstant.kRegular 32 | ? FontConstant.open_sans_regular 33 | : FontConstant.open_sans_light))), 34 | color: color, 35 | fontSize: (width * 0.038 < Dimens.px18 ? width * 0.038 : Dimens.px17), 36 | ); 37 | } 38 | 39 | static TextStyle getMediumText(double width, Color color, int fontType) { 40 | return TextStyle( 41 | fontFamily: (fontType == FontConstant.kBold 42 | ? FontConstant.open_sans_bold 43 | : (fontType == FontConstant.kSemiBold 44 | ? FontConstant.open_sans_bold 45 | : (fontType == FontConstant.kRegular 46 | ? FontConstant.open_sans_regular 47 | : FontConstant.open_sans_light))), 48 | color: color, 49 | fontSize: (width * 0.044 < Dimens.px22 ? width * 0.044 : Dimens.px21), 50 | ); 51 | } 52 | 53 | static TextStyle getLargeText(double width, Color color, int fontType) { 54 | return TextStyle( 55 | fontFamily: (fontType == FontConstant.kBold 56 | ? FontConstant.open_sans_bold 57 | : (fontType == FontConstant.kSemiBold 58 | ? FontConstant.open_sans_bold 59 | : (fontType == FontConstant.kRegular 60 | ? FontConstant.open_sans_regular 61 | : FontConstant.open_sans_light))), 62 | color: color, 63 | fontSize: (width * 0.053 < Dimens.px26 ? width * 0.053 : Dimens.px25), 64 | ); 65 | } 66 | 67 | static TextStyle getExtraLargeText(double width, Color color, int fontType) { 68 | return TextStyle( 69 | fontFamily: (fontType == FontConstant.kBold 70 | ? FontConstant.open_sans_bold 71 | : (fontType == FontConstant.kSemiBold 72 | ? FontConstant.open_sans_bold 73 | : (fontType == FontConstant.kRegular 74 | ? FontConstant.open_sans_regular 75 | : FontConstant.open_sans_light))), 76 | color: color, 77 | fontSize: (width * 0.062 < Dimens.px30 ? width * 0.062 : Dimens.px29), 78 | ); 79 | } 80 | 81 | static TextStyle getSmallTextUnderline( 82 | double width, Color color, int fontType, bool underline) { 83 | return TextStyle( 84 | decoration: underline ? TextDecoration.underline : TextDecoration.none, 85 | fontFamily: (fontType == FontConstant.kBold 86 | ? FontConstant.open_sans_bold 87 | : (fontType == FontConstant.kSemiBold 88 | ? FontConstant.open_sans_bold 89 | : (fontType == FontConstant.kRegular 90 | ? FontConstant.open_sans_regular 91 | : FontConstant.open_sans_light))), 92 | color: color, 93 | fontSize: (width * 0.032 < Dimens.px18 ? width * 0.032 : Dimens.px17), 94 | ); 95 | } 96 | 97 | static TextStyle getMedium1Text(double width, Color color, int fontType) { 98 | return TextStyle( 99 | fontFamily: (fontType == FontConstant.kBold 100 | ? FontConstant.open_sans_bold 101 | : (fontType == FontConstant.kSemiBold 102 | ? FontConstant.open_sans_bold 103 | : (fontType == FontConstant.kRegular 104 | ? FontConstant.open_sans_regular 105 | : FontConstant.open_sans_light))), 106 | color: color, 107 | fontSize: (width * 0.053 < Dimens.px14 ? width * 0.053 : Dimens.px13), 108 | ); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /lib/src/sharedpref/constants/preferences.dart: -------------------------------------------------------------------------------- 1 | class Preferences { 2 | Preferences._(); 3 | 4 | static const String is_logged_in = "isLoggedIn"; 5 | } 6 | -------------------------------------------------------------------------------- /lib/src/sharedpref/preference_connector.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | 3 | class PreferenceConnector { 4 | _getSharedPreference() async { 5 | return await SharedPreferences.getInstance(); 6 | } 7 | 8 | Future getString(String key) async { 9 | SharedPreferences prefs = await _getSharedPreference(); 10 | return prefs.getString(key) ?? ''; 11 | } 12 | 13 | Future getInt(String key) async { 14 | SharedPreferences prefs = await _getSharedPreference(); 15 | return prefs.getInt(key) ?? -1; 16 | } 17 | 18 | Future getDouble(String key) async { 19 | SharedPreferences prefs = await _getSharedPreference(); 20 | return prefs.getDouble(key) ?? -1; 21 | } 22 | 23 | Future getBool(String key) async { 24 | SharedPreferences prefs = await _getSharedPreference(); 25 | return prefs.getBool(key) ?? false; 26 | } 27 | 28 | void setString(String key, String value) async { 29 | SharedPreferences prefs = await _getSharedPreference(); 30 | prefs.setString(key, value); 31 | } 32 | 33 | void setInt(String key, int value) async { 34 | SharedPreferences prefs = await _getSharedPreference(); 35 | prefs.setInt(key, value); 36 | } 37 | 38 | void setDouble(String key, double value) async { 39 | SharedPreferences prefs = await _getSharedPreference(); 40 | prefs.setDouble(key, value); 41 | } 42 | 43 | void setBool(String key, bool value) async { 44 | SharedPreferences prefs = await _getSharedPreference(); 45 | prefs.setBool(key, value); 46 | } 47 | 48 | void removePreference(String key) async { 49 | SharedPreferences prefs = await _getSharedPreference(); 50 | prefs.remove(key); 51 | } 52 | 53 | void clear() async { 54 | SharedPreferences prefs = await _getSharedPreference(); 55 | prefs.clear(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/src/ui/common/ui_helpers.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// Contains useful functions to reduce boilerplate code 4 | class UIHelper { 5 | // Vertical spacing constants. Adjust to your liking. 6 | static const double _NavigationBarSpace = 20.0; 7 | static const double _VerticalSpaceSmall = 10.0; 8 | static const double _VerticalSpaceMedium = 20.0; 9 | static const double _VerticalSpaceLarge1 = 40.0; 10 | static const double _VerticalSpaceLarge2 = 60.0; 11 | 12 | // Vertical spacing constants. Adjust to your liking. 13 | static const double _HorizontalSpaceSmall = 10.0; 14 | static const double _HorizontalSpaceMedium = 20.0; 15 | static const double HorizontalSpaceLarge = 60.0; 16 | 17 | /// Returns a vertical space with height set to [_NavigationBarSpace] 18 | static Widget navigationBarSpace() { 19 | return verticalSpace(_NavigationBarSpace); 20 | } 21 | 22 | /// Returns a vertical space with height set to [_VerticalSpaceSmall] 23 | static Widget verticalSpaceSmall() { 24 | return verticalSpace(_VerticalSpaceSmall); 25 | } 26 | 27 | /// Returns a vertical space with height set to [_VerticalSpaceMedium] 28 | static Widget verticalSpaceMedium() { 29 | return verticalSpace(_VerticalSpaceMedium); 30 | } 31 | 32 | /// Returns a vertical space with height set to [_VerticalSpaceLarge] 33 | static Widget verticalSpaceLarge() { 34 | return verticalSpace(_VerticalSpaceLarge1); 35 | } 36 | 37 | /// Returns a vertical space equal to the [height] supplied 38 | static Widget verticalSpace(double height) { 39 | return Container(height: height); 40 | } 41 | 42 | /// Returns a vertical space with height set to [_HorizontalSpaceSmall] 43 | static Widget horizontalSpaceSmall() { 44 | return horizontalSpace(_HorizontalSpaceSmall); 45 | } 46 | 47 | /// Returns a vertical space with height set to [_HorizontalSpaceMedium] 48 | static Widget horizontalSpaceMedium() { 49 | return horizontalSpace(_HorizontalSpaceMedium); 50 | } 51 | 52 | /// Returns a vertical space with height set to [HorizontalSpaceLarge] 53 | static Widget horizontalSpaceLarge() { 54 | return horizontalSpace(HorizontalSpaceLarge); 55 | } 56 | 57 | /// Returns a vertical space equal to the [width] supplied 58 | static Widget horizontalSpace(double width) { 59 | return Container(width: width); 60 | } 61 | 62 | static Widget buildCustomPrefixIcon(Image iconData) { 63 | return Container( 64 | width: 0, 65 | alignment: Alignment(-0.5, 0.5), 66 | child: SizedBox(height: 24, width: 24, child: iconData), 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/src/ui/custom_widgets/custom_text_field.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/services.dart'; 4 | import 'package:flutter_bloc_architecture/src/constants/font_constants.dart'; 5 | import 'package:flutter_bloc_architecture/src/resources/app_colors.dart'; 6 | import 'package:flutter_bloc_architecture/src/resources/dimens.dart'; 7 | import 'package:flutter_bloc_architecture/src/resources/text_styles.dart'; 8 | 9 | class CustomTextField extends StatelessWidget { 10 | final String hint; 11 | final TextEditingController textEditingController; 12 | final TextInputType keyboardType; 13 | final errorText; 14 | final bool obscureText; 15 | final TextCapitalization textCapitalization; 16 | final FormFieldValidator validator; 17 | final List inputFormatters; 18 | final int maxLength; 19 | final int maxLines; 20 | final TextStyle hintStyle; 21 | final Function tap; 22 | final bool isFocused; 23 | final String counterText; 24 | final bool autoValidate; 25 | final textAlignment; 26 | final FocusNode currentFocusNode; 27 | final FocusNode nextFocusNode; 28 | final TextInputAction textInputAction; 29 | final ValueChanged onFieldSubmitted; 30 | final ValueChanged onChanged; 31 | final String prefixText; 32 | 33 | CustomTextField({ 34 | key, 35 | this.hint, 36 | this.textEditingController, 37 | this.keyboardType, 38 | this.errorText, 39 | this.obscureText, 40 | this.textCapitalization, 41 | this.validator, 42 | this.inputFormatters, 43 | this.maxLength = 100, 44 | this.maxLines = 1, 45 | this.hintStyle, 46 | this.tap, 47 | this.isFocused, 48 | this.counterText = "", 49 | this.autoValidate = false, 50 | this.currentFocusNode, 51 | this.nextFocusNode, 52 | this.onFieldSubmitted, 53 | this.onChanged, 54 | this.textInputAction = TextInputAction.done, 55 | this.textAlignment = TextAlign.left, 56 | this.prefixText, 57 | }) : super(key: key); 58 | 59 | @override 60 | Widget build(BuildContext context) { 61 | double _width = MediaQuery.of(context).size.width; 62 | return TextFormField( 63 | textCapitalization: keyboardType == TextInputType.emailAddress 64 | ? TextCapitalization.none 65 | : TextCapitalization.sentences, 66 | textInputAction: textInputAction, 67 | maxLength: maxLength, 68 | controller: textEditingController, 69 | onTap: tap, 70 | obscureText: obscureText, 71 | keyboardType: keyboardType, 72 | style: AppTextStyles.getMediumText( 73 | _width, AppColors.black, FontConstant.kRegular), 74 | textAlign: textAlignment, 75 | focusNode: currentFocusNode, 76 | inputFormatters: inputFormatters, 77 | onFieldSubmitted: onFieldSubmitted, 78 | onChanged: onChanged, 79 | decoration: InputDecoration( 80 | errorStyle: TextStyle( 81 | color: isFocused ? AppColors.primaryColor : AppColors.primaryColor), 82 | errorBorder: OutlineInputBorder( 83 | borderSide: BorderSide( 84 | width: Dimens.px1, 85 | color: isFocused 86 | ? AppColors.black 87 | : AppColors.black.withOpacity(.50)), 88 | borderRadius: BorderRadius.all( 89 | Radius.circular(Dimens.px22), 90 | )), 91 | focusedErrorBorder: OutlineInputBorder( 92 | borderSide: BorderSide( 93 | width: Dimens.px1, 94 | color: isFocused 95 | ? AppColors.black 96 | : AppColors.black.withOpacity(.50)), 97 | borderRadius: BorderRadius.all( 98 | Radius.circular(Dimens.px22), 99 | )), 100 | prefixText: prefixText, 101 | prefixStyle: AppTextStyles.getMediumText( 102 | _width, AppColors.white, FontConstant.kRegular), 103 | counterText: counterText, 104 | hintStyle: AppTextStyles.getSmallText( 105 | _width, 106 | isFocused ? AppColors.white : AppColors.white.withOpacity(.50), 107 | FontConstant.kRegular), 108 | hintText: hint, 109 | contentPadding: EdgeInsets.only( 110 | left: Dimens.px16, 111 | top: Dimens.px12, 112 | bottom: Dimens.px12, 113 | right: Dimens.px12), 114 | enabledBorder: OutlineInputBorder( 115 | borderSide: BorderSide( 116 | width: Dimens.px1, 117 | color: isFocused 118 | ? AppColors.black 119 | : AppColors.black.withOpacity(.50)), 120 | borderRadius: BorderRadius.all( 121 | Radius.circular(Dimens.px22), 122 | )), 123 | focusedBorder: OutlineInputBorder( 124 | borderSide: BorderSide(width: Dimens.px1, color: AppColors.black), 125 | borderRadius: BorderRadius.all( 126 | Radius.circular(Dimens.px22), 127 | ), 128 | ), 129 | border: OutlineInputBorder( 130 | borderRadius: BorderRadius.all( 131 | Radius.circular(Dimens.px22), 132 | ), 133 | borderSide: BorderSide( 134 | color: isFocused 135 | ? AppColors.black 136 | : AppColors.black.withOpacity(.50), 137 | width: Dimens.px1)), 138 | ), 139 | validator: validator, 140 | //define method here or in place of use 141 | autovalidate: autoValidate, 142 | ); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /lib/src/ui/screens/home/home_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:flutter_bloc_architecture/src/bloc/bottom_nav/bottom_nav_cubit.dart'; 4 | import 'package:flutter_bloc_architecture/src/bloc/bottom_nav/checkbox_cubit.dart'; 5 | import 'package:flutter_bloc_architecture/src/constants/font_constants.dart'; 6 | import 'package:flutter_bloc_architecture/src/constants/string_constant.dart'; 7 | import 'package:flutter_bloc_architecture/src/resources/app_colors.dart'; 8 | import 'package:flutter_bloc_architecture/src/resources/text_styles.dart'; 9 | 10 | class HomeScreen extends StatefulWidget { 11 | @override 12 | _HomeScreenState createState() => _HomeScreenState(); 13 | } 14 | 15 | class _HomeScreenState extends State { 16 | var index=0; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Scaffold( 21 | appBar: AppBar( 22 | elevation: 0, 23 | ), 24 | body: Center( 25 | child: Container( 26 | child: BlocBuilder( 27 | builder: (context, isCheckBox) { 28 | return Checkbox(value: isCheckBox, onChanged: (value){ 29 | context.read().selectCheckBox(value); 30 | }); 31 | 32 | } 33 | ), 34 | ), 35 | ), 36 | bottomNavigationBar: 37 | BlocBuilder( 38 | builder: (context, screenIndex) { 39 | 40 | print("screenIndex=${screenIndex}"); 41 | 42 | return BottomNavigationBar( 43 | backgroundColor: Colors.red, 44 | items: [ 45 | BottomNavigationBarItem( 46 | icon: const Icon(Icons.home), 47 | label: StringConstant.home 48 | ), 49 | BottomNavigationBarItem( 50 | icon: const Icon(Icons.work), 51 | label: StringConstant.help 52 | ), 53 | BottomNavigationBarItem( 54 | icon: const Icon(Icons.face), 55 | label: StringConstant.profile 56 | ) 57 | ], 58 | currentIndex: screenIndex, 59 | onTap: (int i) { 60 | print("index=${i}"); 61 | context.read().selectTab(i); 62 | }, 63 | fixedColor: Colors.white, 64 | ); 65 | 66 | } 67 | ), 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/src/ui/screens/login/login_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:flutter_bloc_architecture/src/bloc/login/login.dart'; 5 | import 'package:flutter_bloc_architecture/src/constants/font_constants.dart'; 6 | import 'package:flutter_bloc_architecture/src/constants/page_route_constants.dart'; 7 | import 'package:flutter_bloc_architecture/src/constants/string_constant.dart'; 8 | import 'package:flutter_bloc_architecture/src/models/local_data_models/login_user_details.dart'; 9 | import 'package:flutter_bloc_architecture/src/resources/app_colors.dart'; 10 | import 'package:flutter_bloc_architecture/src/resources/dimens.dart'; 11 | import 'package:flutter_bloc_architecture/src/resources/text_styles.dart'; 12 | import 'package:flutter_bloc_architecture/src/ui/custom_widgets/custom_text_field.dart'; 13 | import 'package:flutter_bloc_architecture/src/utils/helper.dart'; 14 | 15 | class LoginScreen extends StatefulWidget { 16 | @override 17 | _LoginScreenState createState() => _LoginScreenState(); 18 | } 19 | 20 | class _LoginScreenState extends State { 21 | final _emailController = new TextEditingController(); 22 | final _passwordController = new TextEditingController(); 23 | LoginBloc loginBloc; 24 | final loginUserDetails = LoginUserDetails(); 25 | final _scaffoldKey = GlobalKey(); 26 | final progressKey = GlobalKey(); 27 | final _emailFocus = FocusNode(); 28 | final _passwordFocus = FocusNode(); 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | final size = MediaQuery.of(context).size; 33 | return BlocBuilder( 34 | builder: (context, state) { 35 | return new Scaffold( 36 | backgroundColor: AppColors.white, 37 | key: _scaffoldKey, 38 | resizeToAvoidBottomPadding: true, 39 | body: SingleChildScrollView( 40 | physics: NeverScrollableScrollPhysics(), 41 | child: Container( 42 | height: size.height, 43 | width: size.width, 44 | child: Column( 45 | crossAxisAlignment: CrossAxisAlignment.center, 46 | children: [ 47 | SizedBox( 48 | height: kBottomNavigationBarHeight, 49 | ), 50 | Container( 51 | width: Dimens.px150, 52 | height: Dimens.px150, 53 | child: Image.asset( 54 | 'assets/images/logo.png', 55 | ), 56 | ), 57 | Text(StringConstant.sign_in, 58 | style: AppTextStyles.getLargeText( 59 | size.width, AppColors.black, FontConstant.kBold)), 60 | Container( 61 | width: size.width * 0.85, 62 | child: Column( 63 | children: [ 64 | _email(state, size), 65 | SizedBox(height: size.height * .03), 66 | _password(state, size), 67 | SizedBox(height: size.height * .03), 68 | _submitButton(size, state) 69 | ], 70 | ), 71 | ) 72 | ]), 73 | ), 74 | )); 75 | }, 76 | ); 77 | } 78 | 79 | _onEmailChanged() { 80 | loginUserDetails.userEmail = _emailController.text; 81 | if (loginUserDetails.userEmail.isNotEmpty) { 82 | loginBloc.add(EmailChanged( 83 | email: _emailController.text, 84 | )); 85 | } 86 | } 87 | 88 | _onPasswordChanged() { 89 | loginUserDetails.password = _passwordController.text; 90 | if (loginUserDetails.password.isNotEmpty) { 91 | loginBloc.add(PasswordChanged( 92 | password: _passwordController.text, 93 | )); 94 | } 95 | } 96 | 97 | Widget _email(LoginState loginState, Size size) { 98 | return Column( 99 | crossAxisAlignment: CrossAxisAlignment.start, 100 | children: [ 101 | Text( 102 | StringConstant.email, 103 | style: AppTextStyles.getMediumText( 104 | size.width, AppColors.black, FontConstant.kBold), 105 | ), 106 | SizedBox( 107 | height: Dimens.px8, 108 | ), 109 | CustomTextField( 110 | hint: StringConstant.type_email, 111 | obscureText: false, 112 | keyboardType: TextInputType.emailAddress, 113 | textInputAction: TextInputAction.next, 114 | errorText: StringConstant.please_enter_email_address, 115 | textEditingController: _emailController, 116 | currentFocusNode: _emailFocus, 117 | isFocused: loginUserDetails.userEmail != null && 118 | loginUserDetails.userEmail.isNotEmpty 119 | ? true 120 | : false, 121 | validator: (_) { 122 | return (loginUserDetails.userEmail == null || 123 | loginUserDetails.userEmail.isEmpty) || 124 | loginState.isEmailValid 125 | ? null 126 | : StringConstant.invalid_user_name; 127 | }, 128 | ) 129 | ], 130 | ); 131 | } 132 | 133 | Widget _password(LoginState loginState, Size size) { 134 | return Column( 135 | crossAxisAlignment: CrossAxisAlignment.start, 136 | children: [ 137 | Text( 138 | StringConstant.password, 139 | style: AppTextStyles.getMediumText( 140 | size.width, AppColors.black, FontConstant.kBold), 141 | ), 142 | SizedBox( 143 | height: Dimens.px8, 144 | ), 145 | CustomTextField( 146 | hint: StringConstant.password_hint, 147 | obscureText: true, 148 | keyboardType: TextInputType.text, 149 | textInputAction: TextInputAction.next, 150 | errorText: StringConstant.invalid_password, 151 | textEditingController: _passwordController, 152 | currentFocusNode: _passwordFocus, 153 | isFocused: loginUserDetails.password != null && 154 | loginUserDetails.password.isNotEmpty 155 | ? true 156 | : false, 157 | validator: (_) { 158 | return (loginUserDetails.password == null || 159 | loginUserDetails.password.isEmpty) || 160 | loginState.isPasswordValid 161 | ? null 162 | : StringConstant.invalid_password; 163 | }, 164 | ) 165 | ], 166 | ); 167 | } 168 | 169 | void showInSnackBar(String value) { 170 | _scaffoldKey.currentState.showSnackBar(SnackBar( 171 | content: Text(value), 172 | backgroundColor: AppColors.black, 173 | )); 174 | } 175 | 176 | Widget _submitButton(Size size, LoginState state) { 177 | return Container( 178 | width: size.width, 179 | height: kBottomNavigationBarHeight, 180 | child: BlocListener( 181 | listener: (context, state) { 182 | if (state is UserLoggedIn) { 183 | Navigator.of(context).pushNamedAndRemoveUntil( 184 | PageRouteConstants.home_screen, 185 | (Route route) => false); 186 | } else if (state is LoginFailure) { 187 | /* Helper.showAlert(context, StringConstant.error_message, 188 | StringConstant.invalid_user_credentials);*/ 189 | Navigator.of(context).pushNamedAndRemoveUntil( 190 | PageRouteConstants.home_screen, 191 | (Route route) => false); 192 | } 193 | }, 194 | child: BlocBuilder( 195 | builder: (context, state) { 196 | if (state is LoginLoading) { 197 | return Helper.progressWidget(progressKey); 198 | } else { 199 | return RaisedButton( 200 | child: Text( 201 | StringConstant.sign_in, 202 | style: AppTextStyles.getMediumText( 203 | size.width, AppColors.white, FontConstant.kSemiBold), 204 | ), 205 | onPressed: () { 206 | if (!(_emailController.text.length > 0) || 207 | !state.isEmailValid) { 208 | showInSnackBar(StringConstant.invalid_email); 209 | } else if (!(_passwordController.text.length > 0) || 210 | !state.isPasswordValid) { 211 | showInSnackBar(StringConstant.invalid_password); 212 | } else { 213 | Helper.checkConnectivity().then((internetStatus) { 214 | if (internetStatus) { 215 | if (progressKey.currentWidget == null) { 216 | BlocProvider.of(context).add( 217 | SignInUser( 218 | email: _emailController.text, 219 | password: _passwordController.text, 220 | ), 221 | ); 222 | } 223 | } else { 224 | Helper.showAlert(context, StringConstant.internet_alert, 225 | StringConstant.please_check_internet_connectivity); 226 | } 227 | }); 228 | } 229 | }, 230 | color: Theme.of(context).primaryColor, 231 | shape: RoundedRectangleBorder( 232 | borderRadius: BorderRadius.circular(Dimens.px28), 233 | ), 234 | ); 235 | } 236 | }, 237 | ), 238 | ), 239 | ); 240 | } 241 | 242 | @override 243 | void dispose() { 244 | _emailController.dispose(); 245 | _passwordController.dispose(); 246 | super.dispose(); 247 | } 248 | 249 | @override 250 | void initState() { 251 | _emailController.addListener(_onEmailChanged); 252 | _passwordController.addListener(_onPasswordChanged); 253 | loginBloc = BlocProvider.of(context); 254 | super.initState(); 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /lib/src/ui/screens/splash/splash_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc_architecture/src/constants/page_route_constants.dart'; 3 | import 'package:flutter_bloc_architecture/src/resources/dimens.dart'; 4 | 5 | class SplashScreen extends StatefulWidget { 6 | @override 7 | _SplashScreenState createState() => _SplashScreenState(); 8 | } 9 | 10 | class _SplashScreenState extends State 11 | with SingleTickerProviderStateMixin { 12 | AnimationController animationController; 13 | Animation animation; 14 | 15 | @override 16 | void initState() { 17 | super.initState(); 18 | _startAnimation(); 19 | } 20 | 21 | //animated splash 22 | _startAnimation() { 23 | animationController = 24 | AnimationController(vsync: this, duration: Duration(seconds: 2)); 25 | animation = 26 | CurvedAnimation(parent: animationController, curve: Curves.easeOut) 27 | ..addListener(() { 28 | if (animationController.isCompleted) { 29 | Navigator.of(context).pushNamed(PageRouteConstants.login_screen); 30 | } 31 | setState(() {}); 32 | }); 33 | animationController.forward(); 34 | } 35 | 36 | @override 37 | void dispose() { 38 | animationController.dispose(); 39 | super.dispose(); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | final Size size = MediaQuery.of(context).size; 45 | return Scaffold( 46 | body: Container( 47 | height: size.height, 48 | child: Column( 49 | children: [ 50 | Spacer(), 51 | Image.asset( 52 | 'assets/images/logo.png', 53 | width: animation.value * 250, 54 | height: animation.value * 250, 55 | ), 56 | Spacer(), 57 | Center( 58 | child: Padding( 59 | padding: const EdgeInsets.all(Dimens.px10), 60 | child: Image.asset( 61 | 'assets/images/powered_by.png', 62 | height: Dimens.px25, 63 | fit: BoxFit.scaleDown, 64 | ), 65 | ), 66 | ), 67 | ], 68 | ), 69 | ), 70 | ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/src/utils/date_time_util.dart: -------------------------------------------------------------------------------- 1 | import 'package:intl/intl.dart'; 2 | 3 | String formatDateTime(DateTime dateTime) { 4 | String formattedDate = DateFormat('yyyy-MM-dd – kk:mm').format(dateTime); 5 | return formattedDate; 6 | } 7 | 8 | String formatCurrentDateTime() { 9 | DateTime now = DateTime.now(); 10 | String formattedDate = DateFormat('yyyy-MM-dd – kk:mm').format(now); 11 | return formattedDate; 12 | } 13 | -------------------------------------------------------------------------------- /lib/src/utils/device_utils.dart: -------------------------------------------------------------------------------- 1 | // 2 | import 'package:flutter/material.dart'; 3 | 4 | /// Helper class for device related operations. 5 | /// 6 | class DeviceUtils { 7 | /// 8 | /// hides the keyboard if its already open 9 | /// 10 | static hideKeyboard(BuildContext context) { 11 | FocusScope.of(context).unfocus(); 12 | } 13 | 14 | /// 15 | /// accepts a double [scale] and returns scaled sized based on the screen 16 | /// orientation 17 | /// 18 | static double getScaledSize(BuildContext context, double scale) => 19 | scale * 20 | (MediaQuery.of(context).orientation == Orientation.portrait 21 | ? MediaQuery.of(context).size.width 22 | : MediaQuery.of(context).size.height); 23 | 24 | /// 25 | /// accepts a double [scale] and returns scaled sized based on the screen 26 | /// width 27 | /// 28 | static double getScaledWidth(BuildContext context, double scale) => 29 | scale * MediaQuery.of(context).size.width; 30 | 31 | /// 32 | /// accepts a double [scale] and returns scaled sized based on the screen 33 | /// height 34 | /// 35 | static double getScaledHeight(BuildContext context, double scale) => 36 | scale * MediaQuery.of(context).size.height; 37 | } 38 | -------------------------------------------------------------------------------- /lib/src/utils/helper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_bloc_architecture/src/constants/string_constant.dart'; 6 | import 'package:flutter_bloc_architecture/src/resources/dimens.dart'; 7 | import 'package:flutter_bloc_architecture/src/utils/utils.dart'; 8 | import 'package:fluttertoast/fluttertoast.dart'; 9 | import 'package:logger/logger.dart'; 10 | 11 | class Helper { 12 | static var logger = Logger(); 13 | 14 | static printLogValue(dynamic value) { 15 | logger.d(value.toString()); 16 | } 17 | 18 | static void showMessage(String message) { 19 | Fluttertoast.showToast( 20 | msg: message, 21 | toastLength: Toast.LENGTH_SHORT, 22 | gravity: ToastGravity.CENTER, 23 | timeInSecForIos: 1, 24 | backgroundColor: AppColors.primaryColor, 25 | textColor: AppColors.white, 26 | fontSize: Dimens.px16); 27 | } 28 | 29 | static void showAlert(BuildContext context, String title, String errorMsg) { 30 | showDialog( 31 | context: context, 32 | barrierDismissible: false, 33 | builder: (BuildContext context) { 34 | return AlertDialog( 35 | title: Text( 36 | title, 37 | style: TextStyle(color: Theme.of(context).primaryColor), 38 | ), 39 | content: Text(errorMsg), 40 | actions: [ 41 | FlatButton( 42 | child: Text(StringConstant.ok), 43 | onPressed: () { 44 | Navigator.pop(context); 45 | }, 46 | ), 47 | ], 48 | ); 49 | }, 50 | ); 51 | } 52 | 53 | static Widget progressWidget(GlobalKey progressKey) { 54 | return Container( 55 | height: Dimens.px56, 56 | child: Center( 57 | child: CircularProgressIndicator( 58 | key: progressKey, 59 | ), 60 | )); 61 | } 62 | 63 | static Future checkConnectivity() async { 64 | try { 65 | final result = await InternetAddress.lookup('google.com'); 66 | if (result.isNotEmpty && result.first.rawAddress.isNotEmpty) { 67 | Helper.printLogValue('connected'); 68 | return true; 69 | } else { 70 | return false; 71 | } 72 | } on SocketException catch (_) { 73 | Helper.printLogValue('not connected'); 74 | return false; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/src/utils/navigation_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NavigationService { 4 | final navigatorKey = GlobalKey(); 5 | 6 | Future navigateTo(String routeName, {arguments}) { 7 | return navigatorKey.currentState.pushNamed(routeName, arguments: arguments); 8 | } 9 | 10 | Future navigateAndRemove(String routeName, {arguments}) { 11 | return navigatorKey.currentState.pushNamedAndRemoveUntil( 12 | routeName, (Route route) => false, 13 | arguments: arguments); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/utils/screen_router.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc_architecture/src/constants/page_route_constants.dart'; 3 | import 'package:flutter_bloc_architecture/src/ui/screens/home/home_screen.dart'; 4 | import 'package:flutter_bloc_architecture/src/ui/screens/login/login_screen.dart'; 5 | import 'package:flutter_bloc_architecture/src/ui/screens/splash/splash_screen.dart'; 6 | 7 | class ScreenRouter { 8 | static Route generateRoute(RouteSettings settings) { 9 | switch (settings.name) { 10 | case PageRouteConstants.home_screen: 11 | return MaterialPageRoute(builder: (_) => HomeScreen()); 12 | case PageRouteConstants.splash_screen: 13 | return MaterialPageRoute(builder: (_) => SplashScreen()); 14 | case PageRouteConstants.login_screen: 15 | return MaterialPageRoute(builder: (_) => LoginScreen()); 16 | default: 17 | return MaterialPageRoute( 18 | builder: (_) => Scaffold( 19 | body: Center( 20 | child: Text('No route defined for ${settings.name}')), 21 | )); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/utils/url_launcher.dart: -------------------------------------------------------------------------------- 1 | import 'package:url_launcher/url_launcher.dart'; 2 | 3 | class UrlLauncher { 4 | static Future launchURL(String url) async { 5 | if (await canLaunch(url)) { 6 | await launch(url); 7 | } else { 8 | throw 'Could not launch $url'; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/utils/utils.dart: -------------------------------------------------------------------------------- 1 | export '../resources/app_colors.dart'; 2 | export '../resources/app_localization.dart'; 3 | export 'date_time_util.dart'; 4 | export 'device_utils.dart'; 5 | export 'url_launcher.dart'; 6 | -------------------------------------------------------------------------------- /lib/src/utils/validator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_bloc_architecture/src/constants/regex_constant.dart'; 2 | 3 | class Validator { 4 | bool validateEmail(String value) { 5 | RegExp regExp = RegExp(RegexConstant.valid_email); 6 | if (!regExp.hasMatch(value)) { 7 | return false; 8 | } else { 9 | return true; 10 | } 11 | } 12 | 13 | bool validatePassword(String value) { 14 | if (value.length == 0) { 15 | return false; 16 | } else if (value.length < 4) { 17 | return false; 18 | } else { 19 | return true; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "1.0.3" 11 | analyzer: 12 | dependency: transitive 13 | description: 14 | name: analyzer 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "0.39.4" 18 | archive: 19 | dependency: transitive 20 | description: 21 | name: archive 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.0.11" 25 | args: 26 | dependency: transitive 27 | description: 28 | name: args 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.5.2" 32 | async: 33 | dependency: transitive 34 | description: 35 | name: async 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "2.5.0-nullsafety.1" 39 | auto_route: 40 | dependency: "direct main" 41 | description: 42 | name: auto_route 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "0.3.1" 46 | auto_route_generator: 47 | dependency: "direct dev" 48 | description: 49 | name: auto_route_generator 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "0.3.2" 53 | bloc: 54 | dependency: transitive 55 | description: 56 | name: bloc 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "6.1.3" 60 | boolean_selector: 61 | dependency: transitive 62 | description: 63 | name: boolean_selector 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "2.1.0-nullsafety.1" 67 | build: 68 | dependency: transitive 69 | description: 70 | name: build 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.2.2" 74 | build_config: 75 | dependency: transitive 76 | description: 77 | name: build_config 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "0.4.2" 81 | build_daemon: 82 | dependency: transitive 83 | description: 84 | name: build_daemon 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "2.1.3" 88 | build_resolvers: 89 | dependency: transitive 90 | description: 91 | name: build_resolvers 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "1.3.3" 95 | build_runner: 96 | dependency: "direct dev" 97 | description: 98 | name: build_runner 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "1.8.0" 102 | build_runner_core: 103 | dependency: transitive 104 | description: 105 | name: build_runner_core 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "4.5.2" 109 | built_collection: 110 | dependency: transitive 111 | description: 112 | name: built_collection 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "4.3.2" 116 | built_value: 117 | dependency: transitive 118 | description: 119 | name: built_value 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "7.0.9" 123 | characters: 124 | dependency: transitive 125 | description: 126 | name: characters 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "1.1.0-nullsafety.3" 130 | charcode: 131 | dependency: transitive 132 | description: 133 | name: charcode 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "1.2.0-nullsafety.1" 137 | checked_yaml: 138 | dependency: transitive 139 | description: 140 | name: checked_yaml 141 | url: "https://pub.dartlang.org" 142 | source: hosted 143 | version: "1.0.2" 144 | clock: 145 | dependency: transitive 146 | description: 147 | name: clock 148 | url: "https://pub.dartlang.org" 149 | source: hosted 150 | version: "1.1.0-nullsafety.1" 151 | code_builder: 152 | dependency: transitive 153 | description: 154 | name: code_builder 155 | url: "https://pub.dartlang.org" 156 | source: hosted 157 | version: "3.2.1" 158 | collection: 159 | dependency: transitive 160 | description: 161 | name: collection 162 | url: "https://pub.dartlang.org" 163 | source: hosted 164 | version: "1.15.0-nullsafety.3" 165 | convert: 166 | dependency: transitive 167 | description: 168 | name: convert 169 | url: "https://pub.dartlang.org" 170 | source: hosted 171 | version: "2.1.1" 172 | crypto: 173 | dependency: transitive 174 | description: 175 | name: crypto 176 | url: "https://pub.dartlang.org" 177 | source: hosted 178 | version: "2.1.3" 179 | csslib: 180 | dependency: transitive 181 | description: 182 | name: csslib 183 | url: "https://pub.dartlang.org" 184 | source: hosted 185 | version: "0.16.1" 186 | cupertino_icons: 187 | dependency: "direct main" 188 | description: 189 | name: cupertino_icons 190 | url: "https://pub.dartlang.org" 191 | source: hosted 192 | version: "0.1.3" 193 | dart_style: 194 | dependency: transitive 195 | description: 196 | name: dart_style 197 | url: "https://pub.dartlang.org" 198 | source: hosted 199 | version: "1.3.3" 200 | dio: 201 | dependency: "direct main" 202 | description: 203 | name: dio 204 | url: "https://pub.dartlang.org" 205 | source: hosted 206 | version: "3.0.8" 207 | equatable: 208 | dependency: "direct main" 209 | description: 210 | name: equatable 211 | url: "https://pub.dartlang.org" 212 | source: hosted 213 | version: "1.1.1" 214 | fake_async: 215 | dependency: transitive 216 | description: 217 | name: fake_async 218 | url: "https://pub.dartlang.org" 219 | source: hosted 220 | version: "1.2.0-nullsafety.1" 221 | fixnum: 222 | dependency: transitive 223 | description: 224 | name: fixnum 225 | url: "https://pub.dartlang.org" 226 | source: hosted 227 | version: "0.10.11" 228 | flushbar: 229 | dependency: "direct main" 230 | description: 231 | name: flushbar 232 | url: "https://pub.dartlang.org" 233 | source: hosted 234 | version: "1.9.1" 235 | flutter: 236 | dependency: "direct main" 237 | description: flutter 238 | source: sdk 239 | version: "0.0.0" 240 | flutter_bloc: 241 | dependency: "direct main" 242 | description: 243 | name: flutter_bloc 244 | url: "https://pub.dartlang.org" 245 | source: hosted 246 | version: "6.1.3" 247 | flutter_cupertino_localizations: 248 | dependency: "direct main" 249 | description: 250 | name: flutter_cupertino_localizations 251 | url: "https://pub.dartlang.org" 252 | source: hosted 253 | version: "1.0.1" 254 | flutter_launcher_icons: 255 | dependency: "direct main" 256 | description: 257 | name: flutter_launcher_icons 258 | url: "https://pub.dartlang.org" 259 | source: hosted 260 | version: "0.7.4" 261 | flutter_localizations: 262 | dependency: "direct main" 263 | description: flutter 264 | source: sdk 265 | version: "0.0.0" 266 | flutter_platform_widgets: 267 | dependency: "direct main" 268 | description: 269 | name: flutter_platform_widgets 270 | url: "https://pub.dartlang.org" 271 | source: hosted 272 | version: "0.32.4" 273 | flutter_test: 274 | dependency: "direct dev" 275 | description: flutter 276 | source: sdk 277 | version: "0.0.0" 278 | flutter_web_plugins: 279 | dependency: transitive 280 | description: flutter 281 | source: sdk 282 | version: "0.0.0" 283 | fluttertoast: 284 | dependency: "direct main" 285 | description: 286 | name: fluttertoast 287 | url: "https://pub.dartlang.org" 288 | source: hosted 289 | version: "3.1.3" 290 | get_it: 291 | dependency: "direct main" 292 | description: 293 | name: get_it 294 | url: "https://pub.dartlang.org" 295 | source: hosted 296 | version: "4.0.1" 297 | glob: 298 | dependency: transitive 299 | description: 300 | name: glob 301 | url: "https://pub.dartlang.org" 302 | source: hosted 303 | version: "1.2.0" 304 | graphs: 305 | dependency: transitive 306 | description: 307 | name: graphs 308 | url: "https://pub.dartlang.org" 309 | source: hosted 310 | version: "0.2.0" 311 | html: 312 | dependency: transitive 313 | description: 314 | name: html 315 | url: "https://pub.dartlang.org" 316 | source: hosted 317 | version: "0.14.0+3" 318 | http: 319 | dependency: "direct main" 320 | description: 321 | name: http 322 | url: "https://pub.dartlang.org" 323 | source: hosted 324 | version: "0.12.0+2" 325 | http_multi_server: 326 | dependency: transitive 327 | description: 328 | name: http_multi_server 329 | url: "https://pub.dartlang.org" 330 | source: hosted 331 | version: "2.2.0" 332 | http_parser: 333 | dependency: transitive 334 | description: 335 | name: http_parser 336 | url: "https://pub.dartlang.org" 337 | source: hosted 338 | version: "3.1.3" 339 | image: 340 | dependency: transitive 341 | description: 342 | name: image 343 | url: "https://pub.dartlang.org" 344 | source: hosted 345 | version: "2.1.4" 346 | intl: 347 | dependency: "direct main" 348 | description: 349 | name: intl 350 | url: "https://pub.dartlang.org" 351 | source: hosted 352 | version: "0.16.1" 353 | io: 354 | dependency: transitive 355 | description: 356 | name: io 357 | url: "https://pub.dartlang.org" 358 | source: hosted 359 | version: "0.3.3" 360 | js: 361 | dependency: transitive 362 | description: 363 | name: js 364 | url: "https://pub.dartlang.org" 365 | source: hosted 366 | version: "0.6.1+1" 367 | json_annotation: 368 | dependency: transitive 369 | description: 370 | name: json_annotation 371 | url: "https://pub.dartlang.org" 372 | source: hosted 373 | version: "3.0.1" 374 | json_serializable: 375 | dependency: "direct dev" 376 | description: 377 | name: json_serializable 378 | url: "https://pub.dartlang.org" 379 | source: hosted 380 | version: "3.3.0" 381 | logger: 382 | dependency: "direct main" 383 | description: 384 | name: logger 385 | url: "https://pub.dartlang.org" 386 | source: hosted 387 | version: "0.8.3" 388 | logging: 389 | dependency: transitive 390 | description: 391 | name: logging 392 | url: "https://pub.dartlang.org" 393 | source: hosted 394 | version: "0.11.4" 395 | matcher: 396 | dependency: transitive 397 | description: 398 | name: matcher 399 | url: "https://pub.dartlang.org" 400 | source: hosted 401 | version: "0.12.10-nullsafety.1" 402 | material_dialog: 403 | dependency: "direct main" 404 | description: 405 | name: material_dialog 406 | url: "https://pub.dartlang.org" 407 | source: hosted 408 | version: "0.0.9" 409 | meta: 410 | dependency: transitive 411 | description: 412 | name: meta 413 | url: "https://pub.dartlang.org" 414 | source: hosted 415 | version: "1.3.0-nullsafety.3" 416 | mime: 417 | dependency: transitive 418 | description: 419 | name: mime 420 | url: "https://pub.dartlang.org" 421 | source: hosted 422 | version: "0.9.6+3" 423 | nested: 424 | dependency: transitive 425 | description: 426 | name: nested 427 | url: "https://pub.dartlang.org" 428 | source: hosted 429 | version: "0.0.4" 430 | node_interop: 431 | dependency: transitive 432 | description: 433 | name: node_interop 434 | url: "https://pub.dartlang.org" 435 | source: hosted 436 | version: "1.0.3" 437 | node_io: 438 | dependency: transitive 439 | description: 440 | name: node_io 441 | url: "https://pub.dartlang.org" 442 | source: hosted 443 | version: "1.0.1+2" 444 | package_config: 445 | dependency: transitive 446 | description: 447 | name: package_config 448 | url: "https://pub.dartlang.org" 449 | source: hosted 450 | version: "1.9.2" 451 | package_resolver: 452 | dependency: transitive 453 | description: 454 | name: package_resolver 455 | url: "https://pub.dartlang.org" 456 | source: hosted 457 | version: "1.0.10" 458 | path: 459 | dependency: transitive 460 | description: 461 | name: path 462 | url: "https://pub.dartlang.org" 463 | source: hosted 464 | version: "1.8.0-nullsafety.1" 465 | path_provider: 466 | dependency: "direct main" 467 | description: 468 | name: path_provider 469 | url: "https://pub.dartlang.org" 470 | source: hosted 471 | version: "1.6.5" 472 | path_provider_macos: 473 | dependency: transitive 474 | description: 475 | name: path_provider_macos 476 | url: "https://pub.dartlang.org" 477 | source: hosted 478 | version: "0.0.4" 479 | path_provider_platform_interface: 480 | dependency: transitive 481 | description: 482 | name: path_provider_platform_interface 483 | url: "https://pub.dartlang.org" 484 | source: hosted 485 | version: "1.0.1" 486 | pedantic: 487 | dependency: transitive 488 | description: 489 | name: pedantic 490 | url: "https://pub.dartlang.org" 491 | source: hosted 492 | version: "1.8.0+1" 493 | petitparser: 494 | dependency: transitive 495 | description: 496 | name: petitparser 497 | url: "https://pub.dartlang.org" 498 | source: hosted 499 | version: "2.4.0" 500 | platform: 501 | dependency: transitive 502 | description: 503 | name: platform 504 | url: "https://pub.dartlang.org" 505 | source: hosted 506 | version: "2.2.1" 507 | plugin_platform_interface: 508 | dependency: transitive 509 | description: 510 | name: plugin_platform_interface 511 | url: "https://pub.dartlang.org" 512 | source: hosted 513 | version: "1.0.2" 514 | pool: 515 | dependency: transitive 516 | description: 517 | name: pool 518 | url: "https://pub.dartlang.org" 519 | source: hosted 520 | version: "1.4.0" 521 | progress_dialog: 522 | dependency: "direct main" 523 | description: 524 | name: progress_dialog 525 | url: "https://pub.dartlang.org" 526 | source: hosted 527 | version: "1.2.1" 528 | provider: 529 | dependency: transitive 530 | description: 531 | name: provider 532 | url: "https://pub.dartlang.org" 533 | source: hosted 534 | version: "4.3.3" 535 | pub_semver: 536 | dependency: transitive 537 | description: 538 | name: pub_semver 539 | url: "https://pub.dartlang.org" 540 | source: hosted 541 | version: "1.4.4" 542 | pubspec_parse: 543 | dependency: transitive 544 | description: 545 | name: pubspec_parse 546 | url: "https://pub.dartlang.org" 547 | source: hosted 548 | version: "0.1.5" 549 | quiver: 550 | dependency: transitive 551 | description: 552 | name: quiver 553 | url: "https://pub.dartlang.org" 554 | source: hosted 555 | version: "2.0.5" 556 | retrofit: 557 | dependency: transitive 558 | description: 559 | name: retrofit 560 | url: "https://pub.dartlang.org" 561 | source: hosted 562 | version: "1.3.4+1" 563 | retrofit_generator: 564 | dependency: "direct dev" 565 | description: 566 | name: retrofit_generator 567 | url: "https://pub.dartlang.org" 568 | source: hosted 569 | version: "1.4.1+3" 570 | shared_preferences: 571 | dependency: "direct main" 572 | description: 573 | name: shared_preferences 574 | url: "https://pub.dartlang.org" 575 | source: hosted 576 | version: "0.5.6+3" 577 | shared_preferences_macos: 578 | dependency: transitive 579 | description: 580 | name: shared_preferences_macos 581 | url: "https://pub.dartlang.org" 582 | source: hosted 583 | version: "0.0.1+6" 584 | shared_preferences_platform_interface: 585 | dependency: transitive 586 | description: 587 | name: shared_preferences_platform_interface 588 | url: "https://pub.dartlang.org" 589 | source: hosted 590 | version: "1.0.3" 591 | shared_preferences_web: 592 | dependency: transitive 593 | description: 594 | name: shared_preferences_web 595 | url: "https://pub.dartlang.org" 596 | source: hosted 597 | version: "0.1.2+4" 598 | shelf: 599 | dependency: transitive 600 | description: 601 | name: shelf 602 | url: "https://pub.dartlang.org" 603 | source: hosted 604 | version: "0.7.5" 605 | shelf_web_socket: 606 | dependency: transitive 607 | description: 608 | name: shelf_web_socket 609 | url: "https://pub.dartlang.org" 610 | source: hosted 611 | version: "0.2.3" 612 | sky_engine: 613 | dependency: transitive 614 | description: flutter 615 | source: sdk 616 | version: "0.0.99" 617 | source_gen: 618 | dependency: transitive 619 | description: 620 | name: source_gen 621 | url: "https://pub.dartlang.org" 622 | source: hosted 623 | version: "0.9.5" 624 | source_span: 625 | dependency: transitive 626 | description: 627 | name: source_span 628 | url: "https://pub.dartlang.org" 629 | source: hosted 630 | version: "1.8.0-nullsafety.2" 631 | stack_trace: 632 | dependency: transitive 633 | description: 634 | name: stack_trace 635 | url: "https://pub.dartlang.org" 636 | source: hosted 637 | version: "1.10.0-nullsafety.1" 638 | stream_channel: 639 | dependency: transitive 640 | description: 641 | name: stream_channel 642 | url: "https://pub.dartlang.org" 643 | source: hosted 644 | version: "2.1.0-nullsafety.1" 645 | stream_transform: 646 | dependency: transitive 647 | description: 648 | name: stream_transform 649 | url: "https://pub.dartlang.org" 650 | source: hosted 651 | version: "1.2.0" 652 | string_scanner: 653 | dependency: transitive 654 | description: 655 | name: string_scanner 656 | url: "https://pub.dartlang.org" 657 | source: hosted 658 | version: "1.1.0-nullsafety.1" 659 | term_glyph: 660 | dependency: transitive 661 | description: 662 | name: term_glyph 663 | url: "https://pub.dartlang.org" 664 | source: hosted 665 | version: "1.2.0-nullsafety.1" 666 | test_api: 667 | dependency: transitive 668 | description: 669 | name: test_api 670 | url: "https://pub.dartlang.org" 671 | source: hosted 672 | version: "0.2.19-nullsafety.2" 673 | timing: 674 | dependency: transitive 675 | description: 676 | name: timing 677 | url: "https://pub.dartlang.org" 678 | source: hosted 679 | version: "0.1.1+2" 680 | toast: 681 | dependency: "direct main" 682 | description: 683 | name: toast 684 | url: "https://pub.dartlang.org" 685 | source: hosted 686 | version: "0.1.5" 687 | tuple: 688 | dependency: transitive 689 | description: 690 | name: tuple 691 | url: "https://pub.dartlang.org" 692 | source: hosted 693 | version: "1.0.3" 694 | typed_data: 695 | dependency: transitive 696 | description: 697 | name: typed_data 698 | url: "https://pub.dartlang.org" 699 | source: hosted 700 | version: "1.3.0-nullsafety.3" 701 | url_launcher: 702 | dependency: "direct main" 703 | description: 704 | name: url_launcher 705 | url: "https://pub.dartlang.org" 706 | source: hosted 707 | version: "5.4.2" 708 | url_launcher_macos: 709 | dependency: transitive 710 | description: 711 | name: url_launcher_macos 712 | url: "https://pub.dartlang.org" 713 | source: hosted 714 | version: "0.0.1+4" 715 | url_launcher_platform_interface: 716 | dependency: transitive 717 | description: 718 | name: url_launcher_platform_interface 719 | url: "https://pub.dartlang.org" 720 | source: hosted 721 | version: "1.0.6" 722 | url_launcher_web: 723 | dependency: transitive 724 | description: 725 | name: url_launcher_web 726 | url: "https://pub.dartlang.org" 727 | source: hosted 728 | version: "0.1.1+1" 729 | validators: 730 | dependency: "direct main" 731 | description: 732 | name: validators 733 | url: "https://pub.dartlang.org" 734 | source: hosted 735 | version: "2.0.0+1" 736 | vector_math: 737 | dependency: transitive 738 | description: 739 | name: vector_math 740 | url: "https://pub.dartlang.org" 741 | source: hosted 742 | version: "2.1.0-nullsafety.3" 743 | watcher: 744 | dependency: transitive 745 | description: 746 | name: watcher 747 | url: "https://pub.dartlang.org" 748 | source: hosted 749 | version: "0.9.7+14" 750 | wave: 751 | dependency: "direct main" 752 | description: 753 | name: wave 754 | url: "https://pub.dartlang.org" 755 | source: hosted 756 | version: "0.0.8" 757 | web_socket_channel: 758 | dependency: transitive 759 | description: 760 | name: web_socket_channel 761 | url: "https://pub.dartlang.org" 762 | source: hosted 763 | version: "1.1.0" 764 | xml: 765 | dependency: transitive 766 | description: 767 | name: xml 768 | url: "https://pub.dartlang.org" 769 | source: hosted 770 | version: "3.5.0" 771 | yaml: 772 | dependency: transitive 773 | description: 774 | name: yaml 775 | url: "https://pub.dartlang.org" 776 | source: hosted 777 | version: "2.2.0" 778 | sdks: 779 | dart: ">=2.10.0-110 <2.11.0" 780 | flutter: ">=1.16.0 <2.0.0" 781 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_bloc_architecture 2 | description: A new Flutter project. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 1.0.0+1 15 | 16 | environment: 17 | sdk: ">=2.6.0 <3.0.0" 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | 23 | flutter_localizations: 24 | sdk: flutter 25 | flutter_cupertino_localizations: ^1.0.1 26 | 27 | flutter_bloc: ^6.1.2 28 | intl: ^0.16.0 29 | path_provider: ^1.1.0 30 | progress_dialog: 1.2.1 31 | fluttertoast: ^3.1.3 32 | # To open the url 33 | url_launcher: 5.4.2 34 | 35 | # Used for dependency injection 36 | get_it: 4.0.1 37 | 38 | #Creates an automated routing class 39 | auto_route: 0.3.1 40 | toast: ^0.1.5 41 | 42 | # flutter_platform_widgets will display the widget for both platform seperately 43 | flutter_platform_widgets: 0.32.4 44 | equatable: 1.1.1 45 | wave: ^0.0.8 46 | 47 | # The following adds the Cupertino Icons font to your application. 48 | # Use with the CupertinoIcons class for iOS style icons. 49 | cupertino_icons: ^0.1.3 50 | 51 | # The following adds the shared pref as a dependency in your application 52 | shared_preferences: ^0.5.6+3 53 | 54 | # A composable, Future-based library for making HTTP requests. 55 | http: ^0.12.0+2 56 | 57 | # The following adds the launcher icon support to your application. 58 | # run below mentioned commands to generate launcher icons 59 | # flutter packages get 60 | # flutter packages pub run flutter_launcher_icons:main 61 | flutter_launcher_icons: ^0.7.4 62 | 63 | #a powerful logging framework 64 | logger: ^0.8.3 65 | 66 | # String validation and sanitization for Dart. Dart 2-compatible version of validator 67 | validators: ^2.0.0+1 68 | 69 | # A powerful Http client for Dart 70 | dio: 3.0.8 71 | 72 | # A flexible widget for user notification. 73 | flushbar: ^1.9.1 74 | 75 | # Material Dialog 76 | material_dialog: ^0.0.9 77 | 78 | 79 | 80 | dev_dependencies: 81 | flutter_test: 82 | sdk: flutter 83 | auto_route_generator: 0.3.2 84 | json_serializable: ^3.2.3 85 | retrofit_generator: ^1.0.1 86 | # of course build_runner is needed to run the generator 87 | build_runner: 88 | 89 | 90 | # For information on the generic Dart part of this file, see the 91 | # following page: https://dart.dev/tools/pub/pubspec 92 | 93 | # The following section is specific to Flutter. 94 | flutter: 95 | 96 | # The following line ensures that the Material Icons font is 97 | # included with your application, so that you can use the icons in 98 | # the material Icons class. 99 | uses-material-design: true 100 | 101 | # To add assets to your application, add an assets section, like this: 102 | assets: 103 | - assets/images/logo.png 104 | - assets/images/powered_by.png 105 | # An image asset can refer to one or more resolution-specific "variants", see 106 | # https://flutter.dev/assets-and-images/#resolution-aware. 107 | 108 | # For details regarding adding assets from package dependencies, see 109 | # https://flutter.dev/assets-and-images/#from-packages 110 | 111 | # To add custom fonts to your application, add a fonts section here, 112 | # in this "flutter" section. Each entry in this list should have a 113 | # "family" key with the font family name, and a "fonts" key with a 114 | # list giving the asset and other descriptors for the font. For 115 | # example: 116 | fonts: 117 | - family: OpenSans-Bold 118 | fonts: 119 | - asset: assets/fonts/OpenSans-Bold.ttf 120 | 121 | - family: OpenSans-Light 122 | fonts: 123 | - asset: assets/fonts/OpenSans-Light.ttf 124 | 125 | - family: OpenSans-Regular 126 | fonts: 127 | - asset: assets/fonts/OpenSans-Regular.ttf 128 | 129 | - family: OpenSans-Semibold 130 | fonts: 131 | - asset: assets/fonts/OpenSans-Semibold.ttf 132 | 133 | - family: Muli-Bold 134 | fonts: 135 | - asset: assets/fonts/Muli-Bold.ttf 136 | 137 | # For details regarding fonts from package dependencies, 138 | # see https://flutter.dev/custom-fonts/#from-packages -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_bloc_architecture/src/my_app.dart'; 10 | import 'package:flutter_test/flutter_test.dart'; 11 | 12 | import 'package:flutter_bloc_architecture/main.dart'; 13 | 14 | void main() { 15 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 16 | // Build our app and trigger a frame. 17 | await tester.pumpWidget(MyApp()); 18 | 19 | // Verify that our counter starts at 0. 20 | expect(find.text('0'), findsOneWidget); 21 | expect(find.text('1'), findsNothing); 22 | 23 | // Tap the '+' icon and trigger a frame. 24 | await tester.tap(find.byIcon(Icons.add)); 25 | await tester.pump(); 26 | 27 | // Verify that our counter has incremented. 28 | expect(find.text('0'), findsNothing); 29 | expect(find.text('1'), findsOneWidget); 30 | }); 31 | } 32 | --------------------------------------------------------------------------------