├── .gitignore
├── .metadata
├── .run
├── Color Helper.run.xml
└── Theme Switcher.run.xml
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── flutter_tutorials
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-v21
│ │ │ └── launch_background.xml
│ │ │ ├── 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-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
└── images
│ └── avatar.png
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── 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
├── animated-cross-fade
│ ├── pages
│ │ └── animated_cross_fade_example.dart
│ └── widgets
│ │ ├── avatar_image.dart
│ │ └── cover_image.dart
├── avatar-uploader-tutorial
│ ├── data
│ │ ├── services
│ │ │ ├── media
│ │ │ │ ├── media_service.dart
│ │ │ │ └── media_service_interface.dart
│ │ │ ├── permission
│ │ │ │ ├── permission_handler_permission_service.dart
│ │ │ │ └── permission_service.dart
│ │ │ └── service_locator.dart
│ │ └── utils.dart
│ └── ui
│ │ ├── file_upload_service_home_page.dart
│ │ └── widgets
│ │ ├── avatar_container.dart
│ │ ├── avatar_uploader.dart
│ │ └── image_picker_action_sheet.dart
├── common
│ └── ui
│ │ └── widgets
│ │ ├── app_alert_dialog.dart
│ │ └── bordered_container.dart
├── data
│ ├── app_data.dart
│ └── models
│ │ ├── scroll_physics_data.dart
│ │ └── tutorial.dart
├── main.dart
├── mains
│ ├── main_color_helper.dart
│ └── main_theme_switcher.dart
├── refresh-indicator-thread
│ └── refresh_indicator_thread_home.dart
├── reorderable-list-view
│ └── pages
│ │ └── reorderable_list_view_page.dart
├── scroll-physics-thread
│ ├── always_scrollable_scroll_physics_example.dart
│ ├── bouncing_scroll_physics_example.dart
│ ├── clamping_scroll_physics_example.dart
│ ├── fixed_extent_scroll_physics_example.dart
│ ├── never_scrollable_scroll_physics_example.dart
│ └── scroll_physics_thread_home.dart
└── ui
│ ├── home
│ ├── pages
│ │ └── home_page.dart
│ └── widgets
│ │ ├── list_item.dart
│ │ └── tutorial_list_item.dart
│ └── ui-helper
│ └── navigation_helper.dart
├── 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 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Android Studio will place build artifacts here
44 | /android/app/debug
45 | /android/app/profile
46 | /android/app/release
47 |
48 | pubspec.lock
--------------------------------------------------------------------------------
/.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: 18116933e77adc82f80866c928266a5b4f1ed645
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/.run/Color Helper.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.run/Theme Switcher.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter Tutorials
2 |
3 | This application contains source code of [tutorials I publish on Medium](https://medium.com/@roaa_k) as well as threads [I share on Twitter](https://twitter.com/roaakdm). Updated frequently with more tutorials as they're published.
4 |
5 | ## Tutorials List
6 |
7 | 1. [Flutter Image Uploader With App Permissions and Compression Using GetIt Services](https://medium.com/@roaa_k/flutter-image-uploader-with-app-permissions-and-compression-using-getit-services-59ffea13f913)
8 |
9 | Allow image upload in your Flutter app with one line of code in your widget while handling everything from camera &
10 | gallery permissions to image compression under the hood with GetIt and the service locator pattern.
11 |
12 | 2. [ToDo List With RefreshIndicator](https://twitter.com/roaakdm/status/1472181621759655939)
13 |
14 | Fetch a ToDo list from jsonplaceholder and use RefreshIndicator widget to refetch data
15 |
16 | 3. [ScrollPhysics Types With Examples](https://twitter.com/roaakdm/status/1473375063600779272)
17 |
18 | See all types of ScrollPhysics with example usages and code
19 |
20 | 4. [ReorderableListView Widget](https://twitter.com/roaakdm/status/1475957270064283652)
21 |
22 | Easily allow your users to reorder a list using the ReorderableListView widget
23 |
24 | 4. [AnimatedCrossFade Widget](https://twitter.com/roaakdm/status/1486306936274440192)
25 |
26 | Use the AnimatedCrossFade widget to apply smooth fade animation when switching between two widgets for a better user experience, instead of abruptly doing so
27 |
28 |
29 |
30 | https://user-images.githubusercontent.com/50345358/151159630-cfbaae2f-41d0-4577-a2fa-d380a69c3c12.mp4
31 |
32 |
33 | ## Minimum Requirements
34 | Dart Version 2.15
35 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | linter:
13 | # The lint rules applied to this project can be customized in the
14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 | # included above or to enable additional rules. A list of all available lints
16 | # and their documentation is published at
17 | # https://dart-lang.github.io/linter/lints/index.html.
18 | #
19 | # Instead of disabling a lint rule for the entire project in the
20 | # section below, it can also be suppressed for a single line of code
21 | # or a specific dart file by using the `// ignore: name_of_lint` and
22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 | # producing the lint.
24 | rules:
25 | avoid_print: false # Uncomment to disable the `avoid_print` rule
26 | prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 | avoid_function_literals_in_foreach_calls: false
28 | use_key_in_widget_constructors: false
29 |
30 | # Additional information about this file can be found at
31 | # https://dart.dev/guides/language/analysis-options
32 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/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 30
30 |
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_1_8
33 | targetCompatibility JavaVersion.VERSION_1_8
34 | }
35 |
36 | kotlinOptions {
37 | jvmTarget = '1.8'
38 | }
39 |
40 | sourceSets {
41 | main.java.srcDirs += 'src/main/kotlin'
42 | }
43 |
44 | defaultConfig {
45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
46 | applicationId "com.example.flutter_tutorials"
47 | minSdkVersion 16
48 | targetSdkVersion 30
49 | versionCode flutterVersionCode.toInteger()
50 | versionName flutterVersionName
51 | }
52 |
53 | buildTypes {
54 | release {
55 | // TODO: Add your own signing config for the release build.
56 | // Signing with the debug keys for now, so `flutter run --release` works.
57 | signingConfig signingConfigs.debug
58 | }
59 | }
60 | }
61 |
62 | flutter {
63 | source '../..'
64 | }
65 |
66 | dependencies {
67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
68 | }
69 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
13 |
17 |
21 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/flutter_tutorials/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.flutter_tutorials
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/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 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.1.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/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-6.7-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/assets/images/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/assets/images/avatar.png
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
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 | 9.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 flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | target.build_configurations.each do |config|
41 | config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
42 | '$(inherited)',
43 |
44 | ## dart: PermissionGroup.calendar
45 | # 'PERMISSION_EVENTS=0',
46 |
47 | ## dart: PermissionGroup.reminders
48 | # 'PERMISSION_REMINDERS=0',
49 |
50 | ## dart: PermissionGroup.contacts
51 | # 'PERMISSION_CONTACTS=0',
52 |
53 | ## dart: PermissionGroup.camera
54 | 'PERMISSION_CAMERA=1',
55 |
56 | ## dart: PermissionGroup.microphone
57 | # 'PERMISSION_MICROPHONE=1',
58 |
59 | ## dart: PermissionGroup.speech
60 | # 'PERMISSION_SPEECH_RECOGNIZER=0',
61 |
62 | ## dart: PermissionGroup.photos
63 | 'PERMISSION_PHOTOS=1',
64 |
65 | ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
66 | # 'PERMISSION_LOCATION=0',
67 |
68 | ## dart: PermissionGroup.notification
69 | # 'PERMISSION_NOTIFICATIONS=0',
70 |
71 | ## dart: PermissionGroup.mediaLibrary
72 | 'PERMISSION_MEDIA_LIBRARY=1',
73 |
74 | ## dart: PermissionGroup.sensors
75 | # 'PERMISSION_SENSORS=0'
76 |
77 | # 'AUDIO_SESSION_MICROPHONE=0',
78 | ]
79 | end
80 | end
81 | end
82 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Flutter (1.0.0)
3 | - flutter_image_compress (0.0.1):
4 | - Flutter
5 | - Mantle
6 | - SDWebImage
7 | - SDWebImageWebPCoder
8 | - image_picker (0.0.1):
9 | - Flutter
10 | - libwebp (1.2.1):
11 | - libwebp/demux (= 1.2.1)
12 | - libwebp/mux (= 1.2.1)
13 | - libwebp/webp (= 1.2.1)
14 | - libwebp/demux (1.2.1):
15 | - libwebp/webp
16 | - libwebp/mux (1.2.1):
17 | - libwebp/demux
18 | - libwebp/webp (1.2.1)
19 | - Mantle (2.1.6):
20 | - Mantle/extobjc (= 2.1.6)
21 | - Mantle/extobjc (2.1.6)
22 | - path_provider_ios (0.0.1):
23 | - Flutter
24 | - "permission_handler (5.1.0+2)":
25 | - Flutter
26 | - SDWebImage (5.12.1):
27 | - SDWebImage/Core (= 5.12.1)
28 | - SDWebImage/Core (5.12.1)
29 | - SDWebImageWebPCoder (0.8.4):
30 | - libwebp (~> 1.0)
31 | - SDWebImage/Core (~> 5.10)
32 |
33 | DEPENDENCIES:
34 | - Flutter (from `Flutter`)
35 | - flutter_image_compress (from `.symlinks/plugins/flutter_image_compress/ios`)
36 | - image_picker (from `.symlinks/plugins/image_picker/ios`)
37 | - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
38 | - permission_handler (from `.symlinks/plugins/permission_handler/ios`)
39 |
40 | SPEC REPOS:
41 | trunk:
42 | - libwebp
43 | - Mantle
44 | - SDWebImage
45 | - SDWebImageWebPCoder
46 |
47 | EXTERNAL SOURCES:
48 | Flutter:
49 | :path: Flutter
50 | flutter_image_compress:
51 | :path: ".symlinks/plugins/flutter_image_compress/ios"
52 | image_picker:
53 | :path: ".symlinks/plugins/image_picker/ios"
54 | path_provider_ios:
55 | :path: ".symlinks/plugins/path_provider_ios/ios"
56 | permission_handler:
57 | :path: ".symlinks/plugins/permission_handler/ios"
58 |
59 | SPEC CHECKSUMS:
60 | Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
61 | flutter_image_compress: fd2b476345226e1a10ea352fa306af95704642c1
62 | image_picker: 9aa50e1d8cdacdbed739e925b7eea16d014367e6
63 | libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc
64 | Mantle: 4c0ed6ce47c96eccc4dc3bb071deb3def0e2c3be
65 | path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
66 | permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0
67 | SDWebImage: 4dc3e42d9ec0c1028b960a33ac6b637bb432207b
68 | SDWebImageWebPCoder: f93010f3f6c031e2f8fb3081ca4ee6966c539815
69 |
70 | PODFILE CHECKSUM: dbd6872e034c796d9958efebce52e444008215ed
71 |
72 | COCOAPODS: 1.11.2
73 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 51;
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 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
16 | CF37247928B03CD8E4AB59F1 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB5C116EBC9528CB1A185402 /* Pods_Runner.framework */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXCopyFilesBuildPhase section */
20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
21 | isa = PBXCopyFilesBuildPhase;
22 | buildActionMask = 2147483647;
23 | dstPath = "";
24 | dstSubfolderSpec = 10;
25 | files = (
26 | );
27 | name = "Embed Frameworks";
28 | runOnlyForDeploymentPostprocessing = 0;
29 | };
30 | /* End PBXCopyFilesBuildPhase section */
31 |
32 | /* Begin PBXFileReference section */
33 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
34 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
35 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
36 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
37 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
38 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
39 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
40 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
41 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
42 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
43 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
44 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
45 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
46 | 97EAA63A2A5070653279E994 /* 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 = ""; };
47 | DB5C116EBC9528CB1A185402 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
48 | F64255C655D7D9AAD9F02892 /* 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 = ""; };
49 | FDF203C3A55C69D9678CB2CD /* 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 = ""; };
50 | /* End PBXFileReference section */
51 |
52 | /* Begin PBXFrameworksBuildPhase section */
53 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
54 | isa = PBXFrameworksBuildPhase;
55 | buildActionMask = 2147483647;
56 | files = (
57 | CF37247928B03CD8E4AB59F1 /* Pods_Runner.framework in Frameworks */,
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | /* End PBXFrameworksBuildPhase section */
62 |
63 | /* Begin PBXGroup section */
64 | 21209F2822F69352173258E1 /* Frameworks */ = {
65 | isa = PBXGroup;
66 | children = (
67 | DB5C116EBC9528CB1A185402 /* Pods_Runner.framework */,
68 | );
69 | name = Frameworks;
70 | sourceTree = "";
71 | };
72 | 4359DDA015A41EE8BA122A3F /* Pods */ = {
73 | isa = PBXGroup;
74 | children = (
75 | 97EAA63A2A5070653279E994 /* Pods-Runner.debug.xcconfig */,
76 | F64255C655D7D9AAD9F02892 /* Pods-Runner.release.xcconfig */,
77 | FDF203C3A55C69D9678CB2CD /* Pods-Runner.profile.xcconfig */,
78 | );
79 | path = Pods;
80 | sourceTree = "";
81 | };
82 | 9740EEB11CF90186004384FC /* Flutter */ = {
83 | isa = PBXGroup;
84 | children = (
85 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
86 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
87 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
88 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
89 | );
90 | name = Flutter;
91 | sourceTree = "";
92 | };
93 | 97C146E51CF9000F007C117D = {
94 | isa = PBXGroup;
95 | children = (
96 | 9740EEB11CF90186004384FC /* Flutter */,
97 | 97C146F01CF9000F007C117D /* Runner */,
98 | 97C146EF1CF9000F007C117D /* Products */,
99 | 4359DDA015A41EE8BA122A3F /* Pods */,
100 | 21209F2822F69352173258E1 /* Frameworks */,
101 | );
102 | sourceTree = "";
103 | };
104 | 97C146EF1CF9000F007C117D /* Products */ = {
105 | isa = PBXGroup;
106 | children = (
107 | 97C146EE1CF9000F007C117D /* Runner.app */,
108 | );
109 | name = Products;
110 | sourceTree = "";
111 | };
112 | 97C146F01CF9000F007C117D /* Runner */ = {
113 | isa = PBXGroup;
114 | children = (
115 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
116 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
117 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
118 | 97C147021CF9000F007C117D /* Info.plist */,
119 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
120 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
121 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
122 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
123 | );
124 | path = Runner;
125 | sourceTree = "";
126 | };
127 | /* End PBXGroup section */
128 |
129 | /* Begin PBXNativeTarget section */
130 | 97C146ED1CF9000F007C117D /* Runner */ = {
131 | isa = PBXNativeTarget;
132 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
133 | buildPhases = (
134 | 3CF3494BE76857C8DA391D73 /* [CP] Check Pods Manifest.lock */,
135 | 9740EEB61CF901F6004384FC /* Run Script */,
136 | 97C146EA1CF9000F007C117D /* Sources */,
137 | 97C146EB1CF9000F007C117D /* Frameworks */,
138 | 97C146EC1CF9000F007C117D /* Resources */,
139 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
140 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
141 | 61E009B73D797D502629BCBE /* [CP] Embed Pods Frameworks */,
142 | );
143 | buildRules = (
144 | );
145 | dependencies = (
146 | );
147 | name = Runner;
148 | productName = Runner;
149 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
150 | productType = "com.apple.product-type.application";
151 | };
152 | /* End PBXNativeTarget section */
153 |
154 | /* Begin PBXProject section */
155 | 97C146E61CF9000F007C117D /* Project object */ = {
156 | isa = PBXProject;
157 | attributes = {
158 | LastUpgradeCheck = 1300;
159 | ORGANIZATIONNAME = "";
160 | TargetAttributes = {
161 | 97C146ED1CF9000F007C117D = {
162 | CreatedOnToolsVersion = 7.3.1;
163 | LastSwiftMigration = 1100;
164 | };
165 | };
166 | };
167 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
168 | compatibilityVersion = "Xcode 9.3";
169 | developmentRegion = en;
170 | hasScannedForEncodings = 0;
171 | knownRegions = (
172 | en,
173 | Base,
174 | );
175 | mainGroup = 97C146E51CF9000F007C117D;
176 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
177 | projectDirPath = "";
178 | projectRoot = "";
179 | targets = (
180 | 97C146ED1CF9000F007C117D /* Runner */,
181 | );
182 | };
183 | /* End PBXProject section */
184 |
185 | /* Begin PBXResourcesBuildPhase section */
186 | 97C146EC1CF9000F007C117D /* Resources */ = {
187 | isa = PBXResourcesBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
191 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
192 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
193 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
194 | );
195 | runOnlyForDeploymentPostprocessing = 0;
196 | };
197 | /* End PBXResourcesBuildPhase section */
198 |
199 | /* Begin PBXShellScriptBuildPhase section */
200 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
201 | isa = PBXShellScriptBuildPhase;
202 | buildActionMask = 2147483647;
203 | files = (
204 | );
205 | inputPaths = (
206 | );
207 | name = "Thin Binary";
208 | outputPaths = (
209 | );
210 | runOnlyForDeploymentPostprocessing = 0;
211 | shellPath = /bin/sh;
212 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
213 | };
214 | 3CF3494BE76857C8DA391D73 /* [CP] Check Pods Manifest.lock */ = {
215 | isa = PBXShellScriptBuildPhase;
216 | buildActionMask = 2147483647;
217 | files = (
218 | );
219 | inputFileListPaths = (
220 | );
221 | inputPaths = (
222 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
223 | "${PODS_ROOT}/Manifest.lock",
224 | );
225 | name = "[CP] Check Pods Manifest.lock";
226 | outputFileListPaths = (
227 | );
228 | outputPaths = (
229 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
230 | );
231 | runOnlyForDeploymentPostprocessing = 0;
232 | shellPath = /bin/sh;
233 | 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";
234 | showEnvVarsInLog = 0;
235 | };
236 | 61E009B73D797D502629BCBE /* [CP] Embed Pods Frameworks */ = {
237 | isa = PBXShellScriptBuildPhase;
238 | buildActionMask = 2147483647;
239 | files = (
240 | );
241 | inputFileListPaths = (
242 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
243 | );
244 | name = "[CP] Embed Pods Frameworks";
245 | outputFileListPaths = (
246 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
247 | );
248 | runOnlyForDeploymentPostprocessing = 0;
249 | shellPath = /bin/sh;
250 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
251 | showEnvVarsInLog = 0;
252 | };
253 | 9740EEB61CF901F6004384FC /* Run Script */ = {
254 | isa = PBXShellScriptBuildPhase;
255 | buildActionMask = 2147483647;
256 | files = (
257 | );
258 | inputPaths = (
259 | );
260 | name = "Run Script";
261 | outputPaths = (
262 | );
263 | runOnlyForDeploymentPostprocessing = 0;
264 | shellPath = /bin/sh;
265 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
266 | };
267 | /* End PBXShellScriptBuildPhase section */
268 |
269 | /* Begin PBXSourcesBuildPhase section */
270 | 97C146EA1CF9000F007C117D /* Sources */ = {
271 | isa = PBXSourcesBuildPhase;
272 | buildActionMask = 2147483647;
273 | files = (
274 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
275 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
276 | );
277 | runOnlyForDeploymentPostprocessing = 0;
278 | };
279 | /* End PBXSourcesBuildPhase section */
280 |
281 | /* Begin PBXVariantGroup section */
282 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
283 | isa = PBXVariantGroup;
284 | children = (
285 | 97C146FB1CF9000F007C117D /* Base */,
286 | );
287 | name = Main.storyboard;
288 | sourceTree = "";
289 | };
290 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
291 | isa = PBXVariantGroup;
292 | children = (
293 | 97C147001CF9000F007C117D /* Base */,
294 | );
295 | name = LaunchScreen.storyboard;
296 | sourceTree = "";
297 | };
298 | /* End PBXVariantGroup section */
299 |
300 | /* Begin XCBuildConfiguration section */
301 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
302 | isa = XCBuildConfiguration;
303 | buildSettings = {
304 | ALWAYS_SEARCH_USER_PATHS = NO;
305 | CLANG_ANALYZER_NONNULL = YES;
306 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
307 | CLANG_CXX_LIBRARY = "libc++";
308 | CLANG_ENABLE_MODULES = YES;
309 | CLANG_ENABLE_OBJC_ARC = YES;
310 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
311 | CLANG_WARN_BOOL_CONVERSION = YES;
312 | CLANG_WARN_COMMA = YES;
313 | CLANG_WARN_CONSTANT_CONVERSION = YES;
314 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
315 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
316 | CLANG_WARN_EMPTY_BODY = YES;
317 | CLANG_WARN_ENUM_CONVERSION = YES;
318 | CLANG_WARN_INFINITE_RECURSION = YES;
319 | CLANG_WARN_INT_CONVERSION = YES;
320 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
321 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
322 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
324 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
325 | CLANG_WARN_STRICT_PROTOTYPES = YES;
326 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
327 | CLANG_WARN_UNREACHABLE_CODE = YES;
328 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
329 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
330 | COPY_PHASE_STRIP = NO;
331 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
332 | ENABLE_NS_ASSERTIONS = NO;
333 | ENABLE_STRICT_OBJC_MSGSEND = YES;
334 | GCC_C_LANGUAGE_STANDARD = gnu99;
335 | GCC_NO_COMMON_BLOCKS = YES;
336 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
337 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
338 | GCC_WARN_UNDECLARED_SELECTOR = YES;
339 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
340 | GCC_WARN_UNUSED_FUNCTION = YES;
341 | GCC_WARN_UNUSED_VARIABLE = YES;
342 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
343 | MTL_ENABLE_DEBUG_INFO = NO;
344 | SDKROOT = iphoneos;
345 | SUPPORTED_PLATFORMS = iphoneos;
346 | TARGETED_DEVICE_FAMILY = "1,2";
347 | VALIDATE_PRODUCT = YES;
348 | };
349 | name = Profile;
350 | };
351 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
352 | isa = XCBuildConfiguration;
353 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
354 | buildSettings = {
355 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
356 | CLANG_ENABLE_MODULES = YES;
357 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
358 | DEVELOPMENT_TEAM = X9FZA29898;
359 | ENABLE_BITCODE = NO;
360 | INFOPLIST_FILE = Runner/Info.plist;
361 | LD_RUNPATH_SEARCH_PATHS = (
362 | "$(inherited)",
363 | "@executable_path/Frameworks",
364 | );
365 | PRODUCT_BUNDLE_IDENTIFIER = com.multicaret.flutter.tutorials;
366 | PRODUCT_NAME = "$(TARGET_NAME)";
367 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
368 | SWIFT_VERSION = 5.0;
369 | VERSIONING_SYSTEM = "apple-generic";
370 | };
371 | name = Profile;
372 | };
373 | 97C147031CF9000F007C117D /* Debug */ = {
374 | isa = XCBuildConfiguration;
375 | buildSettings = {
376 | ALWAYS_SEARCH_USER_PATHS = NO;
377 | CLANG_ANALYZER_NONNULL = YES;
378 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
379 | CLANG_CXX_LIBRARY = "libc++";
380 | CLANG_ENABLE_MODULES = YES;
381 | CLANG_ENABLE_OBJC_ARC = YES;
382 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
383 | CLANG_WARN_BOOL_CONVERSION = YES;
384 | CLANG_WARN_COMMA = YES;
385 | CLANG_WARN_CONSTANT_CONVERSION = YES;
386 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
387 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
388 | CLANG_WARN_EMPTY_BODY = YES;
389 | CLANG_WARN_ENUM_CONVERSION = YES;
390 | CLANG_WARN_INFINITE_RECURSION = YES;
391 | CLANG_WARN_INT_CONVERSION = YES;
392 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
393 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
394 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
395 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
396 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
397 | CLANG_WARN_STRICT_PROTOTYPES = YES;
398 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
399 | CLANG_WARN_UNREACHABLE_CODE = YES;
400 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
401 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
402 | COPY_PHASE_STRIP = NO;
403 | DEBUG_INFORMATION_FORMAT = dwarf;
404 | ENABLE_STRICT_OBJC_MSGSEND = YES;
405 | ENABLE_TESTABILITY = YES;
406 | GCC_C_LANGUAGE_STANDARD = gnu99;
407 | GCC_DYNAMIC_NO_PIC = NO;
408 | GCC_NO_COMMON_BLOCKS = YES;
409 | GCC_OPTIMIZATION_LEVEL = 0;
410 | GCC_PREPROCESSOR_DEFINITIONS = (
411 | "DEBUG=1",
412 | "$(inherited)",
413 | );
414 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
415 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
416 | GCC_WARN_UNDECLARED_SELECTOR = YES;
417 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
418 | GCC_WARN_UNUSED_FUNCTION = YES;
419 | GCC_WARN_UNUSED_VARIABLE = YES;
420 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
421 | MTL_ENABLE_DEBUG_INFO = YES;
422 | ONLY_ACTIVE_ARCH = YES;
423 | SDKROOT = iphoneos;
424 | TARGETED_DEVICE_FAMILY = "1,2";
425 | };
426 | name = Debug;
427 | };
428 | 97C147041CF9000F007C117D /* Release */ = {
429 | isa = XCBuildConfiguration;
430 | buildSettings = {
431 | ALWAYS_SEARCH_USER_PATHS = NO;
432 | CLANG_ANALYZER_NONNULL = YES;
433 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
434 | CLANG_CXX_LIBRARY = "libc++";
435 | CLANG_ENABLE_MODULES = YES;
436 | CLANG_ENABLE_OBJC_ARC = YES;
437 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
438 | CLANG_WARN_BOOL_CONVERSION = YES;
439 | CLANG_WARN_COMMA = YES;
440 | CLANG_WARN_CONSTANT_CONVERSION = YES;
441 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
442 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
443 | CLANG_WARN_EMPTY_BODY = YES;
444 | CLANG_WARN_ENUM_CONVERSION = YES;
445 | CLANG_WARN_INFINITE_RECURSION = YES;
446 | CLANG_WARN_INT_CONVERSION = YES;
447 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
448 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
449 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
450 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
451 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
452 | CLANG_WARN_STRICT_PROTOTYPES = YES;
453 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
454 | CLANG_WARN_UNREACHABLE_CODE = YES;
455 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
456 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
457 | COPY_PHASE_STRIP = NO;
458 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
459 | ENABLE_NS_ASSERTIONS = NO;
460 | ENABLE_STRICT_OBJC_MSGSEND = YES;
461 | GCC_C_LANGUAGE_STANDARD = gnu99;
462 | GCC_NO_COMMON_BLOCKS = YES;
463 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
464 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
465 | GCC_WARN_UNDECLARED_SELECTOR = YES;
466 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
467 | GCC_WARN_UNUSED_FUNCTION = YES;
468 | GCC_WARN_UNUSED_VARIABLE = YES;
469 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
470 | MTL_ENABLE_DEBUG_INFO = NO;
471 | SDKROOT = iphoneos;
472 | SUPPORTED_PLATFORMS = iphoneos;
473 | SWIFT_COMPILATION_MODE = wholemodule;
474 | SWIFT_OPTIMIZATION_LEVEL = "-O";
475 | TARGETED_DEVICE_FAMILY = "1,2";
476 | VALIDATE_PRODUCT = YES;
477 | };
478 | name = Release;
479 | };
480 | 97C147061CF9000F007C117D /* Debug */ = {
481 | isa = XCBuildConfiguration;
482 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
483 | buildSettings = {
484 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
485 | CLANG_ENABLE_MODULES = YES;
486 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
487 | DEVELOPMENT_TEAM = X9FZA29898;
488 | ENABLE_BITCODE = NO;
489 | INFOPLIST_FILE = Runner/Info.plist;
490 | LD_RUNPATH_SEARCH_PATHS = (
491 | "$(inherited)",
492 | "@executable_path/Frameworks",
493 | );
494 | PRODUCT_BUNDLE_IDENTIFIER = com.multicaret.flutter.tutorials;
495 | PRODUCT_NAME = "$(TARGET_NAME)";
496 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
497 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
498 | SWIFT_VERSION = 5.0;
499 | VERSIONING_SYSTEM = "apple-generic";
500 | };
501 | name = Debug;
502 | };
503 | 97C147071CF9000F007C117D /* Release */ = {
504 | isa = XCBuildConfiguration;
505 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
506 | buildSettings = {
507 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
508 | CLANG_ENABLE_MODULES = YES;
509 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
510 | DEVELOPMENT_TEAM = X9FZA29898;
511 | ENABLE_BITCODE = NO;
512 | INFOPLIST_FILE = Runner/Info.plist;
513 | LD_RUNPATH_SEARCH_PATHS = (
514 | "$(inherited)",
515 | "@executable_path/Frameworks",
516 | );
517 | PRODUCT_BUNDLE_IDENTIFIER = com.multicaret.flutter.tutorials;
518 | PRODUCT_NAME = "$(TARGET_NAME)";
519 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
520 | SWIFT_VERSION = 5.0;
521 | VERSIONING_SYSTEM = "apple-generic";
522 | };
523 | name = Release;
524 | };
525 | /* End XCBuildConfiguration section */
526 |
527 | /* Begin XCConfigurationList section */
528 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
529 | isa = XCConfigurationList;
530 | buildConfigurations = (
531 | 97C147031CF9000F007C117D /* Debug */,
532 | 97C147041CF9000F007C117D /* Release */,
533 | 249021D3217E4FDB00AE95B9 /* Profile */,
534 | );
535 | defaultConfigurationIsVisible = 0;
536 | defaultConfigurationName = Release;
537 | };
538 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
539 | isa = XCConfigurationList;
540 | buildConfigurations = (
541 | 97C147061CF9000F007C117D /* Debug */,
542 | 97C147071CF9000F007C117D /* Release */,
543 | 249021D4217E4FDB00AE95B9 /* Profile */,
544 | );
545 | defaultConfigurationIsVisible = 0;
546 | defaultConfigurationName = Release;
547 | };
548 | /* End XCConfigurationList section */
549 | };
550 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
551 | }
552 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
69 |
71 |
77 |
78 |
79 |
80 |
82 |
83 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Roaa94/flutter-tutorials/616230fe440587aa83228b9422f22a784c6a6fb1/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 Tutorials
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 | NSCameraUsageDescription
46 | You need to allow camera permission to use this feature
47 |
48 | NSPhotoLibraryUsageDescription
49 | You need to allow photos permission to use this feature
50 |
51 |
52 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/lib/animated-cross-fade/pages/animated_cross_fade_example.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/animated-cross-fade/widgets/avatar_image.dart';
3 | import 'package:flutter_tutorials/animated-cross-fade/widgets/cover_image.dart';
4 |
5 | class AnimatedCrossFadeExample extends StatefulWidget {
6 | static const routeName = 'animated-cross-fade-example';
7 |
8 | @override
9 | State createState() => _AnimatedCrossFadeExampleState();
10 | }
11 |
12 | class _AnimatedCrossFadeExampleState extends State {
13 | final ValueNotifier avatarIsSelectedNotifier = ValueNotifier(true);
14 |
15 | final List buttons = [
16 | 'Profile Picture',
17 | 'Cover',
18 | ];
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return Scaffold(
23 | appBar: AppBar(
24 | backgroundColor: Colors.white,
25 | iconTheme: const IconThemeData(color: Colors.black),
26 | elevation: 0,
27 | title: const Text(
28 | 'Profile',
29 | style: TextStyle(
30 | color: Colors.black,
31 | fontSize: 18,
32 | ),
33 | ),
34 | ),
35 | body: SingleChildScrollView(
36 | padding: const EdgeInsets.all(17),
37 | child: Column(
38 | crossAxisAlignment: CrossAxisAlignment.start,
39 | children: [
40 | Wrap(
41 | spacing: 10,
42 | children: List.generate(
43 | buttons.length,
44 | (index) => InkWell(
45 | borderRadius: BorderRadius.circular(20),
46 | onTap: () => avatarIsSelectedNotifier.value = index == 0,
47 | child: Container(
48 | padding: const EdgeInsets.all(12),
49 | decoration: BoxDecoration(
50 | color: Colors.grey.withOpacity(0.3),
51 | borderRadius: BorderRadius.circular(20),
52 | ),
53 | child: Text(buttons[index]),
54 | ),
55 | ),
56 | ),
57 | ),
58 | const SizedBox(height: 20),
59 | ValueListenableBuilder(
60 | valueListenable: avatarIsSelectedNotifier,
61 | builder: (c, bool avatarIsSelected, _) => AnimatedCrossFade(
62 | firstChild: AvatarImage(),
63 | secondChild: CoverImage(),
64 | sizeCurve: Curves.easeInOut,
65 | crossFadeState: avatarIsSelected ? CrossFadeState.showFirst : CrossFadeState.showSecond,
66 | duration: const Duration(milliseconds: 400),
67 | ),
68 | ),
69 | const SizedBox(height: 20),
70 | Text('Bio', style: TextStyle(color: Colors.grey.withOpacity(0.7))),
71 | const SizedBox(height: 10),
72 | Column(
73 | children: List.generate(
74 | 10,
75 | (index) => Container(
76 | height: 15,
77 | margin: const EdgeInsets.only(bottom: 5),
78 | decoration: BoxDecoration(
79 | color: Colors.grey.withOpacity(0.3),
80 | borderRadius: BorderRadius.circular(5),
81 | ),
82 | ),
83 | ),
84 | )
85 | ],
86 | ),
87 | ),
88 | );
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/lib/animated-cross-fade/widgets/avatar_image.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AvatarImage extends StatelessWidget {
4 | @override
5 | Widget build(BuildContext context) {
6 | return Container(
7 | decoration: BoxDecoration(
8 | borderRadius: BorderRadius.circular(15),
9 | border: Border.all(color: Colors.grey, width: 2),
10 | ),
11 | child: ClipRRect(
12 | borderRadius: BorderRadius.circular(15),
13 | child: Image.asset(
14 | 'assets/images/avatar.png',
15 | fit: BoxFit.cover,
16 | height: 400,
17 | width: double.infinity,
18 | alignment: Alignment.topCenter,
19 | ),
20 | ),
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/animated-cross-fade/widgets/cover_image.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class CoverImage extends StatelessWidget {
4 | @override
5 | Widget build(BuildContext context) {
6 | return ClipRRect(
7 | borderRadius: BorderRadius.circular(15),
8 | child: Image.network(
9 | 'https://cdn.pixabay.com/photo/2016/03/26/13/09/workspace-1280538_1280.jpg',
10 | fit: BoxFit.cover,
11 | height: 200,
12 | width: MediaQuery.of(context).size.width,
13 | ),
14 | );
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/avatar-uploader-tutorial/data/services/media/media_service.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 | import 'dart:math';
3 |
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_image_compress/flutter_image_compress.dart';
6 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/media/media_service_interface.dart';
7 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/permission/permission_service.dart';
8 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/service_locator.dart';
9 | import 'package:image_picker/image_picker.dart';
10 | import 'package:path_provider/path_provider.dart' as path_provider;
11 |
12 | class MediaService implements MediaServiceInterface {
13 | @override
14 | PermissionService get permissionService => getIt();
15 |
16 | Future _handleImageUploadPermissions(BuildContext context, AppImageSource? _imageSource) async {
17 | if (_imageSource == null) {
18 | return false;
19 | }
20 | if (_imageSource == AppImageSource.camera) {
21 | return await permissionService.handleCameraPermission(context);
22 | } else if (_imageSource == AppImageSource.gallery) {
23 | return await permissionService.handlePhotosPermission(context);
24 | } else {
25 | return false;
26 | }
27 | }
28 |
29 | @override
30 | Future uploadImage(
31 | BuildContext context,
32 | AppImageSource appImageSource, {
33 | bool shouldCompress = true,
34 | }) async {
35 | // Handle permissions according to image source,
36 | bool canProceed = await _handleImageUploadPermissions(context, appImageSource);
37 |
38 | if (canProceed) {
39 | File? processedPickedImageFile;
40 |
41 | // Convert our own AppImageSource into a format readable by the used package
42 | // In this case it's an ImageSource enum
43 | ImageSource? _imageSource = ImageSource.values.byName(appImageSource.name);
44 |
45 | final imagePicker = ImagePicker();
46 | final rawPickedImageFile = await imagePicker.pickImage(source: _imageSource, imageQuality: 50);
47 |
48 | if (rawPickedImageFile != null) {
49 | //to convert from XFile type provided by the package to dart:io's File type
50 | processedPickedImageFile = File(rawPickedImageFile.path);
51 | if (shouldCompress) {
52 | processedPickedImageFile = await compressFile(processedPickedImageFile);
53 | }
54 | }
55 | return processedPickedImageFile;
56 | }
57 | }
58 |
59 | @override
60 | Future compressFile(File file, {int quality = 30}) async {
61 | final dir = await path_provider.getTemporaryDirectory();
62 | final targetPath = dir.absolute.path + '/${Random().nextInt(1000)}-temp.jpg';
63 |
64 | return await FlutterImageCompress.compressAndGetFile(
65 | file.absolute.path,
66 | targetPath,
67 | quality: quality,
68 | );
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/avatar-uploader-tutorial/data/services/media/media_service_interface.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/cupertino.dart';
4 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/permission/permission_service.dart';
5 |
6 | // Created our own enum to prevent an abstract interface
7 | // from having a dependency on an external package
8 | enum AppImageSource {
9 | camera,
10 | gallery,
11 | }
12 |
13 | abstract class MediaServiceInterface {
14 | PermissionService get permissionService;
15 |
16 | Future uploadImage(
17 | BuildContext context,
18 | AppImageSource appImageSource, {
19 | bool shouldCompress = true,
20 | });
21 |
22 | Future compressFile(File file, {int quality = 30});
23 | }
24 |
--------------------------------------------------------------------------------
/lib/avatar-uploader-tutorial/data/services/permission/permission_handler_permission_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/common/ui/widgets/app_alert_dialog.dart';
3 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/permission/permission_service.dart';
4 | import 'package:permission_handler/permission_handler.dart';
5 |
6 | class PermissionHandlerPermissionService implements PermissionService {
7 | @override
8 | Future requestCameraPermission() async {
9 | return await Permission.camera.request();
10 | }
11 |
12 | @override
13 | Future requestPhotosPermission() async {
14 | return await Permission.photos.request();
15 | }
16 |
17 | @override
18 | Future handleCameraPermission(BuildContext context) async {
19 | PermissionStatus cameraPermissionStatus = await requestCameraPermission();
20 |
21 | if (cameraPermissionStatus != PermissionStatus.granted) {
22 | print('😰 😰 😰 😰 😰 😰 Permission to camera was not granted! 😰 😰 😰 😰 😰 😰');
23 | await showDialog(
24 | context: context,
25 | builder: (_context) => AppAlertDialog(
26 | onConfirm: () => openAppSettings(),
27 | title: 'Camera Permission',
28 | subtitle: 'Camera permission should Be granted to use this feature, would you like to go to app settings to give camera permission?',
29 | ),
30 | );
31 | return false;
32 | }
33 | return true;
34 | }
35 |
36 | @override
37 | Future handlePhotosPermission(BuildContext context) async {
38 | PermissionStatus photosPermissionStatus = await requestPhotosPermission();
39 |
40 | if (photosPermissionStatus != PermissionStatus.granted) {
41 | print('😰 😰 😰 😰 😰 😰 Permission to photos not granted! 😰 😰 😰 😰 😰 😰');
42 | await showDialog(
43 | context: context,
44 | builder: (_context) => AppAlertDialog(
45 | onConfirm: () => openAppSettings(),
46 | title: 'Photos Permission',
47 | subtitle: 'Photos permission should Be granted to use this feature, would you like to go to app settings to give photos permission?',
48 | ),
49 | );
50 | return false;
51 | }
52 | return true;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/avatar-uploader-tutorial/data/services/permission/permission_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | abstract class PermissionService {
4 | Future requestPhotosPermission();
5 |
6 | Future handlePhotosPermission(BuildContext context);
7 |
8 | Future requestCameraPermission();
9 |
10 | Future handleCameraPermission(BuildContext context);
11 | }
12 |
--------------------------------------------------------------------------------
/lib/avatar-uploader-tutorial/data/services/service_locator.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/media/media_service.dart';
2 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/media/media_service_interface.dart';
3 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/permission/permission_handler_permission_service.dart';
4 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/permission/permission_service.dart';
5 | import 'package:get_it/get_it.dart';
6 |
7 | final getIt = GetIt.instance;
8 |
9 | setupServiceLocator() {
10 | // Permission service is used in FileUploaderService
11 | // so it must be located first
12 | getIt.registerSingleton(PermissionHandlerPermissionService());
13 |
14 | getIt.registerSingleton(MediaService());
15 | }
--------------------------------------------------------------------------------
/lib/avatar-uploader-tutorial/data/utils.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | double getMBFileSize(File file) {
4 | return file.lengthSync() / 125000;
5 | }
6 |
--------------------------------------------------------------------------------
/lib/avatar-uploader-tutorial/ui/file_upload_service_home_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/avatar-uploader-tutorial/ui/widgets/avatar_uploader.dart';
3 |
4 | class FileUploadServiceHomePage extends StatelessWidget {
5 | static const String routeName = 'file-upload-service-home-page';
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return Scaffold(
10 | extendBodyBehindAppBar: true,
11 | appBar: AppBar(
12 | title: const Text('Avatar Uploader'),
13 | ),
14 | body: Center(
15 | child: AvatarUploader(),
16 | ),
17 | );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/avatar-uploader-tutorial/ui/widgets/avatar_container.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class AvatarContainer extends StatelessWidget {
6 | final Function onTap;
7 | final File? imageFile;
8 | final bool isLoading;
9 |
10 | const AvatarContainer({
11 | required this.onTap,
12 | required this.imageFile,
13 | required this.isLoading,
14 | });
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return GestureDetector(
19 | onTap: isLoading ? null : () => onTap(),
20 | child: Container(
21 | width: 200,
22 | height: 200,
23 | decoration: BoxDecoration(
24 | shape: BoxShape.circle,
25 | color: Colors.blueGrey.withOpacity(0.5),
26 | border: Border.all(width: 3, color: Colors.teal),
27 | image: imageFile == null
28 | ? null
29 | : DecorationImage(
30 | image: FileImage(imageFile!),
31 | fit: BoxFit.cover,
32 | ),
33 | ),
34 | child: ClipRRect(
35 | borderRadius: BorderRadius.circular(100),
36 | child: Column(
37 | mainAxisAlignment: MainAxisAlignment.end,
38 | children: [
39 | const SizedBox(height: 70),
40 | if (isLoading) const CircularProgressIndicator(),
41 | const SizedBox(height: 30),
42 | Container(
43 | height: 50,
44 | width: 200,
45 | color: Colors.black.withOpacity(0.5),
46 | padding: const EdgeInsets.only(bottom: 12),
47 | child: Center(
48 | child: Text(
49 | imageFile == null ? 'Upload Image' : 'Change Image',
50 | style: const TextStyle(color: Colors.white, fontSize: 16),
51 | ),
52 | ),
53 | ),
54 | ],
55 | ),
56 | ),
57 | ),
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/avatar-uploader-tutorial/ui/widgets/avatar_uploader.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/cupertino.dart';
4 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/media/media_service_interface.dart';
5 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/service_locator.dart';
6 | import 'package:flutter_tutorials/avatar-uploader-tutorial/ui/widgets/avatar_container.dart';
7 | import 'package:flutter_tutorials/avatar-uploader-tutorial/ui/widgets/image_picker_action_sheet.dart';
8 |
9 | class AvatarUploader extends StatefulWidget {
10 | @override
11 | _AvatarUploaderState createState() => _AvatarUploaderState();
12 | }
13 |
14 | class _AvatarUploaderState extends State {
15 | final MediaServiceInterface _mediaService = getIt();
16 |
17 | File? imageFile;
18 | bool _isLoadingGettingImage = false;
19 |
20 | Future _pickImageSource() async {
21 | AppImageSource? _appImageSource = await showCupertinoModalPopup(
22 | context: context,
23 | builder: (BuildContext context) => ImagePickerActionSheet(),
24 | );
25 | if (_appImageSource != null) {
26 | _getImage(_appImageSource);
27 | }
28 | }
29 |
30 | Future _getImage(AppImageSource _appImageSource) async {
31 | setState(() => _isLoadingGettingImage = true);
32 | final _pickedImageFile = await _mediaService.uploadImage(context, _appImageSource);
33 | setState(() => _isLoadingGettingImage = false);
34 |
35 | if (_pickedImageFile != null) {
36 | setState(() => imageFile = _pickedImageFile);
37 | }
38 | }
39 |
40 | @override
41 | Widget build(BuildContext context) {
42 | return AvatarContainer(
43 | isLoading: _isLoadingGettingImage,
44 | onTap: _pickImageSource,
45 | imageFile: imageFile,
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/avatar-uploader-tutorial/ui/widgets/image_picker_action_sheet.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/media/media_service_interface.dart';
3 |
4 | class ImagePickerActionSheet extends StatelessWidget {
5 | @override
6 | Widget build(BuildContext context) {
7 | return CupertinoActionSheet(
8 | actions: [
9 | CupertinoActionSheetAction(
10 | child: const Text('Take Photo'),
11 | onPressed: () => Navigator.of(context).pop(AppImageSource.camera),
12 | ),
13 | CupertinoActionSheetAction(
14 | child: const Text('Upload From Gallery'),
15 | onPressed: () => Navigator.of(context).pop(AppImageSource.gallery),
16 | ),
17 | ],
18 | cancelButton: CupertinoActionSheetAction(
19 | child: const Text('Cancel'),
20 | onPressed: () => Navigator.of(context).pop(),
21 | ),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/common/ui/widgets/app_alert_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AppAlertDialog extends StatelessWidget {
4 | final Function onConfirm;
5 | final String title;
6 | final String subtitle;
7 |
8 | const AppAlertDialog({
9 | required this.onConfirm,
10 | required this.title,
11 | required this.subtitle,
12 | });
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return AlertDialog(
17 | title: Text(title),
18 | content: Text(subtitle),
19 | actions: [
20 | ElevatedButton(
21 | onPressed: () => onConfirm(),
22 | child: const Text('Confirm'),
23 | ),
24 | ElevatedButton(
25 | onPressed: () => Navigator.of(context).pop(),
26 | child: const Text('Cancel'),
27 | ),
28 | ],
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/common/ui/widgets/bordered_container.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class BorderedContainer extends StatelessWidget {
4 | final Widget child;
5 | final Color? color;
6 |
7 | const BorderedContainer({
8 | required this.child,
9 | this.color,
10 | });
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Container(
15 | // width: double.infinity,
16 | padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 20),
17 | decoration: BoxDecoration(
18 | border: Border(bottom: BorderSide(color: Theme.of(context).dividerColor)),
19 | color: color,
20 | ),
21 | child: child,
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/data/app_data.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_tutorials/animated-cross-fade/pages/animated_cross_fade_example.dart';
2 | import 'package:flutter_tutorials/avatar-uploader-tutorial/ui/file_upload_service_home_page.dart';
3 | import 'package:flutter_tutorials/data/models/scroll_physics_data.dart';
4 | import 'package:flutter_tutorials/data/models/tutorial.dart';
5 | import 'package:flutter_tutorials/refresh-indicator-thread/refresh_indicator_thread_home.dart';
6 | import 'package:flutter_tutorials/reorderable-list-view/pages/reorderable_list_view_page.dart';
7 | import 'package:flutter_tutorials/scroll-physics-thread/always_scrollable_scroll_physics_example.dart';
8 | import 'package:flutter_tutorials/scroll-physics-thread/bouncing_scroll_physics_example.dart';
9 | import 'package:flutter_tutorials/scroll-physics-thread/clamping_scroll_physics_example.dart';
10 | import 'package:flutter_tutorials/scroll-physics-thread/fixed_extent_scroll_physics_example.dart';
11 | import 'package:flutter_tutorials/scroll-physics-thread/never_scrollable_scroll_physics_example.dart';
12 | import 'package:flutter_tutorials/scroll-physics-thread/scroll_physics_thread_home.dart';
13 |
14 | class AppData {
15 | static List appTutorials = [
16 | Tutorial(
17 | title: 'Image Uploader With App Permissions and Compression Using GetIt Services',
18 | description:
19 | 'Allow image upload in your Flutter app with one line of code in your widget while handling everything from camera & gallery permissions to image compression under the hood with GetIt and the service locator pattern.',
20 | tutorialPageRoute: FileUploadServiceHomePage.routeName,
21 | tutorialLink: 'https://medium.com/@roaa_k/flutter-image-uploader-with-app-permissions-and-compression-using-getit-services-59ffea13f913',
22 | ),
23 | Tutorial(
24 | title: 'ToDo List With RefreshIndicator',
25 | description: 'Fetch a ToDo list from jsonplaceholder and use RefreshIndicator widget to refetch data',
26 | tutorialPageRoute: RefreshIndicatorThreadHome.routeName,
27 | tutorialLink: 'https://twitter.com/roaakdm/status/1472181621759655939'),
28 | Tutorial(
29 | title: 'ScrollPhysics Types With Examples',
30 | description: 'See all types of ScrollPhysics with example usages and code',
31 | tutorialPageRoute: ScrollPhysicsThreadHome.routeName,
32 | ),
33 | Tutorial(
34 | title: 'ReorderableListView',
35 | description: 'Easily allow your users to reorder a list using the ReorderableListView widget',
36 | tutorialPageRoute: ReorderableListViewPage.routeName,
37 | ),
38 | Tutorial(
39 | title: 'AnimatedCrossFade widget',
40 | description: 'Use the AnimatedCrossFade widget to apply smooth fade animation when switching between two widgets for a better user experience, instead of abruptly doing so',
41 | tutorialPageRoute: AnimatedCrossFadeExample.routeName,
42 | ),
43 | ];
44 |
45 | static List scrollPhysicsTypes = [
46 | ScrollPhysicsData(
47 | title: 'NeverScrollableScrollPhysics',
48 | pageRoute: NeverScrollableScrollPhysicsExample.routeName,
49 | ),
50 | ScrollPhysicsData(
51 | title: 'AlwaysScrollableScrollPhysics',
52 | pageRoute: AlwaysScrollableScrollPhysicsExample.routeName,
53 | ),
54 | ScrollPhysicsData(
55 | title: 'BouncingScrollPhysics',
56 | pageRoute: BouncingScrollPhysicsExample.routeName,
57 | ),
58 | ScrollPhysicsData(
59 | title: 'ClampingScrollPhysics',
60 | pageRoute: ClampingScrollPhysicsExample.routeName,
61 | ),
62 | ScrollPhysicsData(
63 | title: 'FixedExtentScrollPhysics',
64 | pageRoute: FixedExtentScrollPhysicsExample.routeName,
65 | ),
66 | ];
67 | }
68 |
--------------------------------------------------------------------------------
/lib/data/models/scroll_physics_data.dart:
--------------------------------------------------------------------------------
1 | class ScrollPhysicsData {
2 | String title;
3 | String pageRoute;
4 |
5 | ScrollPhysicsData({
6 | required this.title,
7 | required this.pageRoute,
8 | });
9 | }
10 |
--------------------------------------------------------------------------------
/lib/data/models/tutorial.dart:
--------------------------------------------------------------------------------
1 | class Tutorial {
2 | String title;
3 | String description;
4 | String? tutorialLink;
5 | String? tutorialPageRoute;
6 |
7 | Tutorial({
8 | required this.title,
9 | required this.description,
10 | this.tutorialLink,
11 | this.tutorialPageRoute,
12 | });
13 | }
14 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/animated-cross-fade/pages/animated_cross_fade_example.dart';
3 | import 'package:flutter_tutorials/avatar-uploader-tutorial/data/services/service_locator.dart';
4 | import 'package:flutter_tutorials/avatar-uploader-tutorial/ui/file_upload_service_home_page.dart';
5 | import 'package:flutter_tutorials/refresh-indicator-thread/refresh_indicator_thread_home.dart';
6 | import 'package:flutter_tutorials/reorderable-list-view/pages/reorderable_list_view_page.dart';
7 | import 'package:flutter_tutorials/scroll-physics-thread/always_scrollable_scroll_physics_example.dart';
8 | import 'package:flutter_tutorials/scroll-physics-thread/bouncing_scroll_physics_example.dart';
9 | import 'package:flutter_tutorials/scroll-physics-thread/clamping_scroll_physics_example.dart';
10 | import 'package:flutter_tutorials/scroll-physics-thread/fixed_extent_scroll_physics_example.dart';
11 | import 'package:flutter_tutorials/scroll-physics-thread/never_scrollable_scroll_physics_example.dart';
12 | import 'package:flutter_tutorials/scroll-physics-thread/scroll_physics_thread_home.dart';
13 | import 'package:flutter_tutorials/ui/home/pages/home_page.dart';
14 |
15 | void main() {
16 | setupServiceLocator();
17 | runApp(const MyApp());
18 | }
19 |
20 | class MyApp extends StatelessWidget {
21 | const MyApp({Key? key}) : super(key: key);
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | return MaterialApp(
26 | debugShowCheckedModeBanner: false,
27 | title: 'Flutter Demo',
28 | theme: ThemeData(
29 | primaryColor: Colors.teal,
30 | primarySwatch: Colors.teal,
31 | elevatedButtonTheme: ElevatedButtonThemeData(
32 | style: ElevatedButton.styleFrom(
33 | shape: RoundedRectangleBorder(
34 | borderRadius: BorderRadius.circular(10),
35 | ),
36 | ),
37 | ),
38 | ),
39 | routes: {
40 | FileUploadServiceHomePage.routeName: (context) => FileUploadServiceHomePage(),
41 | RefreshIndicatorThreadHome.routeName: (context) => RefreshIndicatorThreadHome(),
42 | ScrollPhysicsThreadHome.routeName: (context) => ScrollPhysicsThreadHome(),
43 | NeverScrollableScrollPhysicsExample.routeName: (context) => NeverScrollableScrollPhysicsExample(),
44 | BouncingScrollPhysicsExample.routeName: (context) => BouncingScrollPhysicsExample(),
45 | ClampingScrollPhysicsExample.routeName: (context) => ClampingScrollPhysicsExample(),
46 | FixedExtentScrollPhysicsExample.routeName: (context) => FixedExtentScrollPhysicsExample(),
47 | AlwaysScrollableScrollPhysicsExample.routeName: (context) => AlwaysScrollableScrollPhysicsExample(),
48 | ReorderableListViewPage.routeName: (context) => ReorderableListViewPage(),
49 | AnimatedCrossFadeExample.routeName: (context) => AnimatedCrossFadeExample(),
50 | },
51 | home: HomePage(),
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/mains/main_color_helper.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | void main() {
4 | runApp(App());
5 | }
6 |
7 | class App extends StatelessWidget {
8 | @override
9 | Widget build(BuildContext context) {
10 | return MaterialApp(
11 | debugShowCheckedModeBanner: false,
12 | home: HomePage(),
13 | );
14 | }
15 | }
16 |
17 | class HomePage extends StatelessWidget {
18 | @override
19 | Widget build(BuildContext context) {
20 | return Scaffold(
21 | appBar: AppBar(
22 | title: const Text('Material Color Shades'),
23 | ),
24 | body: Center(
25 | child: Column(
26 | children: [
27 | PrimaryColorOptions(),
28 | MaterialColorShades(),
29 | PrimaryColorOptions(),
30 | ],
31 | ),
32 | ),
33 | );
34 | }
35 | }
36 |
37 | class PrimaryColorOptions extends StatelessWidget {
38 | @override
39 | Widget build(BuildContext context) {
40 | return Container(
41 | decoration: BoxDecoration(
42 | border: Border.all(color: Colors.blueGrey, width: 2),
43 | ),
44 | child: Row(
45 | children: List.generate(
46 | AppColors.primaryColors.length,
47 | (i) => Expanded(
48 | child: Container(
49 | height: 50,
50 | color: AppColors.primaryColors[i],
51 | ),
52 | ),
53 | ),
54 | ),
55 | );
56 | }
57 | }
58 |
59 | class MaterialColorShades extends StatelessWidget {
60 | @override
61 | Widget build(BuildContext context) {
62 | return SizedBox(
63 | height: 500,
64 | child: Row(
65 | children: List.generate(
66 | AppColors.materialColors.length,
67 | (i) {
68 | return Expanded(
69 | child: Column(
70 | children: _buildShadesContainers(AppColors.materialColors[i]),
71 | ),
72 | );
73 | },
74 | ),
75 | ),
76 | );
77 | }
78 |
79 | List _buildShadesContainers(MaterialColor materialColor) {
80 | List _shadesContainers = [];
81 | AppColors.getMaterialColorShades(materialColor).forEach(
82 | (materialColorShadeIndex, materialColorShade) {
83 | _shadesContainers.add(Expanded(
84 | child: Container(
85 | width: double.infinity,
86 | decoration: BoxDecoration(
87 | color: materialColorShade,
88 | border: materialColorShadeIndex == 500
89 | ? const Border(
90 | top: BorderSide(width: 2, color: Colors.blueGrey),
91 | bottom: BorderSide(width: 2, color: Colors.blueGrey),
92 | )
93 | : null,
94 | ),
95 | child: Column(
96 | mainAxisAlignment: MainAxisAlignment.center,
97 | children: [
98 | if (materialColorShadeIndex == 500) const Text('MAIN'),
99 | Text('$materialColorShadeIndex'),
100 | ],
101 | ),
102 | ),
103 | ));
104 | },
105 | );
106 | return _shadesContainers;
107 | }
108 | }
109 |
110 | class AppColors {
111 | static List hexColors = [
112 | 'd23156',
113 | '16b9fd',
114 | '13d0c1',
115 | 'e5672f',
116 | 'b73d99',
117 | ];
118 |
119 | static List get primaryColors {
120 | List _primaryColors = [];
121 |
122 | for (String hexColor in hexColors) {
123 | Color _color = Color(int.parse('0xff$hexColor'));
124 | _primaryColors.add(_color);
125 | }
126 |
127 | return _primaryColors;
128 | }
129 |
130 | static Color getShade(Color color, {bool darker = false, double value = .1}) {
131 | assert(value >= 0 && value <= 1);
132 |
133 | final hsl = HSLColor.fromColor(color);
134 | final hslDark = hsl.withLightness((darker ? (hsl.lightness - value) : (hsl.lightness + value)).clamp(0.0, 1.0));
135 |
136 | return hslDark.toColor();
137 | }
138 |
139 | static MaterialColor getMaterialColorFromColor(Color color) {
140 | Map _colorShades = {
141 | 50: getShade(color, value: 0.5),
142 | 100: getShade(color, value: 0.4),
143 | 200: getShade(color, value: 0.3),
144 | 300: getShade(color, value: 0.2),
145 | 400: getShade(color, value: 0.1),
146 | 500: color,
147 | 600: getShade(color, value: 0.1, darker: true),
148 | 700: getShade(color, value: 0.15, darker: true),
149 | 800: getShade(color, value: 0.2, darker: true),
150 | 900: getShade(color, value: 0.25, darker: true),
151 | };
152 | return MaterialColor(color.value, _colorShades);
153 | }
154 |
155 | static List get materialColors {
156 | List _materialColors = [];
157 | for (Color primaryColor in primaryColors) {
158 | _materialColors.add(getMaterialColorFromColor(primaryColor));
159 | }
160 | return _materialColors;
161 | }
162 |
163 | static Map getMaterialColorShades(MaterialColor materialColor) {
164 | return {
165 | 50: materialColor.shade50,
166 | 100: materialColor.shade100,
167 | 200: materialColor.shade200,
168 | 300: materialColor.shade300,
169 | 400: materialColor.shade400,
170 | 500: materialColor.shade500,
171 | 600: materialColor.shade600,
172 | 700: materialColor.shade700,
173 | 800: materialColor.shade800,
174 | 900: materialColor.shade900,
175 | };
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/lib/mains/main_theme_switcher.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:provider/provider.dart';
3 |
4 | void main() {
5 | runApp(App());
6 | }
7 |
8 | const double _containerWidth = 450.0;
9 |
10 | class App extends StatelessWidget {
11 | @override
12 | Widget build(BuildContext context) {
13 | return MultiProvider(
14 | providers: [
15 | ChangeNotifierProvider(
16 | create: (_) => ThemeProvider(),
17 | ),
18 | ],
19 | child: Consumer(
20 | child: HomePage(),
21 | builder: (c, themeProvider, child) {
22 | return MaterialApp(
23 | debugShowCheckedModeBanner: false,
24 | themeMode: themeProvider.selectedThemeMode,
25 | theme: ThemeData(
26 | brightness: Brightness.light,
27 | primarySwatch: AppColors.getMaterialColorFromColor(themeProvider.selectedPrimaryColor),
28 | primaryColor: themeProvider.selectedPrimaryColor,
29 | ),
30 | darkTheme: ThemeData(
31 | brightness: Brightness.dark,
32 | primarySwatch: AppColors.getMaterialColorFromColor(themeProvider.selectedPrimaryColor),
33 | primaryColor: themeProvider.selectedPrimaryColor,
34 | ),
35 | home: child,
36 | );
37 | },
38 | ),
39 | );
40 | }
41 | }
42 |
43 | class HomePage extends StatelessWidget {
44 | @override
45 | Widget build(BuildContext context) {
46 | return Scaffold(
47 | appBar: AppBar(
48 | title: const Text('Theme & Primary Color Switcher'),
49 | ),
50 | body: Center(
51 | child: Container(
52 | padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 17),
53 | width: _containerWidth,
54 | child: Column(
55 | crossAxisAlignment: CrossAxisAlignment.center,
56 | mainAxisAlignment: MainAxisAlignment.center,
57 | children: [
58 | const Padding(
59 | padding: EdgeInsets.symmetric(vertical: 10),
60 | child: Text('Theme'),
61 | ),
62 | ThemeSwitcher(),
63 | const Padding(
64 | padding: EdgeInsets.symmetric(vertical: 10),
65 | child: Text('Primary Color'),
66 | ),
67 | PrimaryColorSwitcher(),
68 | ],
69 | ),
70 | ),
71 | ),
72 | );
73 | }
74 | }
75 |
76 | class ThemeProvider with ChangeNotifier {
77 | ThemeMode selectedThemeMode = appThemes[0].mode;
78 |
79 | setSelectedThemeMode(ThemeMode _themeMode) {
80 | selectedThemeMode = _themeMode;
81 | notifyListeners();
82 | }
83 |
84 | Color selectedPrimaryColor = AppColors.primaryColors[0];
85 |
86 | setSelectedPrimaryColor(Color _color) {
87 | selectedPrimaryColor = _color;
88 | notifyListeners();
89 | }
90 | }
91 |
92 | class ThemeSwitcher extends StatelessWidget {
93 | @override
94 | Widget build(BuildContext context) {
95 | return Consumer(
96 | builder: (c, themeProvider, _) => SizedBox(
97 | height: (_containerWidth - (17 * 2) - (10 * 2)) / 3,
98 | child: GridView.count(
99 | physics: const NeverScrollableScrollPhysics(),
100 | crossAxisSpacing: 10,
101 | crossAxisCount: appThemes.length,
102 | children: List.generate(
103 | appThemes.length,
104 | (i) {
105 | bool _isSelectedTheme = appThemes[i].mode == themeProvider.selectedThemeMode;
106 | return GestureDetector(
107 | onTap: _isSelectedTheme ? null : () => themeProvider.setSelectedThemeMode(appThemes[i].mode),
108 | child: AnimatedContainer(
109 | height: 100,
110 | duration: const Duration(milliseconds: 200),
111 | decoration: BoxDecoration(
112 | color: _isSelectedTheme ? Theme.of(context).primaryColor : Colors.transparent,
113 | borderRadius: BorderRadius.circular(10),
114 | border: Border.all(width: 2, color: Theme.of(context).primaryColor),
115 | ),
116 | child: Center(
117 | child: Container(
118 | padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 7),
119 | margin: const EdgeInsets.symmetric(horizontal: 10),
120 | decoration: BoxDecoration(
121 | borderRadius: BorderRadius.circular(8),
122 | color: Theme.of(context).cardColor.withOpacity(0.5),
123 | ),
124 | child: Row(
125 | mainAxisAlignment: MainAxisAlignment.spaceAround,
126 | children: [
127 | Icon(appThemes[i].icon),
128 | Text(
129 | appThemes[i].title,
130 | style: Theme.of(context).textTheme.subtitle2,
131 | ),
132 | ],
133 | ),
134 | ),
135 | ),
136 | ),
137 | );
138 | },
139 | ),
140 | ),
141 | ),
142 | );
143 | }
144 | }
145 |
146 | class PrimaryColorSwitcher extends StatelessWidget {
147 | @override
148 | Widget build(BuildContext context) {
149 | return Consumer(
150 | builder: (c, themeProvider, _) => SizedBox(
151 | height: (_containerWidth - (17 * 2) - (10 * 2)) / 3,
152 | child: GridView.count(
153 | crossAxisCount: AppColors.primaryColors.length,
154 | physics: const NeverScrollableScrollPhysics(),
155 | crossAxisSpacing: 10,
156 | children: List.generate(
157 | AppColors.primaryColors.length,
158 | (i) {
159 | bool _isSelectedColor = AppColors.primaryColors[i] == themeProvider.selectedPrimaryColor;
160 | return GestureDetector(
161 | onTap: _isSelectedColor ? null : () => themeProvider.setSelectedPrimaryColor(AppColors.primaryColors[i]),
162 | child: Container(
163 | height: 50,
164 | decoration: BoxDecoration(
165 | color: AppColors.primaryColors[i],
166 | borderRadius: BorderRadius.circular(10),
167 | ),
168 | child: AnimatedOpacity(
169 | duration: const Duration(milliseconds: 200),
170 | opacity: _isSelectedColor ? 1 : 0,
171 | child: Center(
172 | child: ClipRRect(
173 | borderRadius: BorderRadius.circular(8),
174 | child: Container(
175 | padding: const EdgeInsets.all(5),
176 | decoration: BoxDecoration(
177 | borderRadius: BorderRadius.circular(3),
178 | color: Theme.of(context).cardColor.withOpacity(0.5),
179 | ),
180 | child: const Icon(
181 | Icons.check,
182 | size: 20,
183 | ),
184 | ),
185 | ),
186 | ),
187 | ),
188 | ),
189 | );
190 | },
191 | ),
192 | ),
193 | ),
194 | );
195 | }
196 | }
197 |
198 | class AppColors {
199 | static List primaryColors = const [
200 | Color(0xffd23156),
201 | Color(0xff16b9fd),
202 | Color(0xff13d0c1),
203 | Color(0xffe5672f),
204 | Color(0xffb73d99),
205 | ];
206 |
207 | static Color getShade(Color color, {bool darker = false, double value = .1}) {
208 | assert(value >= 0 && value <= 1);
209 |
210 | final hsl = HSLColor.fromColor(color);
211 | final hslDark = hsl.withLightness((darker ? (hsl.lightness - value) : (hsl.lightness + value)).clamp(0.0, 1.0));
212 |
213 | return hslDark.toColor();
214 | }
215 |
216 | static MaterialColor getMaterialColorFromColor(Color color) {
217 | Map _colorShades = {
218 | 50: getShade(color, value: 0.5),
219 | 100: getShade(color, value: 0.4),
220 | 200: getShade(color, value: 0.3),
221 | 300: getShade(color, value: 0.2),
222 | 400: getShade(color, value: 0.1),
223 | 500: color, //Primary value
224 | 600: getShade(color, value: 0.1, darker: true),
225 | 700: getShade(color, value: 0.15, darker: true),
226 | 800: getShade(color, value: 0.2, darker: true),
227 | 900: getShade(color, value: 0.25, darker: true),
228 | };
229 | return MaterialColor(color.value, _colorShades);
230 | }
231 | }
232 |
233 | class AppTheme {
234 | ThemeMode mode;
235 | String title;
236 | IconData icon;
237 |
238 | AppTheme({
239 | required this.mode,
240 | required this.title,
241 | required this.icon,
242 | });
243 | }
244 |
245 | List appThemes = [
246 | AppTheme(
247 | mode: ThemeMode.light,
248 | title: 'Light',
249 | icon: Icons.brightness_5_rounded,
250 | ),
251 | AppTheme(
252 | mode: ThemeMode.dark,
253 | title: 'Dark',
254 | icon: Icons.brightness_2_rounded,
255 | ),
256 | AppTheme(
257 | mode: ThemeMode.system,
258 | title: 'Auto',
259 | icon: Icons.brightness_4_rounded,
260 | ),
261 | ];
262 |
--------------------------------------------------------------------------------
/lib/refresh-indicator-thread/refresh_indicator_thread_home.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:dio/dio.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class RefreshIndicatorThreadHome extends StatefulWidget {
7 | static const String routeName = 'refresh-indicator-thread-home';
8 |
9 | @override
10 | _RefreshIndicatorThreadHomeState createState() => _RefreshIndicatorThreadHomeState();
11 | }
12 |
13 | class _RefreshIndicatorThreadHomeState extends State {
14 | StreamController> streamController = StreamController>();
15 |
16 | Future> _getToDos() async {
17 | const endpoint = 'https://jsonplaceholder.typicode.com/todos?userId=2';
18 | print('Fetching from: $endpoint');
19 | var response = await Dio().get(endpoint);
20 | return response.data;
21 | }
22 |
23 | @override
24 | void initState() {
25 | _getToDos().then((todos) => streamController.add(todos));
26 | super.initState();
27 | }
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | print('Rebuilt page!');
32 | return Scaffold(
33 | appBar: AppBar(
34 | title: const Text('Refresh Indicator Example'),
35 | ),
36 | body: RefreshIndicator(
37 | onRefresh: () async => streamController.add(await _getToDos()),
38 | child: StreamBuilder>(
39 | stream: streamController.stream,
40 | builder: (BuildContext context, AsyncSnapshot> snapshot) {
41 | if (snapshot.hasError) {
42 | return const Center(child: Text('An Error Occurred'));
43 | } else {
44 | switch (snapshot.connectionState) {
45 | case ConnectionState.waiting:
46 | return const Center(child: CircularProgressIndicator());
47 | case ConnectionState.active:
48 | case ConnectionState.done:
49 | return SingleChildScrollView(
50 | clipBehavior: Clip.none,
51 | physics: const AlwaysScrollableScrollPhysics(),
52 | child: Column(
53 | crossAxisAlignment: CrossAxisAlignment.start,
54 | children: [
55 | Padding(
56 | padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 20),
57 | child: Text(
58 | 'Dummy Paragraph',
59 | style: Theme.of(context).textTheme.headline5,
60 | ),
61 | ),
62 | const Padding(
63 | padding: EdgeInsets.symmetric(horizontal: 17),
64 | child: Text(
65 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam ut justo feugiat, sodales mauris eget, tristique metus. Aliquam mi tortor, fermentum nec viverra et, semper eget risus. Phasellus tincidunt suscipit erat a ullamcorper. In a mattis lectus. Mauris interdum condimentum ullamcorper. Sed eget porta risus, quis pulvinar lorem. Etiam porttitor aliquam diam, tristique mollis nisi ullamcorper eget.'),
66 | ),
67 | Padding(
68 | padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 20),
69 | child: Text(
70 | 'Checklist',
71 | style: Theme.of(context).textTheme.headline5,
72 | ),
73 | ),
74 | ...List.generate(
75 | 3,
76 | (i) => Container(
77 | width: double.infinity,
78 | padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 10),
79 | decoration: BoxDecoration(
80 | border: Border(bottom: BorderSide(width: 1, color: Theme.of(context).dividerColor)),
81 | ),
82 | child: Row(
83 | children: [
84 | const Icon(Icons.check),
85 | const SizedBox(width: 5),
86 | Expanded(child: Text(snapshot.data![i]['title'])),
87 | ],
88 | ),
89 | ),
90 | ),
91 | ],
92 | ),
93 | );
94 | case ConnectionState.none:
95 | default:
96 | return const Center(child: Text('Nothing!'));
97 | }
98 | }
99 | },
100 | ),
101 | ),
102 | );
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/lib/reorderable-list-view/pages/reorderable_list_view_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/ui/home/widgets/list_item.dart';
3 |
4 | class ReorderableListViewPage extends StatefulWidget {
5 | static const String routeName = 'reorderable-list-view-page';
6 |
7 | @override
8 | _ReorderableListViewPageState createState() => _ReorderableListViewPageState();
9 | }
10 |
11 | class _ReorderableListViewPageState extends State {
12 | final List _list = [
13 | 'List Item 1',
14 | 'List Item 2',
15 | 'List Item 3',
16 | 'List Item 4',
17 | ];
18 |
19 | void reorderList(int oldIndex, int newIndex) {
20 | if (newIndex > oldIndex) {
21 | newIndex -= 1;
22 | }
23 | setState(() {
24 | final String _item = _list.removeAt(oldIndex);
25 | _list.insert(newIndex, _item);
26 | });
27 | }
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | return Scaffold(
32 | appBar: AppBar(
33 | title: const Text('ReorderableListView Example'),
34 | ),
35 | body: ReorderableListView(
36 | padding: const EdgeInsets.symmetric(vertical: 20),
37 | onReorder: reorderList,
38 | children: List.generate(
39 | _list.length,
40 | (index) => ListItem(_list[index], ValueKey(index)),
41 | ),
42 | ),
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/scroll-physics-thread/always_scrollable_scroll_physics_example.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/common/ui/widgets/bordered_container.dart';
3 |
4 | class AlwaysScrollableScrollPhysicsExample extends StatelessWidget {
5 | static const String routeName = 'always-scrollable-scroll-physics-example';
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return Scaffold(
10 | appBar: AppBar(
11 | title: Text(
12 | 'AlwaysScrollableScrollPhysics Example',
13 | style: Theme.of(context).textTheme.subtitle1!.copyWith(color: Colors.white, fontSize: 14),
14 | ),
15 | ),
16 | body: SingleChildScrollView(
17 | padding: const EdgeInsets.symmetric(vertical: 20),
18 | physics: const AlwaysScrollableScrollPhysics(),
19 | clipBehavior: Clip.none,
20 | child: Column(
21 | children: [
22 | const Padding(
23 | padding: EdgeInsets.symmetric(horizontal: 17),
24 | child: Text(
25 | 'Adding AlwaysScrollableScrollPhysics to the parent SingleChildScrollView in this page forces scrolling even when the content of the scrollable widget’s content doesn’t exceed the height of the screen',
26 | ),
27 | ),
28 | const Padding(
29 | padding: EdgeInsets.symmetric(horizontal: 17, vertical: 15),
30 | child: Text(
31 | 'Note: It is important that you set shrinkWrap to true in the ListView.builder() widget or else you will get the scary "Vertical viewport was given unbounded height." Error',
32 | ),
33 | ),
34 | ListView.builder(
35 | shrinkWrap: true,
36 | physics: const NeverScrollableScrollPhysics(),
37 | itemCount: 5,
38 | itemBuilder: (c, i) => BorderedContainer(
39 | child: Text(
40 | 'List Item ${i + 1}',
41 | style: Theme.of(context).textTheme.headline6,
42 | ),
43 | ),
44 | ),
45 | ],
46 | ),
47 | ),
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/scroll-physics-thread/bouncing_scroll_physics_example.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/common/ui/widgets/bordered_container.dart';
3 |
4 | class BouncingScrollPhysicsExample extends StatelessWidget {
5 | static const String routeName = 'bouncing-scroll-physics-example';
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return Scaffold(
10 | appBar: AppBar(
11 | title: Text(
12 | 'BouncingScrollPhysics Example',
13 | style: Theme.of(context).textTheme.subtitle1!.copyWith(color: Colors.white),
14 | ),
15 | ),
16 | body: ListView.builder(
17 | physics: const BouncingScrollPhysics(),
18 | itemCount: 20,
19 | itemBuilder: (c, i) => BorderedContainer(
20 | child: Text(
21 | 'List Item ${i + 1}',
22 | style: Theme.of(context).textTheme.headline6,
23 | ),
24 | ),
25 | ),
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/scroll-physics-thread/clamping_scroll_physics_example.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/common/ui/widgets/bordered_container.dart';
3 |
4 | class ClampingScrollPhysicsExample extends StatelessWidget {
5 | static const String routeName = 'clamping-scroll-physics-example';
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return Scaffold(
10 | appBar: AppBar(
11 | title: Text(
12 | 'ClampingScrollPhysics Example',
13 | style: Theme.of(context).textTheme.subtitle1!.copyWith(color: Colors.white),
14 | ),
15 | ),
16 | body: ListView.builder(
17 | physics: const ClampingScrollPhysics(),
18 | itemCount: 20,
19 | itemBuilder: (c, i) => BorderedContainer(
20 | child: Text(
21 | 'List Item ${i + 1}',
22 | style: Theme.of(context).textTheme.headline6,
23 | ),
24 | ),
25 | ),
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/scroll-physics-thread/fixed_extent_scroll_physics_example.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/common/ui/widgets/bordered_container.dart';
3 |
4 | class FixedExtentScrollPhysicsExample extends StatelessWidget {
5 | static const String routeName = 'fixed-extent-scroll-physics-example';
6 | final FixedExtentScrollController fixedExtentScrollController = FixedExtentScrollController();
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Scaffold(
11 | appBar: AppBar(
12 | title: Text(
13 | 'FixedExtentScrollPhysics Example',
14 | style: Theme.of(context).textTheme.subtitle1!.copyWith(color: Colors.white),
15 | ),
16 | ),
17 | body: ListWheelScrollView(
18 | controller: fixedExtentScrollController,
19 | physics: const FixedExtentScrollPhysics(),
20 | itemExtent: MediaQuery.of(context).size.height,
21 | overAndUnderCenterOpacity: 0,
22 | children: List.generate(
23 | 20,
24 | (i) => BorderedContainer(
25 | color: Colors.teal.withOpacity(0.3),
26 | child: Center(
27 | child: Text(
28 | 'List Item ${i + 1}',
29 | style: Theme.of(context).textTheme.headline4,
30 | ),
31 | ),
32 | ),
33 | ),
34 | ),
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/scroll-physics-thread/never_scrollable_scroll_physics_example.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/common/ui/widgets/bordered_container.dart';
3 |
4 | class NeverScrollableScrollPhysicsExample extends StatelessWidget {
5 | static const String routeName = 'never-scrollable-scroll-physics-example';
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return Scaffold(
10 | appBar: AppBar(
11 | title: Text(
12 | 'NeverScrollableScrollPhysics Example',
13 | style: Theme.of(context).textTheme.subtitle1!.copyWith(color: Colors.white),
14 | ),
15 | ),
16 | body: SingleChildScrollView(
17 | padding: const EdgeInsets.symmetric(vertical: 20),
18 | child: Column(
19 | children: [
20 | InkWell(
21 | onTap: () {},
22 | child: Column(
23 | children: const [
24 | Padding(
25 | padding: EdgeInsets.symmetric(horizontal: 17),
26 | child: Text(
27 | 'The list below is a created using a ListView.builder() widget and has its physics set to NeverScrollableScrollPhysics() because otherwise you will not be able to scroll it unless you tab inside it ans scroll, so the whole screen does not scroll as a whole, it scrolls by section, which is not a good user experience',
28 | ),
29 | ),
30 | Padding(
31 | padding: EdgeInsets.symmetric(horizontal: 17, vertical: 15),
32 | child: Text(
33 | 'Note: It is important that you set shrinkWrap to true in the ListView.builder() widget or else you will get the scary "Vertical viewport was given unbounded height." Error',
34 | ),
35 | ),
36 | ],
37 | ),
38 | ),
39 | ListView.builder(
40 | shrinkWrap: true,
41 | physics: const NeverScrollableScrollPhysics(),
42 | itemCount: 20,
43 | itemBuilder: (c, i) => InkWell(
44 | onTap: () {},
45 | child: BorderedContainer(
46 | child: Text(
47 | 'List Item ${i + 1}',
48 | style: Theme.of(context).textTheme.headline6,
49 | ),
50 | ),
51 | ),
52 | ),
53 | ],
54 | ),
55 | ),
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/scroll-physics-thread/scroll_physics_thread_home.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/data/app_data.dart';
3 |
4 | class ScrollPhysicsThreadHome extends StatelessWidget {
5 | static const String routeName = 'scroll-physics-thread-home';
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return Scaffold(
10 | appBar: AppBar(
11 | title: Text(
12 | 'ScrollPhysics Types w/ Examples',
13 | style: Theme.of(context).textTheme.subtitle1!.copyWith(color: Colors.white),
14 | ),
15 | ),
16 | body: ListView.builder(
17 | itemCount: AppData.scrollPhysicsTypes.length,
18 | itemBuilder: (c, i) => InkWell(
19 | onTap: () => Navigator.of(context).pushNamed(AppData.scrollPhysicsTypes[i].pageRoute),
20 | child: Container(
21 | padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 20),
22 | decoration: BoxDecoration(
23 | border: Border(
24 | bottom: BorderSide(color: Theme.of(context).dividerColor),
25 | ),
26 | ),
27 | child: Text(
28 | AppData.scrollPhysicsTypes[i].title,
29 | style: Theme.of(context).textTheme.headline6,
30 | ),
31 | ),
32 | ),
33 | ),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/ui/home/pages/home_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/data/app_data.dart';
3 | import 'package:flutter_tutorials/ui/home/widgets/tutorial_list_item.dart';
4 |
5 | class HomePage extends StatelessWidget {
6 | @override
7 | Widget build(BuildContext context) {
8 | return Scaffold(
9 | appBar: AppBar(
10 | title: const Text('Flutter Tutorials'),
11 | ),
12 | body: SingleChildScrollView(
13 | child: Column(
14 | children: List.generate(
15 | AppData.appTutorials.length,
16 | (i) => TutorialListItem(AppData.appTutorials[i]),
17 | ),
18 | ),
19 | ),
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/ui/home/widgets/list_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class ListItem extends StatelessWidget {
4 | final String text;
5 |
6 | const ListItem(this.text, Key? key) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Container(
11 | margin: const EdgeInsets.symmetric(horizontal: 17, vertical: 5),
12 | padding: const EdgeInsets.all(20),
13 | decoration: BoxDecoration(
14 | color: Colors.teal.withOpacity(0.2),
15 | borderRadius: BorderRadius.circular(10),
16 | ),
17 | child: Text(
18 | text,
19 | style: Theme.of(context).textTheme.headline6,
20 | ),
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/ui/home/widgets/tutorial_list_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_tutorials/data/models/tutorial.dart';
3 |
4 | class TutorialListItem extends StatelessWidget {
5 | final Tutorial tutorial;
6 |
7 | const TutorialListItem(this.tutorial);
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return InkWell(
12 | onTap: tutorial.tutorialPageRoute == null ? null : () => Navigator.of(context).pushNamed(tutorial.tutorialPageRoute!),
13 | child: Container(
14 | padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 15),
15 | decoration: BoxDecoration(
16 | border: Border(
17 | bottom: BorderSide(width: 1, color: Colors.black.withOpacity(0.2)),
18 | ),
19 | ),
20 | child: Row(
21 | children: [
22 | Expanded(
23 | child: Column(
24 | crossAxisAlignment: CrossAxisAlignment.start,
25 | children: [
26 | Text(tutorial.title, style: Theme.of(context).textTheme.headline6),
27 | const SizedBox(height: 10),
28 | Text(tutorial.description),
29 | ],
30 | ),
31 | ),
32 | const SizedBox(width: 10),
33 | const Icon(Icons.arrow_forward),
34 | ],
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/ui/ui-helper/navigation_helper.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | void pushMaterialPageRoute(BuildContext context, Widget page, {bool rootNavigator = true}) {
5 | Navigator.of(context, rootNavigator: rootNavigator).push(
6 | MaterialPageRoute(
7 | builder: (context) => page,
8 | ),
9 | );
10 | }
11 |
12 | Future pushCupertinoPage(
13 | BuildContext context,
14 | Widget page, {
15 | bool rootNavigator = true,
16 | bool fullscreenDialog = false,
17 | ValueChanged? onPop,
18 | }) async {
19 | final response = await Navigator.of(context, rootNavigator: rootNavigator).push(
20 | CupertinoPageRoute(
21 | builder: (BuildContext context) => page,
22 | fullscreenDialog: fullscreenDialog,
23 | ),
24 | );
25 | if (onPop != null) {
26 | onPop(response);
27 | }
28 | }
29 |
30 | void pushAndReplaceCupertinoPage(BuildContext context, Widget page, {bool rootNavigator = false}) {
31 | Navigator.of(context, rootNavigator: rootNavigator).pushReplacement(
32 | CupertinoPageRoute(
33 | builder: (BuildContext context) => page,
34 | ),
35 | );
36 | }
37 |
38 | void pushAndRemoveUntilCupertinoPage(BuildContext context, Widget page, {bool rootNavigator = true}) {
39 | Navigator.of(context, rootNavigator: rootNavigator).pushAndRemoveUntil(
40 | CupertinoPageRoute(
41 | builder: (BuildContext context) => page,
42 | ),
43 | (Route route) => false,
44 | );
45 | }
46 |
47 | void pushAndRemoveUntilMaterialPage(BuildContext context, Widget page, {bool rootNavigator = true}) {
48 | Navigator.of(context, rootNavigator: rootNavigator).pushAndRemoveUntil(
49 | MaterialPageRoute(builder: (BuildContext context) => page),
50 | (Route route) => false,
51 | );
52 | }
53 |
54 | void pushFadeInPage(
55 | BuildContext context,
56 | Widget page, {
57 | bool rootNavigator = true,
58 | Function? onPop,
59 | }) {
60 | Navigator.of(context, rootNavigator: rootNavigator)
61 | .push(
62 | PageRouteBuilder(
63 | transitionDuration: const Duration(milliseconds: 300),
64 | pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) {
65 | return page;
66 | },
67 | transitionsBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) {
68 | return Align(
69 | child: FadeTransition(
70 | opacity: animation,
71 | child: child,
72 | ),
73 | );
74 | },
75 | ),
76 | )
77 | .then((_) {
78 | if (onPop != null) {
79 | onPop();
80 | }
81 | });
82 | }
83 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_tutorials
2 | description: A new Flutter project.
3 |
4 | # The following line prevents the package from being accidentally published to
5 | # pub.dev using `flutter pub publish`. This is preferred for private packages.
6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
7 |
8 | # The following defines the version and build number for your application.
9 | # A version number is three numbers separated by dots, like 1.2.43
10 | # followed by an optional build number separated by a +.
11 | # Both the version and the builder number may be overridden in flutter
12 | # build by specifying --build-name and --build-number, respectively.
13 | # In Android, build-name is used as versionName while build-number used as versionCode.
14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
16 | # Read more about iOS versioning at
17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
18 | version: 1.0.0+1
19 |
20 | environment:
21 | sdk: ">=2.12.0 <3.0.0"
22 |
23 | # Dependencies specify other packages that your package needs in order to work.
24 | # To automatically upgrade your package dependencies to the latest versions
25 | # consider running `flutter pub upgrade --major-versions`. Alternatively,
26 | # dependencies can be manually updated by changing the version numbers below to
27 | # the latest version available on pub.dev. To see which dependencies have newer
28 | # versions available, run `flutter pub outdated`.
29 | dependencies:
30 | flutter:
31 | sdk: flutter
32 |
33 |
34 | # The following adds the Cupertino Icons font to your application.
35 | # Use with the CupertinoIcons class for iOS style icons.
36 | cupertino_icons: ^1.0.2
37 |
38 | dev_dependencies:
39 | flutter_test:
40 | sdk: flutter
41 |
42 | # The "flutter_lints" package below contains a set of recommended lints to
43 | # encourage good coding practices. The lint set provided by the package is
44 | # activated in the `analysis_options.yaml` file located at the root of your
45 | # package. See that file for information about deactivating specific lint
46 | # rules and activating additional ones.
47 | flutter_lints: ^1.0.4
48 | get_it: ^7.2.0
49 | flutter_image_compress: ^1.1.0
50 | image_picker: ^0.8.4+4
51 | permission_handler: ^8.3.0
52 | path_provider: ^2.0.7
53 | provider: ^6.0.1
54 | dio: ^4.0.4
55 |
56 | # For information on the generic Dart part of this file, see the
57 | # following page: https://dart.dev/tools/pub/pubspec
58 |
59 | # The following section is specific to Flutter.
60 | flutter:
61 |
62 | # The following line ensures that the Material Icons font is
63 | # included with your application, so that you can use the icons in
64 | # the material Icons class.
65 | uses-material-design: true
66 |
67 | # To add assets to your application, add an assets section, like this:
68 | assets:
69 | - assets/images/
70 | # - images/a_dot_ham.jpeg
71 |
72 | # An image asset can refer to one or more resolution-specific "variants", see
73 | # https://flutter.dev/assets-and-images/#resolution-aware.
74 |
75 | # For details regarding adding assets from package dependencies, see
76 | # https://flutter.dev/assets-and-images/#from-packages
77 |
78 | # To add custom fonts to your application, add a fonts section here,
79 | # in this "flutter" section. Each entry in this list should have a
80 | # "family" key with the font family name, and a "fonts" key with a
81 | # list giving the asset and other descriptors for the font. For
82 | # example:
83 | # fonts:
84 | # - family: Schyler
85 | # fonts:
86 | # - asset: fonts/Schyler-Regular.ttf
87 | # - asset: fonts/Schyler-Italic.ttf
88 | # style: italic
89 | # - family: Trajan Pro
90 | # fonts:
91 | # - asset: fonts/TrajanPro.ttf
92 | # - asset: fonts/TrajanPro_Bold.ttf
93 | # weight: 700
94 | #
95 | # For details regarding fonts from package dependencies,
96 | # see https://flutter.dev/custom-fonts/#from-packages
97 |
--------------------------------------------------------------------------------
/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_test/flutter_test.dart';
10 |
11 | import 'package:flutter_tutorials/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(const MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------