├── .gitignore
├── .metadata
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── hellohasan
│ │ │ │ └── flutter_getx_template
│ │ │ │ └── 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
├── fonts
├── Roboto-Bold.ttf
├── Roboto-Italic.ttf
├── Roboto-Light.ttf
├── Roboto-Medium.ttf
├── Roboto-Regular.ttf
└── Roboto-Thin.ttf
├── images
├── arrow_forward.svg
├── ic_favorite.svg
├── ic_font_size.svg
├── ic_fork.svg
├── ic_home.svg
├── ic_language.svg
├── ic_settings.svg
├── ic_test.png
├── ic_theme.png
├── launcher_icon.png
├── test.jpg
└── test_jpeg.jpeg
├── 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
│ │ ├── dev.xcscheme
│ │ └── prod.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-Debug.plist
│ ├── Info-Release.plist
│ └── Runner-Bridging-Header.h
├── l10n.yaml
├── lib
├── app
│ ├── bindings
│ │ ├── initial_binding.dart
│ │ ├── local_source_bindings.dart
│ │ ├── remote_source_bindings.dart
│ │ └── repository_bindings.dart
│ ├── core
│ │ ├── base
│ │ │ ├── base_controller.dart
│ │ │ ├── base_remote_source.dart
│ │ │ ├── base_view.dart
│ │ │ ├── base_widget_mixin.dart
│ │ │ └── paging_controller.dart
│ │ ├── model
│ │ │ ├── github_search_query_param.dart
│ │ │ ├── page_state.dart
│ │ │ └── page_status.dart
│ │ ├── utils
│ │ │ └── debouncer.dart
│ │ ├── values
│ │ │ ├── app_colors.dart
│ │ │ ├── app_values.dart
│ │ │ └── text_styles.dart
│ │ └── widget
│ │ │ ├── app_bar_title.dart
│ │ │ ├── asset_image_view.dart
│ │ │ ├── custom_app_bar.dart
│ │ │ ├── elevated_container.dart
│ │ │ ├── icon_text_widgets.dart
│ │ │ ├── loading.dart
│ │ │ ├── paging_view.dart
│ │ │ └── ripple.dart
│ ├── data
│ │ ├── local
│ │ │ ├── db
│ │ │ │ └── db.txt
│ │ │ └── preference
│ │ │ │ ├── preference_manager.dart
│ │ │ │ └── preference_manager_impl.dart
│ │ ├── model
│ │ │ └── github_project_search_response.dart
│ │ ├── remote
│ │ │ ├── github_remote_data_source.dart
│ │ │ └── github_remote_data_source_impl.dart
│ │ └── repository
│ │ │ ├── github_repository.dart
│ │ │ └── github_repository_impl.dart
│ ├── modules
│ │ ├── favorite
│ │ │ ├── bindings
│ │ │ │ └── favorite_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── favorite_controller.dart
│ │ │ └── views
│ │ │ │ └── favorite_view.dart
│ │ ├── home
│ │ │ ├── bindings
│ │ │ │ └── home_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── home_controller.dart
│ │ │ ├── model
│ │ │ │ └── github_project_ui_data.dart
│ │ │ ├── views
│ │ │ │ └── home_view.dart
│ │ │ └── widget
│ │ │ │ └── item_github_project.dart
│ │ ├── main
│ │ │ ├── bindings
│ │ │ │ └── main_binding.dart
│ │ │ ├── controllers
│ │ │ │ ├── bottom_nav_controller.dart
│ │ │ │ └── main_controller.dart
│ │ │ ├── model
│ │ │ │ ├── menu_code.dart
│ │ │ │ └── menu_item.dart
│ │ │ └── views
│ │ │ │ ├── bottom_nav_bar.dart
│ │ │ │ └── main_view.dart
│ │ ├── other
│ │ │ ├── bindings
│ │ │ │ └── other_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── other_controller.dart
│ │ │ └── views
│ │ │ │ └── other_view.dart
│ │ ├── project_details
│ │ │ ├── bindings
│ │ │ │ └── project_details_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── project_details_controller.dart
│ │ │ └── views
│ │ │ │ └── project_details_view.dart
│ │ └── settings
│ │ │ ├── bindings
│ │ │ └── settings_binding.dart
│ │ │ ├── controllers
│ │ │ └── settings_controller.dart
│ │ │ ├── views
│ │ │ └── settings_view.dart
│ │ │ └── widgets
│ │ │ └── item_settings_widgets.dart
│ ├── my_app.dart
│ ├── network
│ │ ├── dio_provider.dart
│ │ ├── dio_request_retrier.dart
│ │ ├── error_handlers.dart
│ │ ├── exceptions
│ │ │ ├── api_exception.dart
│ │ │ ├── app_exception.dart
│ │ │ ├── base_api_exception.dart
│ │ │ ├── base_exception.dart
│ │ │ ├── json_format_exception.dart
│ │ │ ├── network_exception.dart
│ │ │ ├── not_found_exception.dart
│ │ │ ├── service_unavailable_exception.dart
│ │ │ ├── timeout_exception.dart
│ │ │ └── unauthorize_exception.dart
│ │ ├── pretty_dio_logger.dart
│ │ └── request_headers.dart
│ └── routes
│ │ ├── app_pages.dart
│ │ └── app_routes.dart
├── flavors
│ ├── build_config.dart
│ ├── env_config.dart
│ └── environment.dart
├── l10n
│ ├── app_bn.arb
│ └── app_en.arb
├── main_dev.dart
└── main_prod.dart
├── pubspec.lock
├── pubspec.yaml
├── pull_request_template.md
├── readme_configuration_guideline.md
├── repo_data
├── flutter_getx_template_1.png
├── flutter_getx_template_2.png
├── flutter_getx_template_3.png
├── flutter_getx_template_4.png
└── mvvm_flow.png
├── test
└── widget_test.dart
└── web
├── favicon.png
├── icons
├── Icon-192.png
└── Icon-512.png
├── index.html
└── manifest.json
/.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 | # VS Code
19 | .vscode/
20 |
21 | # Flutter/Dart/Pub related
22 | **/doc/api/
23 | **/ios/Flutter/.last_build_id
24 | .dart_tool/
25 | .flutter-plugins
26 | .flutter-plugins-dependencies
27 | .packages
28 | .pub-cache/
29 | .pub/
30 | /build/
31 |
32 | # Web related
33 | lib/generated_plugin_registrant.dart
34 |
35 | # Symbolication related
36 | app.*.symbols
37 |
38 | # Obfuscation related
39 | app.*.map.json
40 |
41 | # Android related
42 | **/android/**/gradle-wrapper.jar
43 | **/android/.gradle
44 | **/android/captures/
45 | **/android/gradlew
46 | **/android/gradlew.bat
47 | **/android/local.properties
48 | **/android/**/GeneratedPluginRegistrant.java
49 |
50 | # iOS/XCode related
51 | **/ios/**/*.mode1v3
52 | **/ios/**/*.mode2v3
53 | **/ios/**/*.moved-aside
54 | **/ios/**/*.pbxuser
55 | **/ios/**/*.perspectivev3
56 | **/ios/**/*sync/
57 | **/ios/**/.sconsign.dblite
58 | **/ios/**/.tags*
59 | **/ios/**/.vagrant/
60 | **/ios/**/DerivedData/
61 | **/ios/**/Icon?
62 | **/ios/**/Pods/
63 | **/ios/**/.symlinks/
64 | **/ios/**/profile
65 | **/ios/**/xcuserdata
66 | **/ios/.generated/
67 | **/ios/Flutter/App.framework
68 | **/ios/Flutter/Flutter.framework
69 | **/ios/Flutter/Generated.xcconfig
70 | **/ios/Flutter/app.flx
71 | **/ios/Flutter/app.zip
72 | **/ios/Flutter/flutter_assets/
73 | **/ios/ServiceDefinitions.json
74 | **/ios/Runner/GeneratedPluginRegistrant.*
75 |
76 | ### Android ###
77 | # Built application files
78 | *.apk
79 | *.aar
80 | *.ap_
81 | *.aab
82 |
83 | # Files for the ART/Dalvik VM
84 | *.dex
85 |
86 | # Generated files
87 | bin/
88 | gen/
89 | out/
90 | release/
91 |
92 | # Gradle files
93 | .gradle/
94 | build/
95 |
96 | # Local configuration file (sdk path, etc)
97 | local.properties
98 |
99 | # Flutter version manager related
100 | .fvm/
101 | .fvm/*
102 |
103 | *.env
--------------------------------------------------------------------------------
/.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: f4abaa0735eba4dfd8f33f73363911d63931fe03
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Hasan Abdullah
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter GetX Template (GetX, Dio, MVVM)
2 |
3 | This Flutter Template using [GetX](https://pub.dev/packages/get) package for State management, routing and Dependency Injection (bindings). We are using [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel) (Model View ViewModel) architectural pattern here. For network call we are using [Dio](https://pub.dev/packages/dio) package. We followed the recommended folder structure of GetX and used [Get CLI](https://pub.dev/packages/get_cli) command line tool for creating the folder structure.
4 |
5 | # Architecture of this project: MVVM
6 |
7 | MVVM (Model View ViewModel) is one of the most popular architectural pattern for Android App development. Basically
8 | this pattern separates User interface from business-logic and data-logic. So that it's divided into three layers: Model layer,
9 | View layer and View model layer. Let's explore it more deeply.
10 |
11 | 
12 |
13 | ViewModel: At first let's talk about ViewModel. Actually view model is a controller where we
14 | implement our business logics. It receives the data from the model and process the data according to
15 | business logic and pushed into the live data observers which is observing by view.
16 |
17 | View: View is the collections of widgets like Text, Image, Dropdown etc. Which will be displayed
18 | to the users. Even it controls the user input. When it needs any data it command the view model (In this project it's controller)
19 | for data and observe the response. Till then it may display a loader to the user.
20 |
21 | Model: Model is basically backend logic. It controls the data source.
22 |
23 | # To configure and run this project [check here](readme_configuration_guideline.md)
24 | You will find at above link step by step instructions with screenshots.
25 |
26 | # run this project by command line
27 | Dev: `flutter run --flavor dev lib/main_dev.dart`
28 |
29 | Prod: `flutter run --flavor prod lib/main_prod.dart`
30 |
31 | # How to update app information and continue development for your own project?
32 |
33 | 1. Rename root folder name
34 | 2. Update project name and description from pubspec.yaml.
35 | 3. Update app launcher name and icon. [Reference](https://medium.com/@vaibhavi.rana99/change-application-name-and-icon-in-flutter-bebbec297c57)
36 | 4. Update your app's package name by [running this command](https://pub.dev/packages/change_app_package_name):
37 |
38 | `flutter pub run change_app_package_name:main your_package_name`
39 |
40 | # How was this project developed?
41 | - Run [get cli](https://pub.dev/packages/get_cli) command to create project in the required directory: `get create project`
42 | - Create `main_view` by running this command: `get create page:main` and so on...
43 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | analyzer:
4 | exclude: [ ios/**, android/**, test/** ]
5 | plugins:
6 | - dart_code_metrics
7 |
8 | errors:
9 | empty_constructor_bodies: error
10 | missing_required_param: error
11 | always_use_package_imports: error
12 | avoid_types_as_parameter_names: error
13 | close_sinks: error
14 | unnecessary_statements: warning
15 | non_constant_identifier_names: warning
16 |
17 | linter:
18 | rules:
19 | camel_case_types: true
20 | # prefer_double_quotes: true
21 | avoid_empty_else: true
22 | constant_identifier_names: false
23 | use_key_in_widget_constructors: false
24 |
25 | dart_code_metrics:
26 | anti-patterns:
27 | - long-method
28 | - long-parameter-list
29 | metrics:
30 | cyclomatic-complexity: 20
31 | maximum-nesting-level: 5
32 | number-of-parameters: 8
33 | source-lines-of-code: 50
34 | metrics-exclude:
35 | - test/**
36 | - ios/**
37 | - android/**
38 | rules:
39 | newline-before-return:
40 | severity: error
41 | no-boolean-literal-compare:
42 | severity: warning
43 | no-empty-block:
44 | severity: error
45 | # avoid-returning-widgets:
46 | # severity: none
47 | prefer-conditional-expressions:
48 | severity: warning
49 | no-magic-number:
50 | severity: error
51 | allowed: [ 0,1,2,3,4,5,6,7,8,9 ]
52 | # avoid-unused-parameters:
53 | # severity: warning
54 |
55 |
56 |
57 | # severity -> none, style, performance, warning, error.
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | import java.util.regex.Matcher
2 | import java.util.regex.Pattern
3 |
4 | def localProperties = loadPropertiesFile('local.properties')
5 | def keystoreProperties = loadPropertiesFile('key.properties')
6 |
7 | def flutterRoot = localProperties.getProperty('flutter.sdk')
8 | if (flutterRoot == null) {
9 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
10 | }
11 |
12 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
13 | if (flutterVersionCode == null) {
14 | flutterVersionCode = '1'
15 | }
16 |
17 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
18 | if (flutterVersionName == null) {
19 | flutterVersionName = '1.0'
20 | }
21 |
22 | def loadPropertiesFile(String fileName) {
23 | println(fileName)
24 | def properties = new Properties()
25 | def propertiesFile = rootProject.file(fileName)
26 | if (propertiesFile.exists()) {
27 | propertiesFile.withReader('UTF-8') { reader ->
28 | properties.load(reader)
29 | }
30 | }
31 | return properties
32 | }
33 |
34 | def getCurrentFlavor() {
35 | Gradle gradle = getGradle()
36 | String tskReqStr = gradle.getStartParameter().getTaskRequests().toString()
37 |
38 | Pattern pattern
39 | println(tskReqStr)
40 | if( tskReqStr.contains( "assemble" ) )
41 | pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
42 | else if( tskReqStr.contains("bundle") )
43 | pattern = Pattern.compile("bundle(\\w+)(Release|Debug)")
44 | else
45 | pattern = Pattern.compile("generate(\\w+)(Release|Debug)")
46 |
47 | Matcher matcher = pattern.matcher( tskReqStr )
48 |
49 | if( matcher.find() )
50 | return matcher.group(1).toLowerCase()
51 | else
52 | {
53 | println "NO MATCH FOUND"
54 | return ""
55 | }
56 | }
57 |
58 | apply plugin: 'com.android.application'
59 | apply plugin: 'kotlin-android'
60 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
61 |
62 | android {
63 |
64 | sourceSets {
65 | main.java.srcDirs += 'src/main/kotlin'
66 | }
67 |
68 | defaultConfig {
69 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
70 | applicationId "com.hellohasan.flutter_getx_template"
71 | minSdkVersion 23
72 | targetSdkVersion 33
73 | compileSdk 33
74 | versionCode flutterVersionCode.toInteger()
75 | versionName flutterVersionName
76 | }
77 |
78 | lintOptions {
79 | checkReleaseBuilds false
80 | }
81 |
82 | signingConfigs {
83 | release {
84 | keyAlias keystoreProperties['keyAlias']
85 | keyPassword keystoreProperties['password']
86 | storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
87 | storePassword keystoreProperties['password']
88 | }
89 | }
90 |
91 | buildTypes {
92 | release {
93 | signingConfig signingConfigs.release
94 | }
95 | }
96 |
97 | flavorDimensions "default"
98 | productFlavors {
99 | dev {
100 | dimension "default"
101 | applicationIdSuffix ".dev"
102 | }
103 | prod {
104 | dimension "default"
105 | }
106 | }
107 | }
108 |
109 | flutter {
110 | source '../..'
111 | target "lib/main_" + getCurrentFlavor() + ".dart"
112 | }
113 |
114 | dependencies {
115 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
116 | }
117 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
9 |
17 |
21 |
25 |
30 |
34 |
35 |
36 |
37 |
38 |
39 |
41 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/hellohasan/flutter_getx_template/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.hellohasan.flutter_getx_template
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 | -
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | -
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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.9.0'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.0.4'
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 | tasks.register("clean", 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 | #Sun Dec 12 12:34:09 BDT 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
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 |
--------------------------------------------------------------------------------
/fonts/Roboto-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/fonts/Roboto-Bold.ttf
--------------------------------------------------------------------------------
/fonts/Roboto-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/fonts/Roboto-Italic.ttf
--------------------------------------------------------------------------------
/fonts/Roboto-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/fonts/Roboto-Light.ttf
--------------------------------------------------------------------------------
/fonts/Roboto-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/fonts/Roboto-Medium.ttf
--------------------------------------------------------------------------------
/fonts/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/fonts/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/fonts/Roboto-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/fonts/Roboto-Thin.ttf
--------------------------------------------------------------------------------
/images/arrow_forward.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
41 |
--------------------------------------------------------------------------------
/images/ic_favorite.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
58 |
--------------------------------------------------------------------------------
/images/ic_font_size.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/images/ic_fork.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/images/ic_home.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
44 |
--------------------------------------------------------------------------------
/images/ic_language.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/ic_settings.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
50 |
--------------------------------------------------------------------------------
/images/ic_test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/images/ic_test.png
--------------------------------------------------------------------------------
/images/ic_theme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/images/ic_theme.png
--------------------------------------------------------------------------------
/images/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/images/launcher_icon.png
--------------------------------------------------------------------------------
/images/test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/images/test.jpg
--------------------------------------------------------------------------------
/images/test_jpeg.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/images/test_jpeg.jpeg
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/ephemeral/
22 | Flutter/app.flx
23 | Flutter/app.zip
24 | Flutter/flutter_assets/
25 | Flutter/flutter_export_environment.sh
26 | ServiceDefinitions.json
27 | Runner/GeneratedPluginRegistrant.*
28 |
29 | # Exceptions to above rules.
30 | !default.mode1v3
31 | !default.mode2v3
32 | !default.pbxuser
33 | !default.perspectivev3
34 |
--------------------------------------------------------------------------------
/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 | 11.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, '11.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 | end
41 | end
42 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Flutter (1.0.0)
3 | - fluttertoast (0.0.2):
4 | - Flutter
5 | - Toast
6 | - FMDB (2.7.5):
7 | - FMDB/standard (= 2.7.5)
8 | - FMDB/standard (2.7.5)
9 | - path_provider_foundation (0.0.1):
10 | - Flutter
11 | - FlutterMacOS
12 | - shared_preferences_foundation (0.0.1):
13 | - Flutter
14 | - FlutterMacOS
15 | - sqflite (0.0.3):
16 | - Flutter
17 | - FMDB (>= 2.7.5)
18 | - Toast (4.0.0)
19 |
20 | DEPENDENCIES:
21 | - Flutter (from `Flutter`)
22 | - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
23 | - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
24 | - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
25 | - sqflite (from `.symlinks/plugins/sqflite/ios`)
26 |
27 | SPEC REPOS:
28 | trunk:
29 | - FMDB
30 | - Toast
31 |
32 | EXTERNAL SOURCES:
33 | Flutter:
34 | :path: Flutter
35 | fluttertoast:
36 | :path: ".symlinks/plugins/fluttertoast/ios"
37 | path_provider_foundation:
38 | :path: ".symlinks/plugins/path_provider_foundation/darwin"
39 | shared_preferences_foundation:
40 | :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
41 | sqflite:
42 | :path: ".symlinks/plugins/sqflite/ios"
43 |
44 | SPEC CHECKSUMS:
45 | Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
46 | fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
47 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
48 | path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
49 | shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
50 | sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
51 | Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
52 |
53 | PODFILE CHECKSUM: 7368163408c647b7eb699d0d788ba6718e18fb8d
54 |
55 | COCOAPODS: 1.12.1
56 |
--------------------------------------------------------------------------------
/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 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/dev.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/prod.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hasancse91/flutter_getx_template/f1ebf2f6584497ab22313e8b17993ebd0f7a0a49/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-Debug.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_getx_template
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | NSBonjourServices
26 |
27 | _dartobservatory._tcp
28 |
29 | UILaunchStoryboardName
30 | LaunchScreen
31 | UIMainStoryboardFile
32 | Main
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 | UIViewControllerBasedStatusBarAppearance
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/ios/Runner/Info-Release.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_getx_template
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/l10n.yaml:
--------------------------------------------------------------------------------
1 | arb-dir: lib/l10n
2 | template-arb-file: app_en.arb
3 | output-localization-file: app_localizations.dart
--------------------------------------------------------------------------------
/lib/app/bindings/initial_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'local_source_bindings.dart';
4 | import 'remote_source_bindings.dart';
5 | import 'repository_bindings.dart';
6 |
7 | class InitialBinding implements Bindings {
8 | @override
9 | void dependencies() {
10 | RepositoryBindings().dependencies();
11 | RemoteSourceBindings().dependencies();
12 | LocalSourceBindings().dependencies();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/app/bindings/local_source_bindings.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/data/local/preference/preference_manager.dart';
4 | import '/app/data/local/preference/preference_manager_impl.dart';
5 |
6 | class LocalSourceBindings implements Bindings {
7 | @override
8 | void dependencies() {
9 | Get.lazyPut(
10 | () => PreferenceManagerImpl(),
11 | tag: (PreferenceManager).toString(),
12 | fenix: true,
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lib/app/bindings/remote_source_bindings.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/data/remote/github_remote_data_source.dart';
4 | import '/app/data/remote/github_remote_data_source_impl.dart';
5 |
6 | class RemoteSourceBindings implements Bindings {
7 | @override
8 | void dependencies() {
9 | Get.lazyPut(
10 | () => GithubRemoteDataSourceImpl(),
11 | tag: (GithubRemoteDataSource).toString(),
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/app/bindings/repository_bindings.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/data/repository/github_repository.dart';
4 | import '/app/data/repository/github_repository_impl.dart';
5 |
6 | class RepositoryBindings implements Bindings {
7 | @override
8 | void dependencies() {
9 | Get.lazyPut(
10 | () => GithubRepositoryImpl(),
11 | tag: (GithubRepository).toString(),
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/app/core/base/base_controller.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
4 | import 'package:get/get.dart';
5 | import 'package:logger/logger.dart';
6 |
7 | import '/app/core/model/page_state.dart';
8 | import '/app/network/exceptions/api_exception.dart';
9 | import '/app/network/exceptions/app_exception.dart';
10 | import '/app/network/exceptions/json_format_exception.dart';
11 | import '/app/network/exceptions/network_exception.dart';
12 | import '/app/network/exceptions/not_found_exception.dart';
13 | import '/app/network/exceptions/service_unavailable_exception.dart';
14 | import '/app/network/exceptions/unauthorize_exception.dart';
15 | import '/flavors/build_config.dart';
16 |
17 | abstract class BaseController extends GetxController {
18 | final Logger logger = BuildConfig.instance.config.logger;
19 |
20 | AppLocalizations get appLocalization => AppLocalizations.of(Get.context!)!;
21 |
22 | final logoutController = false.obs;
23 |
24 | //Reload the page
25 | final _refreshController = false.obs;
26 |
27 | refreshPage(bool refresh) => _refreshController(refresh);
28 |
29 | //Controls page state
30 | final _pageSateController = PageState.DEFAULT.obs;
31 |
32 | PageState get pageState => _pageSateController.value;
33 |
34 | updatePageState(PageState state) => _pageSateController(state);
35 |
36 | resetPageState() => _pageSateController(PageState.DEFAULT);
37 |
38 | showLoading() => updatePageState(PageState.LOADING);
39 |
40 | hideLoading() => resetPageState();
41 |
42 | final _messageController = ''.obs;
43 |
44 | String get message => _messageController.value;
45 |
46 | showMessage(String msg) => _messageController(msg);
47 |
48 | final _errorMessageController = ''.obs;
49 |
50 | String get errorMessage => _errorMessageController.value;
51 |
52 | showErrorMessage(String msg) {
53 | _errorMessageController(msg);
54 | }
55 |
56 | final _successMessageController = ''.obs;
57 |
58 | String get successMessage => _messageController.value;
59 |
60 | showSuccessMessage(String msg) => _successMessageController(msg);
61 |
62 | // ignore: long-parameter-list
63 | dynamic callDataService(
64 | Future future, {
65 | Function(Exception exception)? onError,
66 | Function(T response)? onSuccess,
67 | Function? onStart,
68 | Function? onComplete,
69 | }) async {
70 | Exception? _exception;
71 |
72 | onStart == null ? showLoading() : onStart();
73 |
74 | try {
75 | final T response = await future;
76 |
77 | if (onSuccess != null) onSuccess(response);
78 |
79 | onComplete == null ? hideLoading() : onComplete();
80 |
81 | return response;
82 | } on ServiceUnavailableException catch (exception) {
83 | _exception = exception;
84 | showErrorMessage(exception.message);
85 | } on UnauthorizedException catch (exception) {
86 | _exception = exception;
87 | showErrorMessage(exception.message);
88 | } on TimeoutException catch (exception) {
89 | _exception = exception;
90 | showErrorMessage(exception.message ?? 'Timeout exception');
91 | } on NetworkException catch (exception) {
92 | _exception = exception;
93 | showErrorMessage(exception.message);
94 | } on JsonFormatException catch (exception) {
95 | _exception = exception;
96 | showErrorMessage(exception.message);
97 | } on NotFoundException catch (exception) {
98 | _exception = exception;
99 | showErrorMessage(exception.message);
100 | } on ApiException catch (exception) {
101 | _exception = exception;
102 | } on AppException catch (exception) {
103 | _exception = exception;
104 | showErrorMessage(exception.message);
105 | } catch (error) {
106 | _exception = AppException(message: "$error");
107 | logger.e("Controller>>>>>> error $error");
108 | }
109 |
110 | if (onError != null) onError(_exception);
111 |
112 | onComplete == null ? hideLoading() : onComplete();
113 | }
114 |
115 | @override
116 | void onClose() {
117 | _messageController.close();
118 | _refreshController.close();
119 | _pageSateController.close();
120 | super.onClose();
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/lib/app/core/base/base_remote_source.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:get/get_connect/http/src/status/http_status.dart';
3 |
4 | import '/app/network/dio_provider.dart';
5 | import '/app/network/error_handlers.dart';
6 | import '/app/network/exceptions/base_exception.dart';
7 | import '/flavors/build_config.dart';
8 |
9 | abstract class BaseRemoteSource {
10 | Dio get dioClient => DioProvider.dioWithHeaderToken;
11 |
12 | final logger = BuildConfig.instance.config.logger;
13 |
14 | Future> callApiWithErrorParser(Future> api) async {
15 | try {
16 | Response response = await api;
17 |
18 | if (response.statusCode != HttpStatus.ok ||
19 | (response.data as Map)['statusCode'] !=
20 | HttpStatus.ok) {
21 | // TODO
22 | }
23 |
24 | return response;
25 | } on DioError catch (dioError) {
26 | Exception exception = handleDioError(dioError);
27 | logger.e(
28 | "Throwing error from repository: >>>>>>> $exception : ${(exception as BaseException).message}");
29 | throw exception;
30 | } catch (error) {
31 | logger.e("Generic error: >>>>>>> $error");
32 |
33 | if (error is BaseException) {
34 | rethrow;
35 | }
36 |
37 | throw handleError("$error");
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/app/core/base/base_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
4 | import 'package:fluttertoast/fluttertoast.dart';
5 | import 'package:get/get.dart';
6 | import 'package:logger/logger.dart';
7 |
8 | import '/app/core/base/base_controller.dart';
9 | import '/app/core/model/page_state.dart';
10 | import '/app/core/values/app_colors.dart';
11 | import '/app/core/widget/loading.dart';
12 | import '/flavors/build_config.dart';
13 |
14 | abstract class BaseView
15 | extends GetView {
16 | final GlobalKey globalKey = GlobalKey();
17 |
18 | AppLocalizations get appLocalization => AppLocalizations.of(Get.context!)!;
19 |
20 | final Logger logger = BuildConfig.instance.config.logger;
21 |
22 | Widget body(BuildContext context);
23 |
24 | PreferredSizeWidget? appBar(BuildContext context);
25 |
26 | @override
27 | Widget build(BuildContext context) {
28 | return GestureDetector(
29 | child: Stack(
30 | children: [
31 | annotatedRegion(context),
32 | Obx(() => controller.pageState == PageState.LOADING
33 | ? _showLoading()
34 | : Container()),
35 | Obx(() => controller.errorMessage.isNotEmpty
36 | ? showErrorSnackBar(controller.errorMessage)
37 | : Container()),
38 | Container(),
39 | ],
40 | ),
41 | );
42 | }
43 |
44 | Widget annotatedRegion(BuildContext context) {
45 | return AnnotatedRegion(
46 | value: SystemUiOverlayStyle(
47 | //Status bar color for android
48 | statusBarColor: statusBarColor(),
49 | statusBarIconBrightness: Brightness.dark,
50 | ),
51 | child: Material(
52 | color: Colors.transparent,
53 | child: pageScaffold(context),
54 | ),
55 | );
56 | }
57 |
58 | Widget pageScaffold(BuildContext context) {
59 | return Scaffold(
60 | //sets ios status bar color
61 | backgroundColor: pageBackgroundColor(),
62 | key: globalKey,
63 | appBar: appBar(context),
64 | floatingActionButton: floatingActionButton(),
65 | body: pageContent(context),
66 | bottomNavigationBar: bottomNavigationBar(),
67 | drawer: drawer(),
68 | );
69 | }
70 |
71 | Widget pageContent(BuildContext context) {
72 | return SafeArea(
73 | child: body(context),
74 | );
75 | }
76 |
77 | Widget showErrorSnackBar(String message) {
78 | final snackBar = SnackBar(content: Text(message));
79 | WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
80 | ScaffoldMessenger.of(Get.context!).showSnackBar(snackBar);
81 | });
82 |
83 | return Container();
84 | }
85 |
86 | void showToast(String message) {
87 | Fluttertoast.showToast(
88 | msg: message,
89 | toastLength: Toast.LENGTH_SHORT,
90 | timeInSecForIosWeb: 1
91 | );
92 | }
93 |
94 | Color pageBackgroundColor() {
95 | return AppColors.pageBackground;
96 | }
97 |
98 | Color statusBarColor() {
99 | return AppColors.pageBackground;
100 | }
101 |
102 | Widget? floatingActionButton() {
103 | return null;
104 | }
105 |
106 | Widget? bottomNavigationBar() {
107 | return null;
108 | }
109 |
110 | Widget? drawer() {
111 | return null;
112 | }
113 |
114 | Widget _showLoading() {
115 | return const Loading();
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/lib/app/core/base/base_widget_mixin.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
3 | import 'package:get/get.dart';
4 | import 'package:logger/logger.dart';
5 |
6 | import '/flavors/build_config.dart';
7 |
8 | mixin BaseWidgetMixin on StatelessWidget {
9 | AppLocalizations get appLocalization => AppLocalizations.of(Get.context!)!;
10 | final Logger logger = BuildConfig.instance.config.logger;
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Container(
15 | child: body(context),
16 | );
17 | }
18 |
19 | Widget body(BuildContext context);
20 | }
21 |
--------------------------------------------------------------------------------
/lib/app/core/base/paging_controller.dart:
--------------------------------------------------------------------------------
1 | import '/app/core/values/app_values.dart';
2 |
3 | class PagingController {
4 | List listItems = [];
5 | int pageNumber = AppValues.defaultPageNumber;
6 | bool isLoadingPage = false;
7 | bool endOfList = false;
8 |
9 | initRefresh() {
10 | listItems = [];
11 | pageNumber = AppValues.defaultPageNumber;
12 | isLoadingPage = false;
13 | endOfList = false;
14 | }
15 |
16 | bool canLoadNextPage() {
17 | return !isLoadingPage && !endOfList;
18 | }
19 |
20 | appendPage(List items) {
21 | listItems.addAll(items);
22 | pageNumber++;
23 | }
24 |
25 | appendLastPage(List items) {
26 | listItems.addAll(items);
27 | endOfList = true;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/app/core/model/github_search_query_param.dart:
--------------------------------------------------------------------------------
1 | import '/app/core/values/app_values.dart';
2 |
3 | class GithubSearchQueryParam {
4 | String searchKeyWord;
5 | int perPage;
6 | int pageNumber;
7 |
8 | GithubSearchQueryParam({
9 | required this.searchKeyWord,
10 | this.perPage = AppValues.defaultPageSize,
11 | this.pageNumber = AppValues.defaultPageNumber,
12 | });
13 |
14 | Map toJson() {
15 | final Map data = {};
16 | data['q'] = searchKeyWord;
17 | data['per_page'] = perPage;
18 | data['page'] = pageNumber;
19 |
20 | return data;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/app/core/model/page_state.dart:
--------------------------------------------------------------------------------
1 | enum PageState {
2 | DEFAULT,
3 | LOADING,
4 | SUCCESS,
5 | FAILED,
6 | UPDATED,
7 | CREATED,
8 | NO_INTERNET,
9 | MESSAGE,
10 | UNAUTHORIZED,
11 | }
12 |
--------------------------------------------------------------------------------
/lib/app/core/model/page_status.dart:
--------------------------------------------------------------------------------
1 | import '/app/core/model/page_state.dart';
2 |
3 | class PageStatus {
4 | final bool isSuccess;
5 | final String message;
6 | final String title;
7 | final String nextRoute;
8 | final PageState pageState;
9 |
10 | PageStatus({
11 | this.isSuccess = false,
12 | this.title = "",
13 | this.message = "",
14 | this.nextRoute = "",
15 | this.pageState = PageState.DEFAULT,
16 | });
17 | }
18 |
--------------------------------------------------------------------------------
/lib/app/core/utils/debouncer.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | import '/app/core/values/app_values.dart';
6 |
7 | class Debouncer {
8 | final int milliseconds;
9 | VoidCallback? action;
10 | Timer? _timer;
11 |
12 | Debouncer({this.milliseconds = AppValues.defaultDebounceTimeInMilliSeconds});
13 |
14 | run(VoidCallback action) {
15 | if (_timer != null) {
16 | _timer!.cancel();
17 | }
18 | _timer = Timer(Duration(milliseconds: milliseconds), action);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/app/core/values/app_colors.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | abstract class AppColors {
4 | static const Color pageBackground = Color(0xFFFAFBFD);
5 | static const Color statusBarColor = Color(0xFF38686A);
6 | static const Color appBarColor = Color(0xFF38686A);
7 | static const Color appBarIconColor = Color(0xFFFFFFFF);
8 | static const Color appBarTextColor = Color(0xFFFFFFFF);
9 |
10 | static const Color centerTextColor = Colors.grey;
11 | static const MaterialColor colorPrimarySwatch = Colors.cyan;
12 | static const Color colorPrimary = Color(0xFF38686A);
13 | static const Color colorAccent = Color(0xFF38686A);
14 | static const Color colorLightGreen = Color(0xFF00EFA7);
15 | static const Color colorWhite = Color(0xFFFFFFFF);
16 | static const Color lightGreyColor = Color(0xFFC4C4C4);
17 | static const Color errorColor = Color(0xFFAB0B0B);
18 | static const Color colorDark = Color(0xFF323232);
19 |
20 | static const Color buttonBgColor = colorPrimary;
21 | static const Color disabledButtonBgColor = Color(0xFFBFBFC0);
22 | static const Color defaultRippleColor = Color(0x0338686A);
23 |
24 | static const Color textColorPrimary = Color(0xFF323232);
25 | static const Color textColorSecondary = Color(0xFF9FA4B0);
26 | static const Color textColorTag = colorPrimary;
27 | static const Color textColorGreyLight = Color(0xFFABABAB);
28 | static const Color textColorGreyDark = Color(0xFF979797);
29 | static const Color textColorBlueGreyDark = Color(0xFF939699);
30 | static const Color textColorCyan = Color(0xFF38686A);
31 | static const Color textColorWhite = Color(0xFFFFFFFF);
32 | static Color searchFieldTextColor = const Color(0xFF323232).withOpacity(0.5);
33 |
34 | static const Color iconColorDefault = Colors.grey;
35 |
36 | static Color barrierColor = const Color(0xFF000000).withOpacity(0.5);
37 |
38 | static Color timelineDividerColor = const Color(0x5438686A);
39 |
40 | static const Color gradientStartColor = Colors.black87;
41 | static const Color gradientEndColor = Colors.transparent;
42 | static const Color silverAppBarOverlayColor = Color(0x80323232);
43 |
44 | static const Color switchActiveColor = colorPrimary;
45 | static const Color switchInactiveColor = Color(0xFFABABAB);
46 | static Color elevatedContainerColorOpacity = Colors.grey.withOpacity(0.5);
47 | static const Color suffixImageColor = Colors.grey;
48 | }
49 |
--------------------------------------------------------------------------------
/lib/app/core/values/app_values.dart:
--------------------------------------------------------------------------------
1 | abstract class AppValues {
2 | static const double padding = 16;
3 | static const double padding_zero = 0;
4 | static const double halfPadding = 8;
5 | static const double smallPadding = 10;
6 | static const double extraSmallPadding = 6;
7 | static const double largePadding = 24;
8 | static const double extraLargePadding = 32;
9 | static const double padding_4 = 4;
10 | static const double padding_2 = 2;
11 | static const double padding_3 = 3;
12 | static const double buttonVerticalPadding = 12;
13 |
14 | static const double margin = 16;
15 | static const double margin_zero = 0;
16 | static const double smallMargin = 8;
17 | static const double extraSmallMargin = 6;
18 | static const double largeMargin = 24;
19 | static const double margin_40 = 40;
20 | static const double margin_32 = 32;
21 | static const double margin_18 = 18;
22 | static const double margin_2 = 2;
23 | static const double margin_4 = 4;
24 | static const double margin_6 = 6;
25 | static const double margin_12 = 12;
26 | static const double margin_10 = 10;
27 | static const double margin_30 = 30;
28 | static const double margin_20 = 20;
29 | static const double extraLargeMargin = 36;
30 | static const double marginBelowVerticalLine = 64;
31 | static const double extraLargeSpacing = 96;
32 |
33 | static const double radius = 16;
34 | static const double radius_zero = 0;
35 | static const double smallRadius = 8;
36 | static const double radius_6 = 6;
37 | static const double radius_12 = 12;
38 | static const double largeRadius = 24;
39 | static const double roundedButtonRadius = 24;
40 | static const double extraLargeRadius = 36;
41 |
42 | static const double elevation = 16;
43 | static const double smallElevation = 8;
44 | static const double extraSmallElevation = 4;
45 | static const double largeElevation = 24;
46 |
47 | static const double circularImageDefaultSize = 90;
48 | static const double circularImageSize_30 = 30;
49 | static const double circularImageDefaultBorderSize = 0;
50 | static const double circularImageDefaultElevation = 0;
51 | static const double momentThumbnailDefaultSize = 80;
52 | static const double momentSmallThumbnailDefaultSize = 32;
53 | static const double collectionThumbnailDefaultSize = 150;
54 | static const double defaultViewPortFraction = 0.9;
55 | static const int defaultAnimationDuration = 300;
56 | static const double listBottomEmptySpace = 200;
57 | static const double maxButtonWidth = 496;
58 | static const double stackedImageDefaultBorderSize = 4;
59 | static const double stackedImageDefaultSpaceFactor = 0.4;
60 | static const double stackedImageDefaultSize = 30;
61 |
62 | static const double iconDefaultSize = 24;
63 | static const double emoticonDefaultSize = 22;
64 | static const double iconSize_20 = 20;
65 | static const double iconSize_22 = 22;
66 | static const double iconSize_18 = 18;
67 | static const double iconSmallSize = 16;
68 | static const double iconSmallerSize = 12;
69 | static const double iconSize_14 = 14;
70 | static const double iconSize_28 = 28;
71 | static const double iconLargeSize = 36;
72 | static const double iconExtraLargerSize = 96;
73 | static const double appBarIconSize = 32;
74 |
75 | static const double customAppBarSize = 144.0;
76 | static const double collapsedAppBarSize = 70.0;
77 |
78 | static const int loggerLineLength = 120;
79 | static const int loggerErrorMethodCount = 8;
80 | static const int loggerMethodCount = 2;
81 |
82 | static const double fullViewPort = 1;
83 | static const double indicatorDefaultSize = 8;
84 | static const double indicatorShadowBlurRadius = 1;
85 | static const double indicatorShadowSpreadRadius = 0;
86 | static const double appbarActionRippleRadius = 50;
87 | static const double activeIndicatorSize = 8;
88 | static const double inactiveIndicatorSize = 10;
89 | static const double datePickerHeightOnIos = 270;
90 | static const int maxCharacterCountOfQuote = 108;
91 | static const double barrierColorOpacity = 0.4;
92 |
93 | static const int defaultPageSize = 10;
94 | static const int defaultPageNumber = 1;
95 | static const int defaultDebounceTimeInMilliSeconds = 1000;
96 | static const int defaultThrottleTimeInMilliSeconds = 500;
97 |
98 | static const double height_16 = 16;
99 | }
100 |
--------------------------------------------------------------------------------
/lib/app/core/values/text_styles.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '/app/core/values/app_colors.dart';
4 |
5 | const centerTextStyle = TextStyle(
6 | fontSize: 28,
7 | fontWeight: FontWeight.bold,
8 | color: AppColors.centerTextColor,
9 | );
10 |
11 | const errorTextStyle = TextStyle(
12 | fontSize: 12,
13 | fontWeight: FontWeight.w400,
14 | color: AppColors.errorColor,
15 | );
16 |
17 | const greyDarkTextStyle = TextStyle(
18 | fontSize: 14,
19 | fontWeight: FontWeight.w400,
20 | color: AppColors.textColorGreyDark,
21 | height: 1.45);
22 |
23 | const primaryColorSubtitleStyle = TextStyle(
24 | fontSize: 14,
25 | fontWeight: FontWeight.w400,
26 | color: AppColors.colorPrimary,
27 | height: 1.45);
28 |
29 | const whiteText16 = TextStyle(
30 | fontSize: 16,
31 | fontWeight: FontWeight.w400,
32 | color: Colors.white,
33 | );
34 |
35 | const whiteText18 = TextStyle(
36 | fontSize: 18,
37 | fontWeight: FontWeight.w400,
38 | color: Colors.white,
39 | );
40 |
41 | const whiteText32 = TextStyle(
42 | fontSize: 32,
43 | fontWeight: FontWeight.w400,
44 | color: Colors.white,
45 | );
46 |
47 | const cyanText16 = TextStyle(
48 | fontSize: 16,
49 | fontWeight: FontWeight.w400,
50 | color: AppColors.textColorCyan,
51 | );
52 |
53 | const cyanText32 = TextStyle(
54 | fontSize: 32,
55 | fontWeight: FontWeight.w400,
56 | color: AppColors.textColorCyan,
57 | );
58 |
59 | const dialogSubtitle = TextStyle(
60 | fontSize: 16,
61 | fontWeight: FontWeight.w400,
62 | color: AppColors.textColorPrimary,
63 | );
64 |
65 | const labelStyle = TextStyle(
66 | fontSize: 18,
67 | fontWeight: FontWeight.w400,
68 | height: 1.8,
69 | );
70 |
71 | final labelStylePrimaryTextColor = labelStyle.copyWith(
72 | color: AppColors.textColorPrimary,
73 | height: 1,
74 | );
75 |
76 | final labelStyleAppPrimaryColor = labelStyle.copyWith(
77 | color: AppColors.colorPrimary,
78 | height: 1,
79 | );
80 |
81 | final labelStyleGrey =
82 | labelStyle.copyWith(color: const Color(0xFF323232).withOpacity(0.5));
83 |
84 | final labelCyanStyle = labelStyle.copyWith(color: AppColors.textColorCyan);
85 |
86 | const labelStyleWhite = TextStyle(
87 | fontSize: 18,
88 | fontWeight: FontWeight.w400,
89 | height: 1.8,
90 | color: Colors.white,
91 | );
92 |
93 | const appBarSubtitleStyle = TextStyle(
94 | fontSize: 16,
95 | fontWeight: FontWeight.w500,
96 | height: 1.25,
97 | color: AppColors.colorWhite);
98 |
99 | const cardTitleStyle = TextStyle(
100 | fontSize: 20,
101 | fontWeight: FontWeight.w500,
102 | height: 1.2,
103 | color: AppColors.textColorPrimary);
104 |
105 | const cardTitleCyanStyle = TextStyle(
106 | fontSize: 20,
107 | fontWeight: FontWeight.w500,
108 | color: AppColors.colorPrimary,
109 | );
110 |
111 | const cardSubtitleStyle = TextStyle(
112 | fontSize: 14,
113 | fontWeight: FontWeight.w500,
114 | height: 1.2,
115 | color: AppColors.textColorGreyLight);
116 |
117 | const titleStyle = TextStyle(
118 | fontSize: 18,
119 | fontWeight: FontWeight.w500,
120 | height: 1.34,
121 | );
122 |
123 | const settingsItemStyle = TextStyle(
124 | fontSize: 16,
125 | fontWeight: FontWeight.w400,
126 | );
127 |
128 | final cardTagStyle = titleStyle.copyWith(color: AppColors.textColorGreyDark);
129 |
130 | const titleStyleWhite = TextStyle(
131 | fontSize: 18, fontWeight: FontWeight.w500, color: AppColors.colorWhite);
132 |
133 | const inputFieldLabelStyle = TextStyle(
134 | fontSize: 18,
135 | fontWeight: FontWeight.w500,
136 | height: 1.34,
137 | color: AppColors.textColorPrimary,
138 | );
139 |
140 | const cardSmallTagStyle = TextStyle(
141 | fontSize: 14,
142 | fontWeight: FontWeight.w500,
143 | height: 1.2,
144 | color: AppColors.textColorGreyDark);
145 |
146 | const pageTitleStyle = TextStyle(
147 | fontSize: 18,
148 | fontWeight: FontWeight.w600,
149 | height: 1.15,
150 | color: AppColors.appBarTextColor);
151 |
152 | final pageTitleBlackStyle =
153 | pageTitleStyle.copyWith(color: AppColors.textColorPrimary);
154 |
155 | const appBarActionTextStyle = TextStyle(
156 | fontSize: 16,
157 | fontWeight: FontWeight.w600,
158 | color: AppColors.colorPrimary,
159 | );
160 |
161 | const pageTitleWhiteStyle = TextStyle(
162 | fontSize: 28,
163 | fontWeight: FontWeight.w600,
164 | height: 1.15,
165 | color: AppColors.colorWhite);
166 |
167 | const extraBigTitleStyle = TextStyle(
168 | fontSize: 40,
169 | fontWeight: FontWeight.w600,
170 | height: 1.12,
171 | );
172 |
173 | final extraBigTitleCyanStyle =
174 | extraBigTitleStyle.copyWith(color: AppColors.textColorCyan);
175 |
176 | const bigTitleStyle = TextStyle(
177 | fontSize: 28,
178 | fontWeight: FontWeight.w700,
179 | height: 1.15,
180 | );
181 |
182 | const mediumTitleStyle = TextStyle(
183 | fontSize: 24,
184 | fontWeight: FontWeight.w500,
185 | height: 1.15,
186 | );
187 |
188 | const descriptionTextStyle = TextStyle(
189 | fontSize: 16,
190 | );
191 |
192 | final bigTitleCyanStyle =
193 | bigTitleStyle.copyWith(color: AppColors.textColorCyan);
194 |
195 | const bigTitleWhiteStyle = TextStyle(
196 | fontSize: 28,
197 | fontWeight: FontWeight.w700,
198 | height: 1.15,
199 | color: Colors.white,
200 | );
201 |
202 | const boldTitleStyle = TextStyle(
203 | fontSize: 18,
204 | fontWeight: FontWeight.w700,
205 | height: 1.34,
206 | );
207 | final boldTitleWhiteStyle =
208 | boldTitleStyle.copyWith(color: AppColors.textColorWhite);
209 |
210 | final boldTitleCyanStyle =
211 | boldTitleStyle.copyWith(color: AppColors.textColorCyan);
212 |
213 | final boldTitleSecondaryColorStyle =
214 | boldTitleStyle.copyWith(color: AppColors.textColorSecondary);
215 |
216 | final boldTitlePrimaryColorStyle =
217 | boldTitleStyle.copyWith(color: AppColors.colorPrimary);
218 |
--------------------------------------------------------------------------------
/lib/app/core/widget/app_bar_title.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '/app/core/values/text_styles.dart';
4 |
5 | class AppBarTitle extends StatelessWidget {
6 | final String text;
7 |
8 | const AppBarTitle({Key? key, required this.text}) : super(key: key);
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Text(
13 | text,
14 | style: pageTitleStyle,
15 | textAlign: TextAlign.center,
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/app/core/widget/asset_image_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_svg/flutter_svg.dart';
3 |
4 | class AssetImageView extends StatelessWidget {
5 | const AssetImageView({
6 | Key? key,
7 | required this.fileName,
8 | this.height,
9 | this.width,
10 | this.color,
11 | this.scale,
12 | this.fit,
13 | }) : super(key: key);
14 |
15 | final String fileName;
16 | final double? height;
17 | final double? width;
18 | final Color? color;
19 | final double? scale;
20 | final BoxFit? fit;
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return _getView();
25 | }
26 |
27 | Widget _getView() {
28 | String mimType = fileName.split(".").last;
29 | String path = "images/$fileName";
30 |
31 | if (mimType.isEmpty) {
32 | return Icon(
33 | Icons.image_not_supported_outlined,
34 | size: width,
35 | color: color,
36 | );
37 | }
38 |
39 | switch (mimType) {
40 | case "svg":
41 | return SvgPicture.asset(
42 | path,
43 | height: height,
44 | width: width,
45 | colorFilter: color == null? null: ColorFilter.mode(color ?? Colors.black, BlendMode.srcIn),
46 | fit: fit ?? BoxFit.contain,
47 | );
48 | case "png":
49 | case "jpg":
50 | case "jpeg":
51 | return Image.asset(
52 | path,
53 | height: height,
54 | width: width,
55 | color: color,
56 | scale: scale,
57 | );
58 | default:
59 | return Icon(
60 | Icons.image_not_supported_outlined,
61 | size: width,
62 | color: color,
63 | );
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib/app/core/widget/custom_app_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '/app/core/values/app_colors.dart';
4 | import '/app/core/widget/app_bar_title.dart';
5 |
6 | //Default appbar customized with the design of our app
7 | class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
8 | final String appBarTitleText;
9 | final List? actions;
10 | final bool isBackButtonEnabled;
11 |
12 | CustomAppBar({
13 | Key? key,
14 | required this.appBarTitleText,
15 | this.actions,
16 | this.isBackButtonEnabled = true,
17 | }) : super(key: key);
18 |
19 | @override
20 | Size get preferredSize => AppBar().preferredSize;
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return AppBar(
25 | backgroundColor: AppColors.appBarColor,
26 | centerTitle: true,
27 | elevation: 0,
28 | automaticallyImplyLeading: isBackButtonEnabled,
29 | actions: actions,
30 | iconTheme: const IconThemeData(color: AppColors.appBarIconColor),
31 | title: AppBarTitle(text: appBarTitleText),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/app/core/widget/elevated_container.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '/app/core/values/app_colors.dart';
4 | import '/app/core/values/app_values.dart';
5 |
6 | class ElevatedContainer extends StatelessWidget {
7 | final Widget child;
8 | final Color bgColor;
9 | final EdgeInsetsGeometry? padding;
10 | final double borderRadius;
11 |
12 | const ElevatedContainer({
13 | Key? key,
14 | required this.child,
15 | this.bgColor = AppColors.pageBackground,
16 | this.padding,
17 | this.borderRadius = AppValues.smallRadius,
18 | }) : super(key: key);
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return Container(
23 | padding: padding,
24 | decoration: BoxDecoration(
25 | borderRadius: BorderRadius.circular(borderRadius),
26 | boxShadow: [
27 | BoxShadow(
28 | color: AppColors.elevatedContainerColorOpacity,
29 | spreadRadius: 3,
30 | blurRadius: 8,
31 | offset: const Offset(0, 3), // changes position of shadow
32 | ),
33 | ],
34 | color: AppColors.pageBackground),
35 | child: child,
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/app/core/widget/icon_text_widgets.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '/app/core/values/app_values.dart';
4 | import '/app/core/widget/asset_image_view.dart';
5 |
6 | class IconTextWidget extends StatelessWidget {
7 | const IconTextWidget({
8 | Key? key,
9 | this.fileName,
10 | this.icon,
11 | this.value,
12 | this.height,
13 | this.width,
14 | this.size,
15 | this.color,
16 | }) : super(key: key);
17 |
18 | final String? fileName;
19 | final IconData? icon;
20 | final String? value;
21 | final double? height;
22 | final double? width;
23 | final double? size;
24 | final Color? color;
25 |
26 | @override
27 | Widget build(BuildContext context) {
28 | if (fileName != null) {
29 | return _getImage(fileName!);
30 | } else if (icon != null) {
31 | return _getIcon(icon!);
32 | } else {
33 | return _getIcon(Icons.image_not_supported_outlined);
34 | }
35 | }
36 |
37 | Widget _getIcon(IconData iconData) {
38 | return Expanded(
39 | child: Row(
40 | children: [
41 | Icon(icon, size: size, color: color),
42 | const SizedBox(width: AppValues.margin_2),
43 | if (value != null) Text(value!, style: TextStyle(color: color)),
44 | ],
45 | ),
46 | );
47 | }
48 |
49 | Widget _getImage(String fileName) {
50 | return Expanded(
51 | child: Row(
52 | children: [
53 | AssetImageView(
54 | fileName: fileName,
55 | height: height,
56 | width: width,
57 | color: color,
58 | ),
59 | const SizedBox(width: AppValues.margin_2),
60 | if (value != null) Text(value!, style: TextStyle(color: color)),
61 | ],
62 | ),
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/lib/app/core/widget/loading.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '/app/core/values/app_colors.dart';
4 | import '/app/core/values/app_values.dart';
5 | import '/app/core/widget/elevated_container.dart';
6 |
7 | class Loading extends StatelessWidget {
8 | const Loading({Key? key}) : super(key: key);
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return const Center(
13 | child: ElevatedContainer(
14 | padding: EdgeInsets.all(AppValues.margin),
15 | child: CircularProgressIndicator(
16 | color: AppColors.colorPrimary,
17 | ),
18 | ),
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/app/core/widget/paging_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/rendering.dart';
3 |
4 | import '/app/core/utils/debouncer.dart';
5 | import '/app/core/values/app_values.dart';
6 |
7 | ///ignore: must_be_immutable
8 | class PagingView extends StatelessWidget {
9 | final Widget child;
10 | final Function() onLoadNextPage;
11 | final Future Function()? onRefresh;
12 |
13 | ScrollController? scrollController;
14 |
15 | late final _debouncer = Debouncer(milliseconds: 500);
16 |
17 | PagingView({
18 | Key? key,
19 | required this.child,
20 | required this.onLoadNextPage,
21 | this.onRefresh,
22 | this.scrollController,
23 | }) : super(key: key) {
24 | scrollController ??= ScrollController();
25 | }
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | return NotificationListener(
30 | onNotification: (ScrollNotification scrollInfo) {
31 | if (scrollController != null) {
32 | var triggerFetchMoreSize =
33 | 0.75 * scrollController!.position.maxScrollExtent;
34 |
35 | if (scrollController!.position.pixels >= triggerFetchMoreSize &&
36 | (scrollController!.position.userScrollDirection ==
37 | ScrollDirection.reverse)) {
38 | _debouncer.run(() {
39 | onLoadNextPage();
40 | });
41 | }
42 | }
43 |
44 | return true;
45 | },
46 | child: onRefresh == null
47 | ? _getScrollableView()
48 | : RefreshIndicator(
49 | child: _getScrollableView(),
50 | onRefresh: onRefresh!,
51 | ),
52 | );
53 | }
54 |
55 | _getScrollableView() {
56 | return SingleChildScrollView(
57 | controller: scrollController,
58 | child: Column(
59 | children: [
60 | child,
61 | const SizedBox(height: AppValues.listBottomEmptySpace),
62 | ],
63 | ),
64 | );
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib/app/core/widget/ripple.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_getx_template/app/core/values/app_colors.dart';
3 | import 'package:flutter_getx_template/app/core/values/app_values.dart';
4 |
5 | class Ripple extends StatelessWidget {
6 | final Function()? onTap;
7 | final Widget? child;
8 | final Color rippleColor;
9 | final double rippleRadius;
10 |
11 | const Ripple({
12 | Key? key,
13 | this.child,
14 | required this.onTap,
15 | this.rippleColor = AppColors.defaultRippleColor,
16 | this.rippleRadius = AppValues.smallRadius,
17 | }) : super(key: key);
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return Material(
22 | color: Colors.transparent,
23 | child: InkWell(
24 | borderRadius: BorderRadius.circular(rippleRadius),
25 | highlightColor: rippleColor,
26 | onTap: onTap,
27 | child: child,
28 | ),
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/app/data/local/db/db.txt:
--------------------------------------------------------------------------------
1 | DB related files will be placed in this package
--------------------------------------------------------------------------------
/lib/app/data/local/preference/preference_manager.dart:
--------------------------------------------------------------------------------
1 | abstract class PreferenceManager {
2 | static const keyToken = "token";
3 |
4 | Future getString(String key, {String defaultValue = ""});
5 |
6 | Future setString(String key, String value);
7 |
8 | Future getInt(String key, {int defaultValue = 0});
9 |
10 | Future setInt(String key, int value);
11 |
12 | Future getDouble(String key, {double defaultValue = 0.0});
13 |
14 | Future setDouble(String key, double value);
15 |
16 | Future getBool(String key, {bool defaultValue = false});
17 |
18 | Future setBool(String key, bool value);
19 |
20 | Future> getStringList(String key,
21 | {List defaultValue = const []});
22 |
23 | Future setStringList(String key, List value);
24 |
25 | Future remove(String key);
26 |
27 | Future clear();
28 | }
29 |
--------------------------------------------------------------------------------
/lib/app/data/local/preference/preference_manager_impl.dart:
--------------------------------------------------------------------------------
1 | import 'package:shared_preferences/shared_preferences.dart';
2 |
3 | import '/app/data/local/preference/preference_manager.dart';
4 |
5 | class PreferenceManagerImpl implements PreferenceManager {
6 | final _preference = SharedPreferences.getInstance();
7 |
8 | @override
9 | Future getString(String key, {String defaultValue = ""}) {
10 | return _preference
11 | .then((preference) => preference.getString(key) ?? defaultValue);
12 | }
13 |
14 | @override
15 | Future setString(String key, String value) {
16 | return _preference.then((preference) => preference.setString(key, value));
17 | }
18 |
19 | @override
20 | Future getInt(String key, {int defaultValue = 0}) {
21 | return _preference
22 | .then((preference) => preference.getInt(key) ?? defaultValue);
23 | }
24 |
25 | @override
26 | Future setInt(String key, int value) {
27 | return _preference.then((preference) => preference.setInt(key, value));
28 | }
29 |
30 | @override
31 | Future getDouble(String key, {double defaultValue = 0.0}) {
32 | return _preference
33 | .then((preference) => preference.getDouble(key) ?? defaultValue);
34 | }
35 |
36 | @override
37 | Future setDouble(String key, double value) {
38 | return _preference.then((preference) => preference.setDouble(key, value));
39 | }
40 |
41 | @override
42 | Future getBool(String key, {bool defaultValue = false}) {
43 | return _preference
44 | .then((preference) => preference.getBool(key) ?? defaultValue);
45 | }
46 |
47 | @override
48 | Future setBool(String key, bool value) {
49 | return _preference.then((preference) => preference.setBool(key, value));
50 | }
51 |
52 | @override
53 | Future> getStringList(String key,
54 | {List defaultValue = const []}) {
55 | return _preference
56 | .then((preference) => preference.getStringList(key) ?? defaultValue);
57 | }
58 |
59 | @override
60 | Future setStringList(String key, List value) {
61 | return _preference
62 | .then((preference) => preference.setStringList(key, value));
63 | }
64 |
65 | @override
66 | Future remove(String key) {
67 | return _preference.then((preference) => preference.remove(key));
68 | }
69 |
70 | @override
71 | Future clear() {
72 | return _preference.then((preference) => preference.clear());
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/app/data/model/github_project_search_response.dart:
--------------------------------------------------------------------------------
1 | class GithubProjectSearchResponse {
2 | GithubProjectSearchResponse({
3 | this.totalCount,
4 | this.incompleteResults,
5 | this.items,
6 | });
7 |
8 | GithubProjectSearchResponse.fromJson(dynamic json) {
9 | totalCount = json['total_count'];
10 | incompleteResults = json['incomplete_results'];
11 | if (json['items'] != null) {
12 | items = [];
13 | json['items'].forEach((v) {
14 | items?.add(Item.fromJson(v));
15 | });
16 | }
17 | }
18 |
19 | int? totalCount;
20 | bool? incompleteResults;
21 | List- ? items;
22 |
23 | Map toJson() {
24 | final map = {};
25 | map['total_count'] = totalCount;
26 | map['incomplete_results'] = incompleteResults;
27 | if (items != null) {
28 | map['items'] = items?.map((v) => v.toJson()).toList();
29 | }
30 |
31 | return map;
32 | }
33 | }
34 |
35 | class Item {
36 | Item({
37 | this.name,
38 | this.owner,
39 | this.description,
40 | this.stargazersCount,
41 | this.forks,
42 | this.watchers,
43 | this.score,
44 | });
45 |
46 | Item.fromJson(dynamic json) {
47 | name = json['name'];
48 | owner = json['owner'] != null ? Owner.fromJson(json['owner']) : null;
49 | description = json['description'];
50 | stargazersCount = json['stargazers_count'];
51 | forks = json['forks'];
52 | watchers = json['watchers'];
53 | score = json['score'];
54 | }
55 |
56 | String? name;
57 | Owner? owner;
58 | int? stargazersCount;
59 | int? forks;
60 | int? watchers;
61 | double? score;
62 | String? description;
63 |
64 | Map toJson() {
65 | final map = {};
66 | map['name'] = name;
67 | if (owner != null) {
68 | map['owner'] = owner?.toJson();
69 | }
70 | map['description'] = description;
71 | map['stargazers_count'] = stargazersCount;
72 | map['forks'] = forks;
73 | map['watchers'] = watchers;
74 | map['score'] = score;
75 |
76 | return map;
77 | }
78 | }
79 |
80 | class Owner {
81 | Owner({
82 | this.login,
83 | this.avatarUrl,
84 | });
85 |
86 | Owner.fromJson(dynamic json) {
87 | login = json['login'];
88 | avatarUrl = json['avatar_url'];
89 | }
90 |
91 | String? login;
92 | String? avatarUrl;
93 |
94 | Map toJson() {
95 | final map = {};
96 | map['login'] = login;
97 | map['avatar_url'] = avatarUrl;
98 |
99 | return map;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/lib/app/data/remote/github_remote_data_source.dart:
--------------------------------------------------------------------------------
1 | import '/app/core/model/github_search_query_param.dart';
2 | import '/app/data/model/github_project_search_response.dart';
3 |
4 | abstract class GithubRemoteDataSource {
5 | Future searchGithubProject(
6 | GithubSearchQueryParam queryParam);
7 |
8 | Future
- getGithubProjectDetails(String userName, String repositoryName);
9 | }
10 |
--------------------------------------------------------------------------------
/lib/app/data/remote/github_remote_data_source_impl.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | import '/app/core/base/base_remote_source.dart';
4 | import '/app/core/model/github_search_query_param.dart';
5 | import '/app/data/model/github_project_search_response.dart';
6 | import '/app/data/remote/github_remote_data_source.dart';
7 | import '/app/network/dio_provider.dart';
8 |
9 | class GithubRemoteDataSourceImpl extends BaseRemoteSource
10 | implements GithubRemoteDataSource {
11 | @override
12 | Future searchGithubProject(
13 | GithubSearchQueryParam queryParam) {
14 | var endpoint = "${DioProvider.baseUrl}/search/repositories";
15 | var dioCall = dioClient.get(endpoint, queryParameters: queryParam.toJson());
16 |
17 | try {
18 | return callApiWithErrorParser(dioCall)
19 | .then((response) => _parseGithubProjectSearchResponse(response));
20 | } catch (e) {
21 | rethrow;
22 | }
23 | }
24 |
25 | @override
26 | Future
- getGithubProjectDetails(String userName, String repositoryName) {
27 | var endpoint = "${DioProvider.baseUrl}/repos/$userName/$repositoryName";
28 | var dioCall = dioClient.get(endpoint);
29 |
30 | try {
31 | return callApiWithErrorParser(dioCall)
32 | .then((response) => _parseGithubProjectResponse(response));
33 | } catch (e) {
34 | rethrow;
35 | }
36 | }
37 |
38 | GithubProjectSearchResponse _parseGithubProjectSearchResponse(
39 | Response response) {
40 | return GithubProjectSearchResponse.fromJson(response.data);
41 | }
42 |
43 | Item _parseGithubProjectResponse(Response response) {
44 | return Item.fromJson(response.data);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/app/data/repository/github_repository.dart:
--------------------------------------------------------------------------------
1 | import '/app/core/model/github_search_query_param.dart';
2 | import '/app/data/model/github_project_search_response.dart';
3 |
4 | abstract class GithubRepository {
5 | Future searchProject(
6 | GithubSearchQueryParam queryParam);
7 |
8 | Future
- getProject(String userName, String repositoryName);
9 | }
10 |
--------------------------------------------------------------------------------
/lib/app/data/repository/github_repository_impl.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/core/model/github_search_query_param.dart';
4 | import '/app/data/model/github_project_search_response.dart';
5 | import '/app/data/remote/github_remote_data_source.dart';
6 | import '/app/data/repository/github_repository.dart';
7 |
8 | class GithubRepositoryImpl implements GithubRepository {
9 | final GithubRemoteDataSource _remoteSource =
10 | Get.find(tag: (GithubRemoteDataSource).toString());
11 |
12 | @override
13 | Future searchProject(
14 | GithubSearchQueryParam queryParam) {
15 | return _remoteSource.searchGithubProject(queryParam);
16 | }
17 |
18 | @override
19 | Future
- getProject(String userName, String repositoryName) {
20 | return _remoteSource.getGithubProjectDetails(userName, repositoryName);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/app/modules/favorite/bindings/favorite_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/modules/favorite/controllers/favorite_controller.dart';
4 |
5 | class FavoriteBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => FavoriteController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/favorite/controllers/favorite_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/core/base/base_controller.dart';
4 |
5 | class FavoriteController extends BaseController {
6 | final count = 0.obs;
7 |
8 | void increment() => count.value++;
9 | }
10 |
--------------------------------------------------------------------------------
/lib/app/modules/favorite/views/favorite_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '/app/core/base/base_view.dart';
4 | import '/app/core/values/text_styles.dart';
5 | import '/app/core/widget/custom_app_bar.dart';
6 | import '/app/modules/favorite/controllers/favorite_controller.dart';
7 |
8 | class FavoriteView extends BaseView {
9 | @override
10 | PreferredSizeWidget? appBar(BuildContext context) {
11 | return CustomAppBar(
12 | appBarTitleText: 'Favorite',
13 | );
14 | }
15 |
16 | @override
17 | Widget body(BuildContext context) {
18 | return const Center(
19 | child: Text(
20 | 'FavoriteView is working',
21 | style: titleStyle,
22 | ),
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/app/modules/home/bindings/home_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/modules/home/controllers/home_controller.dart';
4 |
5 | class HomeBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => HomeController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/home/controllers/home_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/core/base/base_controller.dart';
4 | import '/app/core/base/paging_controller.dart';
5 | import '/app/core/model/github_search_query_param.dart';
6 | import '/app/data/model/github_project_search_response.dart';
7 | import '/app/data/repository/github_repository.dart';
8 | import '/app/modules/home/model/github_project_ui_data.dart';
9 |
10 | class HomeController extends BaseController {
11 | final GithubRepository _repository =
12 | Get.find(tag: (GithubRepository).toString());
13 |
14 | final RxList _githubProjectListController =
15 | RxList.empty();
16 |
17 | List get projectList =>
18 | _githubProjectListController.toList();
19 |
20 | final pagingController = PagingController();
21 |
22 | void getGithubGetxProjectList() {
23 | if (!pagingController.canLoadNextPage()) return;
24 |
25 | pagingController.isLoadingPage = true;
26 |
27 | var queryParam = GithubSearchQueryParam(
28 | searchKeyWord: 'flutter getx template',
29 | pageNumber: pagingController.pageNumber,
30 | );
31 |
32 | var githubRepoSearchService = _repository.searchProject(queryParam);
33 |
34 | callDataService(
35 | githubRepoSearchService,
36 | onSuccess: _handleProjectListResponseSuccess,
37 | );
38 |
39 | pagingController.isLoadingPage = false;
40 | }
41 |
42 | onRefreshPage() {
43 | pagingController.initRefresh();
44 | getGithubGetxProjectList();
45 | }
46 |
47 | onLoadNextPage() {
48 | logger.i("On load next");
49 |
50 | getGithubGetxProjectList();
51 | }
52 |
53 | void _handleProjectListResponseSuccess(GithubProjectSearchResponse response) {
54 | List? repoList = response.items
55 | ?.map((e) => GithubProjectUiData(
56 | repositoryName: e.name != null ? e.name! : "Null",
57 | ownerLoginName: e.owner != null ? e.owner!.login! : "Null",
58 | ownerAvatar: e.owner != null ? e.owner!.avatarUrl! : "",
59 | numberOfStar: e.stargazersCount ?? 0,
60 | numberOfFork: e.forks ?? 0,
61 | score: e.score ?? 0.0,
62 | watchers: e.watchers ?? 0,
63 | description: e.description ?? "",
64 | ))
65 | .toList();
66 |
67 | if (_isLastPage(repoList!.length, response.totalCount!)) {
68 | pagingController.appendLastPage(repoList);
69 | } else {
70 | pagingController.appendPage(repoList);
71 | }
72 |
73 | var newList = [...pagingController.listItems];
74 |
75 | _githubProjectListController(newList);
76 | }
77 |
78 | bool _isLastPage(int newListItemCount, int totalCount) {
79 | return (projectList.length + newListItemCount) >= totalCount;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/app/modules/home/model/github_project_ui_data.dart:
--------------------------------------------------------------------------------
1 | class GithubProjectUiData {
2 | String repositoryName;
3 | String ownerLoginName;
4 | String ownerAvatar;
5 | int numberOfStar;
6 | int numberOfFork;
7 | String description;
8 | double score;
9 | int watchers;
10 |
11 | GithubProjectUiData({
12 | this.repositoryName = "",
13 | this.ownerLoginName = "",
14 | this.ownerAvatar = "",
15 | this.numberOfStar = 0,
16 | this.numberOfFork = 0,
17 | this.description = "",
18 | this.score = 0.0,
19 | this.watchers = 0,
20 | });
21 | }
22 |
--------------------------------------------------------------------------------
/lib/app/modules/home/views/home_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import '/app/core/base/base_view.dart';
5 | import '/app/core/values/app_values.dart';
6 | import '/app/core/widget/custom_app_bar.dart';
7 | import '/app/core/widget/paging_view.dart';
8 | import '/app/modules/home/controllers/home_controller.dart';
9 | import '/app/modules/home/widget/item_github_project.dart';
10 |
11 | class HomeView extends BaseView {
12 | HomeView() {
13 | controller.getGithubGetxProjectList();
14 | }
15 |
16 | @override
17 | PreferredSizeWidget? appBar(BuildContext context) {
18 | return CustomAppBar(
19 | appBarTitleText: 'GetX Templates on GitHub',
20 | );
21 | }
22 |
23 | @override
24 | Widget body(BuildContext context) {
25 | return PagingView(
26 | onRefresh: () async {
27 | controller.onRefreshPage();
28 | },
29 | onLoadNextPage: () {
30 | controller.onLoadNextPage();
31 | },
32 | child: Padding(
33 | padding: const EdgeInsets.all(AppValues.padding),
34 | child: Obx(
35 | () => ListView.separated(
36 | shrinkWrap: true,
37 | itemCount: controller.projectList.length,
38 | primary: false,
39 | physics: const NeverScrollableScrollPhysics(),
40 | itemBuilder: (context, index) {
41 | var model = controller.projectList[index];
42 |
43 | return ItemGithubProject(dataModel: model);
44 | },
45 | separatorBuilder: (BuildContext context, int index) =>
46 | const SizedBox(height: AppValues.smallMargin),
47 | ),
48 | ),
49 | ),
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/app/modules/home/widget/item_github_project.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_getx_template/app/core/widget/ripple.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '/app/core/base/base_widget_mixin.dart';
6 | import '/app/core/values/app_colors.dart';
7 | import '/app/core/values/app_values.dart';
8 | import '/app/core/values/text_styles.dart';
9 | import '/app/core/widget/elevated_container.dart';
10 | import '/app/core/widget/icon_text_widgets.dart';
11 | import '/app/modules/home/model/github_project_ui_data.dart';
12 | import '/app/routes/app_pages.dart';
13 |
14 | class ItemGithubProject extends StatelessWidget with BaseWidgetMixin {
15 | final GithubProjectUiData dataModel;
16 |
17 | ItemGithubProject({
18 | Key? key,
19 | required this.dataModel,
20 | }) : super(key: key);
21 |
22 | @override
23 | Widget body(BuildContext context) {
24 | return ElevatedContainer(
25 | child: Ripple(
26 | onTap: _onTap,
27 | child: Padding(
28 | padding: const EdgeInsets.all(AppValues.padding),
29 | child: Row(
30 | mainAxisAlignment: MainAxisAlignment.start,
31 | crossAxisAlignment: CrossAxisAlignment.center,
32 | children: [
33 | CircleAvatar(
34 | backgroundImage: NetworkImage(dataModel.ownerAvatar),
35 | radius: AppValues.circularImageSize_30,
36 | ),
37 | const SizedBox(width: AppValues.margin_10),
38 | _getDetailsView(),
39 | ],
40 | ),
41 | ),
42 | ),
43 | );
44 | }
45 |
46 | Widget _getDetailsView() {
47 | return Expanded(
48 | child: Column(
49 | crossAxisAlignment: CrossAxisAlignment.start,
50 | children: [
51 | Text(
52 | dataModel.repositoryName,
53 | style: cardTitleStyle,
54 | overflow: TextOverflow.ellipsis,
55 | maxLines: 1,
56 | ),
57 | const SizedBox(height: AppValues.margin_4),
58 | Text(
59 | dataModel.ownerLoginName,
60 | style: cardSubtitleStyle,
61 | maxLines: 1,
62 | overflow: TextOverflow.ellipsis,
63 | ),
64 | const SizedBox(height: AppValues.margin_4),
65 | _getForkStarWatcherView(),
66 | ],
67 | ),
68 | );
69 | }
70 |
71 | Widget _getForkStarWatcherView() {
72 | return Row(
73 | children: [
74 | IconTextWidget(
75 | fileName: "ic_fork.svg",
76 | value: dataModel.numberOfFork.toString(),
77 | height: AppValues.iconSize_20,
78 | width: AppValues.iconSize_20,
79 | color: AppColors.iconColorDefault,
80 | ),
81 | IconTextWidget(
82 | icon: Icons.star_border,
83 | value: dataModel.numberOfStar.toString(),
84 | size: AppValues.iconSize_20,
85 | color: AppColors.iconColorDefault,
86 | ),
87 | IconTextWidget(
88 | icon: Icons.visibility_outlined,
89 | value: dataModel.watchers.toString(),
90 | size: AppValues.iconSize_20,
91 | color: AppColors.iconColorDefault,
92 | ),
93 | ],
94 | );
95 | }
96 |
97 | void _onTap() {
98 | Get.toNamed(Routes.PROJECT_DETAILS, arguments: dataModel);
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/lib/app/modules/main/bindings/main_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/modules/favorite/controllers/favorite_controller.dart';
4 | import '/app/modules/home/controllers/home_controller.dart';
5 | import '/app/modules/main/controllers/main_controller.dart';
6 | import '/app/modules/other/controllers/other_controller.dart';
7 | import '/app/modules/settings/controllers/settings_controller.dart';
8 |
9 | class MainBinding extends Bindings {
10 | @override
11 | void dependencies() {
12 | Get.lazyPut(
13 | () => MainController(),
14 | fenix: true,
15 | );
16 | Get.lazyPut(
17 | () => OtherController(),
18 | fenix: true,
19 | );
20 | Get.lazyPut(
21 | () => HomeController(),
22 | fenix: true,
23 | );
24 | Get.lazyPut(
25 | () => FavoriteController(),
26 | );
27 | Get.lazyPut(
28 | () => SettingsController(),
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/app/modules/main/controllers/bottom_nav_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | class BottomNavController extends GetxController {
4 | final _selectedIndexController = 0.obs;
5 |
6 | updateSelectedIndex(int index) => _selectedIndexController(index);
7 |
8 | int get selectedIndex => _selectedIndexController.value;
9 | }
10 |
--------------------------------------------------------------------------------
/lib/app/modules/main/controllers/main_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/core/base/base_controller.dart';
4 | import '/app/modules/main/model/menu_code.dart';
5 |
6 | class MainController extends BaseController {
7 | final _selectedMenuCodeController = MenuCode.HOME.obs;
8 |
9 | MenuCode get selectedMenuCode => _selectedMenuCodeController.value;
10 |
11 | final lifeCardUpdateController = false.obs;
12 |
13 | onMenuSelected(MenuCode menuCode) async {
14 | _selectedMenuCodeController(menuCode);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/app/modules/main/model/menu_code.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
2 | import 'package:flutter_getx_template/app/modules/main/model/menu_item.dart';
3 |
4 | enum MenuCode { HOME, FAVORITE, SETTINGS }
5 |
6 | extension MenuCodeExtensions on MenuCode {
7 | BottomNavItem toBottomNavItem(AppLocalizations appLocalization) {
8 | switch (this) {
9 | case MenuCode.HOME:
10 | return BottomNavItem(
11 | navTitle: appLocalization.bottomNavHome,
12 | iconSvgName: "ic_home.svg",
13 | menuCode: MenuCode.HOME,
14 | );
15 | case MenuCode.FAVORITE:
16 | return BottomNavItem(
17 | navTitle: appLocalization.bottomNavFavorite,
18 | iconSvgName: "ic_favorite.svg",
19 | menuCode: MenuCode.FAVORITE);
20 | case MenuCode.SETTINGS:
21 | return BottomNavItem(
22 | navTitle: appLocalization.bottomNavSettings,
23 | iconSvgName: "ic_settings.svg",
24 | menuCode: MenuCode.SETTINGS);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/app/modules/main/model/menu_item.dart:
--------------------------------------------------------------------------------
1 | import '/app/modules/main/model/menu_code.dart';
2 |
3 | class BottomNavItem {
4 | final String navTitle;
5 | final String iconSvgName;
6 | final MenuCode menuCode;
7 |
8 | const BottomNavItem(
9 | {required this.navTitle,
10 | required this.iconSvgName,
11 | required this.menuCode});
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/main/views/bottom_nav_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_getx_template/app/core/base/base_widget_mixin.dart';
3 | import 'package:flutter_getx_template/app/core/widget/asset_image_view.dart';
4 | import 'package:get/get.dart';
5 |
6 | import '/app/core/values/app_colors.dart';
7 | import '/app/core/values/app_values.dart';
8 | import '/app/modules/main/controllers/bottom_nav_controller.dart';
9 | import '/app/modules/main/model/menu_code.dart';
10 | import '/app/modules/main/model/menu_item.dart';
11 |
12 | typedef OnBottomNavItemSelected = Function(MenuCode menuCode);
13 |
14 | class BottomNavBar extends StatelessWidget with BaseWidgetMixin {
15 | BottomNavBar({
16 | Key? key,
17 | required this.onItemSelected,
18 | }) : super(key: key);
19 |
20 | final OnBottomNavItemSelected onItemSelected;
21 | final navController = BottomNavController();
22 | final Key bottomNavKey = GlobalKey();
23 | final Color selectedItemColor = Colors.white;
24 | final Color unselectedItemColor = Colors.grey;
25 |
26 | @override
27 | Widget body(BuildContext context) {
28 | List navItems = _getNavItems();
29 |
30 | return Obx(
31 | () => BottomNavigationBar(
32 | key: bottomNavKey,
33 | items: _navItemBuilder(navItems),
34 | showSelectedLabels: true,
35 | showUnselectedLabels: true,
36 | type: BottomNavigationBarType.fixed,
37 | backgroundColor: AppColors.colorAccent,
38 | selectedItemColor: selectedItemColor,
39 | unselectedItemColor: unselectedItemColor,
40 | currentIndex: navController.selectedIndex,
41 | onTap: (index) {
42 | navController.updateSelectedIndex(index);
43 | onItemSelected(navItems[index].menuCode);
44 | },
45 | ),
46 | );
47 | }
48 |
49 | List _navItemBuilder(List navItems) {
50 | return navItems
51 | .map(
52 | (BottomNavItem navItem) => _getBottomNavigationBarItem(
53 | navItem,
54 | navItems.indexOf(navItem) == navController.selectedIndex,
55 | ),
56 | )
57 | .toList();
58 | }
59 |
60 | BottomNavigationBarItem _getBottomNavigationBarItem(
61 | BottomNavItem navItem,
62 | bool isSelected,
63 | ) {
64 | return BottomNavigationBarItem(
65 | icon: AssetImageView(
66 | fileName: navItem.iconSvgName,
67 | height: AppValues.iconDefaultSize,
68 | width: AppValues.iconDefaultSize,
69 | color: isSelected ? selectedItemColor : unselectedItemColor,
70 | ),
71 | label: navItem.navTitle,
72 | tooltip: navItem.navTitle,
73 | );
74 | }
75 |
76 | List _getNavItems() {
77 | return MenuCode.values
78 | .map((e) => e.toBottomNavItem(appLocalization))
79 | .toList();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/app/modules/main/views/main_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '/app/core/base/base_view.dart';
6 | import '/app/modules/favorite/views/favorite_view.dart';
7 | import '/app/modules/home/views/home_view.dart';
8 | import '/app/modules/main/controllers/main_controller.dart';
9 | import '/app/modules/main/model/menu_code.dart';
10 | import '/app/modules/main/views/bottom_nav_bar.dart';
11 | import '/app/modules/other/views/other_view.dart';
12 | import '/app/modules/settings/views/settings_view.dart';
13 |
14 | // ignore: must_be_immutable
15 | class MainView extends BaseView {
16 | @override
17 | PreferredSizeWidget? appBar(BuildContext context) => null;
18 |
19 | @override
20 | Widget body(BuildContext context) {
21 | return Container(
22 | key: UniqueKey(),
23 | child: Obx(
24 | () => getPageOnSelectedMenu(controller.selectedMenuCode),
25 | ),
26 | );
27 | }
28 |
29 | @override
30 | Widget? bottomNavigationBar() {
31 | return BottomNavBar(onItemSelected: controller.onMenuSelected);
32 | }
33 |
34 | final HomeView homeView = HomeView();
35 | FavoriteView? favoriteView;
36 | SettingsView? settingsView;
37 |
38 | Widget getPageOnSelectedMenu(MenuCode menuCode) {
39 | switch (menuCode) {
40 | case MenuCode.HOME:
41 | return homeView;
42 | case MenuCode.FAVORITE:
43 | favoriteView ??= FavoriteView();
44 | return favoriteView!;
45 | case MenuCode.SETTINGS:
46 | settingsView ??= SettingsView();
47 | return settingsView!;
48 | default:
49 | return OtherView(
50 | viewParam: describeEnum(menuCode),
51 | );
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/app/modules/other/bindings/other_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/modules/other/controllers/other_controller.dart';
4 |
5 | class OtherBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => OtherController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/other/controllers/other_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/core/base/base_controller.dart';
4 |
5 | class OtherController extends BaseController {
6 | final count = 0.obs;
7 |
8 | void increment() => count.value++;
9 | }
10 |
--------------------------------------------------------------------------------
/lib/app/modules/other/views/other_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '/app/core/base/base_view.dart';
4 | import '/app/core/widget/custom_app_bar.dart';
5 | import '../controllers/other_controller.dart';
6 |
7 | class OtherView extends BaseView {
8 | final String viewParam;
9 |
10 | OtherView({this.viewParam = ""});
11 |
12 | @override
13 | PreferredSizeWidget? appBar(BuildContext context) {
14 | return CustomAppBar(appBarTitleText: viewParam);
15 | }
16 |
17 | @override
18 | Widget body(BuildContext context) {
19 | return const Center(
20 | child: Text(
21 | 'OtherView is working',
22 | style: TextStyle(fontSize: 20),
23 | ),
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/app/modules/project_details/bindings/project_details_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/modules/project_details/controllers/project_details_controller.dart';
4 |
5 | class ProjectDetailsBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => ProjectDetailsController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/project_details/controllers/project_details_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/core/base/base_controller.dart';
4 | import '/app/data/model/github_project_search_response.dart';
5 | import '/app/data/repository/github_repository.dart';
6 | import '/app/modules/home/model/github_project_ui_data.dart';
7 |
8 | class ProjectDetailsController extends BaseController {
9 | final GithubRepository _repository =
10 | Get.find(tag: (GithubRepository).toString());
11 |
12 | final Rx _projectUiData = GithubProjectUiData().obs;
13 |
14 | GithubProjectUiData get projectUiData => _projectUiData.value;
15 |
16 | @override
17 | void onInit() {
18 | var dataModel = Get.arguments;
19 | if (dataModel is GithubProjectUiData) {
20 | getGithubRepository(dataModel.ownerLoginName, dataModel.repositoryName);
21 | }
22 | super.onInit();
23 | }
24 |
25 | void getGithubRepository(userName, repositoryName) {
26 | callDataService(
27 | _repository.getProject(userName, repositoryName),
28 | onSuccess: _handleProjectDetailsResponseSuccess,
29 | );
30 | }
31 |
32 | void _handleProjectDetailsResponseSuccess(Item project) {
33 | _projectUiData(GithubProjectUiData(
34 | repositoryName: project.name != null ? project.name! : "",
35 | ownerLoginName: project.owner != null ? project.owner!.login! : "",
36 | ownerAvatar: project.owner != null ? project.owner!.avatarUrl! : "",
37 | numberOfStar: project.stargazersCount ?? 0,
38 | numberOfFork: project.forks ?? 0,
39 | score: project.score ?? 0.0,
40 | watchers: project.watchers ?? 0,
41 | description: project.description ?? "",
42 | ));
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/app/modules/project_details/views/project_details_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import '/app/core/base/base_view.dart';
5 | import '/app/core/values/app_colors.dart';
6 | import '/app/core/values/app_values.dart';
7 | import '/app/core/values/text_styles.dart';
8 | import '/app/core/widget/custom_app_bar.dart';
9 | import '/app/core/widget/icon_text_widgets.dart';
10 | import '/app/modules/project_details/controllers/project_details_controller.dart';
11 |
12 | class ProjectDetailsView extends BaseView {
13 | @override
14 | PreferredSizeWidget? appBar(BuildContext context) {
15 | return CustomAppBar(
16 | appBarTitleText: 'Repository details',
17 | isBackButtonEnabled: true,
18 | );
19 | }
20 |
21 | @override
22 | Widget body(BuildContext context) {
23 | return Scaffold(
24 | body: Center(
25 | child: Obx(() => _getView()),
26 | ),
27 | );
28 | }
29 |
30 | Widget _getView() {
31 | return controller.projectUiData.repositoryName.isEmpty
32 | ? Container()
33 | : Container(
34 | margin: const EdgeInsets.all(AppValues.margin_20),
35 | child: Column(
36 | crossAxisAlignment: CrossAxisAlignment.start,
37 | children: [
38 | Text(
39 | controller.projectUiData.repositoryName,
40 | style: cardTitleStyle,
41 | overflow: TextOverflow.ellipsis,
42 | maxLines: 1,
43 | ),
44 | _getAuthor(),
45 | const SizedBox(height: AppValues.margin_4),
46 | _getForkStarWatcherView(),
47 | const SizedBox(height: AppValues.margin_30),
48 | _getDescription()
49 | ],
50 | ),
51 | );
52 | }
53 |
54 | Widget _getAuthor() {
55 | return Row(
56 | children: [
57 | CircleAvatar(
58 | backgroundImage: NetworkImage(controller.projectUiData.ownerAvatar),
59 | radius: AppValues.iconSmallSize,
60 | ),
61 | const SizedBox(width: AppValues.margin_6),
62 | Text(
63 | controller.projectUiData.ownerLoginName,
64 | style: cardSubtitleStyle,
65 | maxLines: 1,
66 | overflow: TextOverflow.ellipsis,
67 | ),
68 | ],
69 | );
70 | }
71 |
72 | Widget _getForkStarWatcherView() {
73 | return Container(
74 | margin: const EdgeInsets.only(left: AppValues.margin_40),
75 | child: Row(
76 | children: [
77 | IconTextWidget(
78 | fileName: "ic_fork.svg",
79 | value: controller.projectUiData.numberOfFork.toString(),
80 | height: AppValues.iconSize_20,
81 | width: AppValues.iconSize_20,
82 | color: AppColors.iconColorDefault,
83 | ),
84 | IconTextWidget(
85 | icon: Icons.star_border,
86 | value: controller.projectUiData.numberOfStar.toString(),
87 | size: AppValues.iconSize_20,
88 | color: AppColors.iconColorDefault,
89 | ),
90 | IconTextWidget(
91 | icon: Icons.visibility_outlined,
92 | value: controller.projectUiData.watchers.toString(),
93 | size: AppValues.iconSize_20,
94 | color: AppColors.iconColorDefault,
95 | ),
96 | ],
97 | ),
98 | );
99 | }
100 |
101 | Widget _getDescription() {
102 | return Expanded(
103 | child: SingleChildScrollView(
104 | scrollDirection: Axis.vertical,
105 | child: Text(controller.projectUiData.description,
106 | style: descriptionTextStyle),
107 | ),
108 | );
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/lib/app/modules/settings/bindings/settings_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/modules/settings/controllers/settings_controller.dart';
4 |
5 | class SettingsBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => SettingsController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/settings/controllers/settings_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '/app/core/base/base_controller.dart';
4 |
5 | class SettingsController extends BaseController {
6 | final count = 0.obs;
7 |
8 | void increment() => count.value++;
9 | }
10 |
--------------------------------------------------------------------------------
/lib/app/modules/settings/views/settings_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import '/app/modules/settings/widgets/item_settings_widgets.dart';
3 | import '/app/core/base/base_view.dart';
4 | import '/app/core/widget/custom_app_bar.dart';
5 | import '/app/modules/settings/controllers/settings_controller.dart';
6 |
7 | class SettingsView extends BaseView {
8 | @override
9 | PreferredSizeWidget? appBar(BuildContext context) {
10 | return CustomAppBar(
11 | appBarTitleText: appLocalization.bottomNavSettings,
12 | isBackButtonEnabled: false,
13 | );
14 | }
15 |
16 | @override
17 | Widget body(BuildContext context) {
18 | return Column(
19 | children: [
20 | ItemSettings(
21 | title: appLocalization.settingsTheme,
22 | prefixImage: 'ic_theme.png',
23 | suffixImage: 'arrow_forward.svg',
24 | onTap: _onThemeItemClicked,
25 | ),
26 | _getHorizontalDivider(),
27 | ItemSettings(
28 | title: appLocalization.settingsLanguage,
29 | prefixImage: 'ic_language.svg',
30 | suffixImage: 'arrow_forward.svg',
31 | onTap: _onLanguageItemClicked,
32 | ),
33 | _getHorizontalDivider(),
34 | ItemSettings(
35 | title: appLocalization.settingsFontSize,
36 | prefixImage: 'ic_font_size.svg',
37 | suffixImage: 'arrow_forward.svg',
38 | onTap: _onFontSizeItemClicked,
39 | ),
40 | _getHorizontalDivider(),
41 | ],
42 | );
43 | }
44 |
45 | Widget _getHorizontalDivider() {
46 | return const Divider(height: 1);
47 | }
48 |
49 | void _onThemeItemClicked() {
50 | showToast('Theme: Development in progress');
51 | }
52 |
53 | void _onLanguageItemClicked() {
54 | showToast('Language: Development in progress');
55 | }
56 |
57 | void _onFontSizeItemClicked() {
58 | showToast('Font Size: Development in progress');
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/lib/app/modules/settings/widgets/item_settings_widgets.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import '/app/core/base/base_widget_mixin.dart';
3 | import '/app/core/values/app_colors.dart';
4 | import '/app/core/values/app_values.dart';
5 | import '/app/core/values/text_styles.dart';
6 | import '/app/core/widget/asset_image_view.dart';
7 | import '/app/core/widget/ripple.dart';
8 |
9 | class ItemSettings extends StatelessWidget with BaseWidgetMixin {
10 | final String prefixImage;
11 | final String suffixImage;
12 | final String title;
13 | final Function()? onTap;
14 |
15 | ItemSettings({
16 | required this.prefixImage,
17 | required this.suffixImage,
18 | required this.title,
19 | required this.onTap,
20 | });
21 |
22 | @override
23 | Widget body(BuildContext context) {
24 | return Ripple(
25 | onTap: onTap,
26 | child: Padding(
27 | padding: const EdgeInsets.all(AppValues.padding),
28 | child: Row(
29 | children: [
30 | AssetImageView(
31 | fileName: prefixImage,
32 | height: AppValues.iconSize_20,
33 | width: AppValues.iconSize_20,
34 | ),
35 | const SizedBox(width: AppValues.smallPadding),
36 | Text(title, style: settingsItemStyle),
37 | const Spacer(),
38 | AssetImageView(
39 | fileName: suffixImage,
40 | color: AppColors.suffixImageColor,
41 | height: AppValues.iconSize_20,
42 | width: AppValues.iconSize_20,
43 | ),
44 | ],
45 | ),
46 | ),
47 | );
48 | }
49 | }
--------------------------------------------------------------------------------
/lib/app/my_app.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '/app/bindings/initial_binding.dart';
6 | import '/app/core/values/app_colors.dart';
7 | import '/app/routes/app_pages.dart';
8 | import '/flavors/build_config.dart';
9 | import '/flavors/env_config.dart';
10 |
11 | class MyApp extends StatefulWidget {
12 | const MyApp({Key? key}) : super(key: key);
13 |
14 | @override
15 | _MyAppState createState() => _MyAppState();
16 | }
17 |
18 | class _MyAppState extends State {
19 | final EnvConfig _envConfig = BuildConfig.instance.config;
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return GetMaterialApp(
24 | title: _envConfig.appName,
25 | initialRoute: AppPages.INITIAL,
26 | initialBinding: InitialBinding(),
27 | getPages: AppPages.routes,
28 | localizationsDelegates: AppLocalizations.localizationsDelegates,
29 | supportedLocales: _getSupportedLocal(),
30 | theme: ThemeData(
31 | primarySwatch: AppColors.colorPrimarySwatch,
32 | visualDensity: VisualDensity.adaptivePlatformDensity,
33 | brightness: Brightness.light,
34 | primaryColor: AppColors.colorPrimary,
35 | textTheme: const TextTheme(
36 | labelLarge: TextStyle(
37 | color: Colors.white,
38 | fontSize: 20.0,
39 | fontWeight: FontWeight.bold,
40 | ),
41 | ),
42 | fontFamily: 'Roboto',
43 | ),
44 | debugShowCheckedModeBanner: false,
45 | );
46 | }
47 |
48 | List _getSupportedLocal() {
49 | return [
50 | const Locale('en', ''),
51 | const Locale('bn', ''),
52 | ];
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/app/network/dio_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:flutter_getx_template/flavors/environment.dart';
3 |
4 | import '/app/network/pretty_dio_logger.dart';
5 | import '/app/network/request_headers.dart';
6 | import '/flavors/build_config.dart';
7 |
8 | class DioProvider {
9 | static final String baseUrl = BuildConfig.instance.config.baseUrl;
10 |
11 | static Dio? _instance;
12 |
13 | static const int _maxLineWidth = 90;
14 | static final _prettyDioLogger = PrettyDioLogger(
15 | requestHeader: true,
16 | requestBody: true,
17 | responseBody: BuildConfig.instance.environment == Environment.DEVELOPMENT,
18 | responseHeader: false,
19 | error: true,
20 | compact: true,
21 | maxWidth: _maxLineWidth);
22 |
23 | static final BaseOptions _options = BaseOptions(
24 | baseUrl: baseUrl,
25 | connectTimeout: const Duration(seconds: 60),
26 | receiveTimeout: const Duration(seconds: 60),
27 | );
28 |
29 | static Dio get httpDio {
30 | if (_instance == null) {
31 | _instance = Dio(_options);
32 |
33 | _instance!.interceptors.add(_prettyDioLogger);
34 |
35 | return _instance!;
36 | } else {
37 | _instance!.interceptors.clear();
38 | _instance!.interceptors.add(_prettyDioLogger);
39 |
40 | return _instance!;
41 | }
42 | }
43 |
44 | ///returns a Dio client with Access token in header
45 | static Dio get tokenClient {
46 | _addInterceptors();
47 |
48 | return _instance!;
49 | }
50 |
51 | ///returns a Dio client with Access token in header
52 | ///Also adds a token refresh interceptor which retry the request when it's unauthorized
53 | static Dio get dioWithHeaderToken {
54 | _addInterceptors();
55 |
56 | return _instance!;
57 | }
58 |
59 | static _addInterceptors() {
60 | _instance ??= httpDio;
61 | _instance!.interceptors.clear();
62 | _instance!.interceptors.add(RequestHeaderInterceptor());
63 | _instance!.interceptors.add(_prettyDioLogger);
64 | }
65 |
66 | static String _buildContentType(String version) {
67 | return "user_defined_content_type+$version";
68 | }
69 |
70 | DioProvider.setContentType(String version) {
71 | _instance?.options.contentType = _buildContentType(version);
72 | }
73 |
74 | DioProvider.setContentTypeApplicationJson() {
75 | _instance?.options.contentType = "application/json";
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/lib/app/network/dio_request_retrier.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:get/get.dart' as getx;
3 |
4 | import '/app/data/local/preference/preference_manager.dart';
5 | import '/app/network/dio_provider.dart';
6 |
7 | class DioRequestRetrier {
8 | final dioClient = DioProvider.tokenClient;
9 | final RequestOptions requestOptions;
10 |
11 | final PreferenceManager _preferenceManager =
12 | getx.Get.find(tag: (PreferenceManager).toString());
13 |
14 | DioRequestRetrier({required this.requestOptions});
15 |
16 | Future> retry() async {
17 | var header = await getCustomHeaders();
18 |
19 | return await dioClient.request(
20 | requestOptions.path,
21 | cancelToken: requestOptions.cancelToken,
22 | data: requestOptions.data,
23 | queryParameters: requestOptions.queryParameters,
24 | onReceiveProgress: requestOptions.onReceiveProgress,
25 | onSendProgress: requestOptions.onSendProgress,
26 | options: Options(headers: header, method: requestOptions.method),
27 | );
28 | }
29 |
30 | Future