├── .gitignore ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── developersancho │ │ │ │ └── rorty │ │ │ │ └── rorty_flutter │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ ├── android12splash.png │ │ │ └── splash.png │ │ │ ├── drawable-mdpi │ │ │ ├── android12splash.png │ │ │ └── splash.png │ │ │ ├── drawable-night-hdpi │ │ │ ├── android12splash.png │ │ │ └── splash.png │ │ │ ├── drawable-night-mdpi │ │ │ ├── android12splash.png │ │ │ └── splash.png │ │ │ ├── drawable-night-v21 │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ │ ├── drawable-night-xhdpi │ │ │ ├── android12splash.png │ │ │ └── splash.png │ │ │ ├── drawable-night-xxhdpi │ │ │ ├── android12splash.png │ │ │ └── splash.png │ │ │ ├── drawable-night-xxxhdpi │ │ │ ├── android12splash.png │ │ │ └── splash.png │ │ │ ├── drawable-night │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ │ ├── drawable-v21 │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ │ ├── drawable-xhdpi │ │ │ ├── android12splash.png │ │ │ └── splash.png │ │ │ ├── drawable-xxhdpi │ │ │ ├── android12splash.png │ │ │ └── splash.png │ │ │ ├── drawable-xxxhdpi │ │ │ ├── android12splash.png │ │ │ └── splash.png │ │ │ ├── drawable │ │ │ ├── background.png │ │ │ └── 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-v31 │ │ │ └── styles.xml │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ ├── values-v31 │ │ │ └── styles.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── art ├── architecture.png ├── architecturecircles.png ├── clean_arch.jpeg ├── flutter-logo.webp ├── project.png └── screenshots │ ├── android │ ├── abouts-dark.png │ ├── abouts.png │ ├── character-detail-dark.png │ ├── character-detail.png │ ├── characters-dark.png │ ├── characters.png │ ├── episode-detail-dark.png │ ├── episode-detail.png │ ├── episodes-dark.png │ ├── episodes.png │ ├── location-detail-dark.png │ ├── location-detail.png │ ├── locations-dark.png │ ├── locations.png │ ├── settings-dark.png │ ├── settings.png │ └── splash.png │ ├── desktop │ ├── home-dark.png │ └── home.png │ ├── ios │ ├── abouts-dark.png │ ├── abouts.png │ ├── character-detail-dark.png │ ├── character-detail.png │ ├── characters-dark.png │ ├── characters.png │ ├── episode-detail-dark.png │ ├── episode-detail.png │ ├── episodes-dark.png │ ├── episodes.png │ ├── location-detail-dark.png │ ├── location-detail.png │ ├── locations-dark.png │ ├── locations.png │ ├── settings-dark.png │ ├── settings.png │ └── splash.png │ └── web │ ├── home-dark.png │ └── home.png ├── assets ├── fonts │ ├── raleway_bold.ttf │ ├── raleway_medium.ttf │ ├── raleway_regular.ttf │ └── raleway_semi_bold.ttf ├── images │ ├── ic_app_logo.jpeg │ ├── ic_profile.png │ ├── ic_splash.png │ ├── intro_1.jpeg │ ├── intro_2.jpeg │ └── intro_3.png └── resources │ ├── en-US.json │ └── tr-TR.json ├── flutter_native_splash.yaml ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ ├── Contents.json │ ├── LaunchBackground.imageset │ │ ├── Contents.json │ │ ├── background.png │ │ └── darkbackground.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ ├── LaunchImageDark.png │ │ ├── LaunchImageDark@2x.png │ │ └── LaunchImageDark@3x.png │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── app │ ├── di │ │ └── injector.dart │ ├── language │ │ ├── app_language_provider.dart │ │ └── language_manager.dart │ ├── theme │ │ ├── app_color.dart │ │ ├── app_theme.dart │ │ └── app_theme_provider.dart │ ├── utils │ │ ├── constants.dart │ │ └── extension │ │ │ ├── list_methods.dart │ │ │ ├── platform_extension.dart │ │ │ └── string_methods.dart │ └── widgets │ │ ├── app_bar.dart │ │ ├── character_status_view.dart │ │ ├── circular_dot_view.dart │ │ ├── empty_screen.dart │ │ ├── error_screen.dart │ │ ├── favorite_button.dart │ │ ├── line_view.dart │ │ └── loading_screen.dart ├── core │ ├── base_view_model.dart │ ├── use_case.dart │ └── view_state.dart ├── data │ ├── local │ │ └── data_local_source.dart │ ├── model │ │ ├── dto │ │ │ ├── character │ │ │ │ ├── character_dto.dart │ │ │ │ ├── character_dto_extension.dart │ │ │ │ ├── character_location_dto.dart │ │ │ │ └── character_status.dart │ │ │ ├── episode │ │ │ │ ├── episode_dto.dart │ │ │ │ └── episode_dto_extension.dart │ │ │ └── location │ │ │ │ ├── location_dto.dart │ │ │ │ └── location_dto_extension.dart │ │ └── remote │ │ │ ├── base │ │ │ └── PageInfo.dart │ │ │ ├── character │ │ │ ├── CharacterInfo.dart │ │ │ ├── CharacterResponse.dart │ │ │ ├── Location.dart │ │ │ └── Origin.dart │ │ │ ├── episode │ │ │ ├── EpisodeInfo.dart │ │ │ └── EpisodeResponse.dart │ │ │ └── location │ │ │ ├── LocationInfo.dart │ │ │ └── LocationResponse.dart │ ├── remote │ │ ├── dio │ │ │ ├── data_state.dart │ │ │ ├── dio_exception.dart │ │ │ ├── dio_factory.dart │ │ │ └── logging_interceptor.dart │ │ └── service │ │ │ ├── character │ │ │ ├── character_service.dart │ │ │ └── character_service.g.dart │ │ │ ├── episode │ │ │ ├── episode_service.dart │ │ │ └── episode_service.g.dart │ │ │ └── location │ │ │ ├── location_service.dart │ │ │ └── location_service.g.dart │ └── repository │ │ ├── character_repository.dart │ │ ├── episode_repository.dart │ │ └── location_repository.dart ├── domain │ ├── character │ │ ├── favorite │ │ │ ├── add_character_favorite.dart │ │ │ ├── delete_character_favorite.dart │ │ │ ├── get_character_favorites.dart │ │ │ └── update_character_favorite.dart │ │ ├── get_character_detail.dart │ │ └── get_characters.dart │ ├── episode │ │ ├── favorite │ │ │ ├── add_episode_favorite.dart │ │ │ ├── delete_episode_favorite.dart │ │ │ ├── get_episode_favorites.dart │ │ │ └── update_episode_favorite.dart │ │ ├── get_episode_detail.dart │ │ └── get_episodes.dart │ └── location │ │ ├── favorite │ │ ├── add_location_favorite.dart │ │ ├── delete_location_favorite.dart │ │ ├── get_location_favorites.dart │ │ └── update_location_favorite.dart │ │ ├── get_location_detail.dart │ │ └── get_locations.dart ├── main.dart └── presentation │ ├── characters │ ├── detail │ │ ├── character_detail_screen.dart │ │ └── character_detail_view_model.dart │ └── list │ │ ├── characters_screen.dart │ │ └── characters_view_model.dart │ ├── episodes │ ├── detail │ │ ├── episode_detail_screen.dart │ │ └── episode_detail_view_model.dart │ └── list │ │ ├── episodes_screen.dart │ │ └── episodes_view_model.dart │ ├── home │ ├── home_screen.dart │ └── home_view_model.dart │ ├── locations │ ├── detail │ │ ├── location_detail_screen.dart │ │ └── location_detail_view_model.dart │ └── list │ │ ├── locations_screen.dart │ │ └── locations_view_model.dart │ └── settings │ ├── about │ └── about_screen.dart │ ├── language │ └── language_screen.dart │ └── settings_screen.dart ├── macos ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── app_icon_1024.png │ │ ├── app_icon_128.png │ │ ├── app_icon_16.png │ │ ├── app_icon_256.png │ │ ├── app_icon_32.png │ │ ├── app_icon_512.png │ │ └── app_icon_64.png │ ├── Base.lproj │ └── MainMenu.xib │ ├── Configs │ ├── AppInfo.xcconfig │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── Warnings.xcconfig │ ├── DebugProfile.entitlements │ ├── Info.plist │ ├── MainFlutterWindow.swift │ └── Release.entitlements ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart └── web ├── favicon.png ├── icons ├── Icon-192.png ├── Icon-512.png ├── Icon-maskable-192.png └── Icon-maskable-512.png ├── index.html ├── manifest.json └── splash ├── img ├── dark-1x.png ├── dark-2x.png ├── dark-3x.png ├── dark-4x.png ├── light-1x.png ├── light-2x.png ├── light-3x.png └── light-4x.png ├── splash.js └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Web related 36 | lib/generated_plugin_registrant.dart 37 | 38 | # Symbolication related 39 | app.*.symbols 40 | 41 | # Obfuscation related 42 | app.*.map.json 43 | 44 | # Android Studio will place build artifacts here 45 | /android/app/debug 46 | /android/app/profile 47 | /android/app/release 48 | /.metadata 49 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | 7 | def localProperties = new Properties() 8 | def localPropertiesFile = rootProject.file('local.properties') 9 | if (localPropertiesFile.exists()) { 10 | localPropertiesFile.withReader('UTF-8') { reader -> 11 | localProperties.load(reader) 12 | } 13 | } 14 | 15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 16 | if (flutterVersionCode == null) { 17 | flutterVersionCode = '1' 18 | } 19 | 20 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 21 | if (flutterVersionName == null) { 22 | flutterVersionName = '1.0' 23 | } 24 | 25 | android { 26 | compileSdkVersion flutter.compileSdkVersion 27 | ndkVersion flutter.ndkVersion 28 | 29 | compileOptions { 30 | sourceCompatibility JavaVersion.VERSION_1_8 31 | targetCompatibility JavaVersion.VERSION_1_8 32 | } 33 | 34 | kotlinOptions { 35 | jvmTarget = '1.8' 36 | } 37 | 38 | sourceSets { 39 | main.java.srcDirs += 'src/main/kotlin' 40 | } 41 | 42 | defaultConfig { 43 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 44 | applicationId "com.developersancho.rorty.rorty_flutter" 45 | // You can update the following values to match your application needs. 46 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. 47 | minSdkVersion flutter.minSdkVersion 48 | targetSdkVersion flutter.targetSdkVersion 49 | versionCode flutterVersionCode.toInteger() 50 | versionName flutterVersionName 51 | } 52 | 53 | buildTypes { 54 | release { 55 | // TODO: Add your own signing config for the release build. 56 | // Signing with the debug keys for now, so `flutter run --release` works. 57 | signingConfig signingConfigs.debug 58 | } 59 | } 60 | } 61 | 62 | flutter { 63 | source '../..' 64 | } 65 | 66 | dependencies { 67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${kotlin_version}" 68 | } 69 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 10 | 18 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/developersancho/rorty/rorty_flutter/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.developersancho.rorty.rorty_flutter 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-hdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-hdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-mdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-mdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-hdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-night-hdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-night-hdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-mdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-night-mdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-night-mdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-night-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-night-xhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-night-xhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xxhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-night-xxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-night-xxxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-night/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-xhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-xhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-xxhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-xxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-xxxhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable-xxxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/drawable/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 16 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 17 | 20 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 16 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #252941 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 17 | 20 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = '../build' 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(':app') 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | kotlin_version = 1.9.10 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "7.3.0" apply false 22 | id "org.jetbrains.kotlin.android" version "${kotlin_version}" apply false 23 | } 24 | 25 | include ":app" -------------------------------------------------------------------------------- /art/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/architecture.png -------------------------------------------------------------------------------- /art/architecturecircles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/architecturecircles.png -------------------------------------------------------------------------------- /art/clean_arch.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/clean_arch.jpeg -------------------------------------------------------------------------------- /art/flutter-logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/flutter-logo.webp -------------------------------------------------------------------------------- /art/project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/project.png -------------------------------------------------------------------------------- /art/screenshots/android/abouts-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/abouts-dark.png -------------------------------------------------------------------------------- /art/screenshots/android/abouts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/abouts.png -------------------------------------------------------------------------------- /art/screenshots/android/character-detail-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/character-detail-dark.png -------------------------------------------------------------------------------- /art/screenshots/android/character-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/character-detail.png -------------------------------------------------------------------------------- /art/screenshots/android/characters-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/characters-dark.png -------------------------------------------------------------------------------- /art/screenshots/android/characters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/characters.png -------------------------------------------------------------------------------- /art/screenshots/android/episode-detail-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/episode-detail-dark.png -------------------------------------------------------------------------------- /art/screenshots/android/episode-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/episode-detail.png -------------------------------------------------------------------------------- /art/screenshots/android/episodes-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/episodes-dark.png -------------------------------------------------------------------------------- /art/screenshots/android/episodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/episodes.png -------------------------------------------------------------------------------- /art/screenshots/android/location-detail-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/location-detail-dark.png -------------------------------------------------------------------------------- /art/screenshots/android/location-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/location-detail.png -------------------------------------------------------------------------------- /art/screenshots/android/locations-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/locations-dark.png -------------------------------------------------------------------------------- /art/screenshots/android/locations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/locations.png -------------------------------------------------------------------------------- /art/screenshots/android/settings-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/settings-dark.png -------------------------------------------------------------------------------- /art/screenshots/android/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/settings.png -------------------------------------------------------------------------------- /art/screenshots/android/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/android/splash.png -------------------------------------------------------------------------------- /art/screenshots/desktop/home-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/desktop/home-dark.png -------------------------------------------------------------------------------- /art/screenshots/desktop/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/desktop/home.png -------------------------------------------------------------------------------- /art/screenshots/ios/abouts-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/abouts-dark.png -------------------------------------------------------------------------------- /art/screenshots/ios/abouts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/abouts.png -------------------------------------------------------------------------------- /art/screenshots/ios/character-detail-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/character-detail-dark.png -------------------------------------------------------------------------------- /art/screenshots/ios/character-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/character-detail.png -------------------------------------------------------------------------------- /art/screenshots/ios/characters-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/characters-dark.png -------------------------------------------------------------------------------- /art/screenshots/ios/characters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/characters.png -------------------------------------------------------------------------------- /art/screenshots/ios/episode-detail-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/episode-detail-dark.png -------------------------------------------------------------------------------- /art/screenshots/ios/episode-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/episode-detail.png -------------------------------------------------------------------------------- /art/screenshots/ios/episodes-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/episodes-dark.png -------------------------------------------------------------------------------- /art/screenshots/ios/episodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/episodes.png -------------------------------------------------------------------------------- /art/screenshots/ios/location-detail-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/location-detail-dark.png -------------------------------------------------------------------------------- /art/screenshots/ios/location-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/location-detail.png -------------------------------------------------------------------------------- /art/screenshots/ios/locations-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/locations-dark.png -------------------------------------------------------------------------------- /art/screenshots/ios/locations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/locations.png -------------------------------------------------------------------------------- /art/screenshots/ios/settings-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/settings-dark.png -------------------------------------------------------------------------------- /art/screenshots/ios/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/settings.png -------------------------------------------------------------------------------- /art/screenshots/ios/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/ios/splash.png -------------------------------------------------------------------------------- /art/screenshots/web/home-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/web/home-dark.png -------------------------------------------------------------------------------- /art/screenshots/web/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/art/screenshots/web/home.png -------------------------------------------------------------------------------- /assets/fonts/raleway_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/assets/fonts/raleway_bold.ttf -------------------------------------------------------------------------------- /assets/fonts/raleway_medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/assets/fonts/raleway_medium.ttf -------------------------------------------------------------------------------- /assets/fonts/raleway_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/assets/fonts/raleway_regular.ttf -------------------------------------------------------------------------------- /assets/fonts/raleway_semi_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/assets/fonts/raleway_semi_bold.ttf -------------------------------------------------------------------------------- /assets/images/ic_app_logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/assets/images/ic_app_logo.jpeg -------------------------------------------------------------------------------- /assets/images/ic_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/assets/images/ic_profile.png -------------------------------------------------------------------------------- /assets/images/ic_splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/assets/images/ic_splash.png -------------------------------------------------------------------------------- /assets/images/intro_1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/assets/images/intro_1.jpeg -------------------------------------------------------------------------------- /assets/images/intro_2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/assets/images/intro_2.jpeg -------------------------------------------------------------------------------- /assets/images/intro_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/assets/images/intro_3.png -------------------------------------------------------------------------------- /assets/resources/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "characters": "Characters", 3 | "episodes": "Episodes", 4 | "locations": "Locations", 5 | "settings": "Settings", 6 | "character_detail": "Character Detail", 7 | "episode_detail": "Episode Detail", 8 | "location_detail": "Location Detail", 9 | "app_language": "App Language", 10 | "app_version": "App Version", 11 | "theme_mode": "Theme Mode", 12 | "abouts": "Abouts", 13 | "turkish": "Turkish", 14 | "english": "English", 15 | "languageChangeTitle": "Language Change", 16 | "languageChangeSubtitle": "You can change application language", 17 | "episode": "Episode", 18 | "dimension": "Dimension", 19 | "air_date": "Air Date", 20 | "species": "Species", 21 | "gender": "Gender", 22 | "type": "Type", 23 | "last_know_location": "Last Know Location", 24 | "location": "Location", 25 | "name": "Name", 26 | "information": "Information" 27 | } -------------------------------------------------------------------------------- /assets/resources/tr-TR.json: -------------------------------------------------------------------------------- 1 | { 2 | "characters": "Karakterler", 3 | "episodes": "Bölümler", 4 | "locations": "Konumlar", 5 | "settings": "Ayarlar", 6 | "character_detail": "Karakter Detay", 7 | "episode_detail": "Bölüm Detay", 8 | "location_detail": "Konum Detay", 9 | "app_language": "Uygulama Dili", 10 | "app_version": "Uygulama Versiyonu", 11 | "theme_mode": "Tema Modu", 12 | "abouts": "Hakkımızda", 13 | "turkish": "Türkçe", 14 | "english": "İngilizce", 15 | "languageChangeTitle": "Dili Değiştir", 16 | "languageChangeSubtitle": "Uygulama dilini değiştirebilirsiniz", 17 | "episode": "Bölüm", 18 | "dimension": "Boyut", 19 | "air_date": "Hava Tarihi", 20 | "species": "Türler", 21 | "gender": "Cinsiyet", 22 | "type": "Tip", 23 | "last_know_location": "Son Bilinen Konum", 24 | "location": "Konum", 25 | "name": "İsim", 26 | "information": "Bilgi" 27 | } -------------------------------------------------------------------------------- /flutter_native_splash.yaml: -------------------------------------------------------------------------------- 1 | flutter_native_splash: 2 | # flutter pub run flutter_native_splash:create 3 | # To restore Flutter's default white splash screen, run the following command in the terminal: 4 | # flutter pub run flutter_native_splash:remove 5 | color: "#252941" 6 | #background_image: "assets/background.png" 7 | 8 | # The image parameter allows you to specify an image used in the splash screen. It must be a 9 | # png file and should be sized for 4x pixel density. 10 | image: assets/images/ic_splash.png 11 | 12 | # The branding property allows you to specify an image used as branding in the splash screen. 13 | # It must be a png file. Currently, it is only supported for Android < v12 and iOS. 14 | #branding: assets/dart.png 15 | 16 | # To position the branding image at the bottom of the screen you can use bottom, bottomRight, 17 | # and bottomLeft. The default values is bottom if not specified or specified something else. 18 | #branding_mode: bottom 19 | 20 | # The color_dark, background_image_dark, image_dark, branding_dark are parameters that set the background 21 | # and image when the device is in dark mode. If they are not specified, the app will use the 22 | # parameters from above. If the image_dark parameter is specified, color_dark or 23 | # background_image_dark must be specified. color_dark and background_image_dark cannot both be 24 | # set. 25 | color_dark: "#252941" 26 | #background_image_dark: "assets/dark-background.png" 27 | image_dark: assets/images/ic_splash.png 28 | #branding_dark: assets/dart_dark.png 29 | 30 | # Android 12 handles the splash screen differently than previous versions. Please visit 31 | # https://developer.android.com/guide/topics/ui/splash-screen 32 | # Following are Android 12 specific parameter. 33 | android_12: 34 | # The image parameter sets the splash screen icon image. If this parameter is not specified, 35 | # the app's launcher icon will be used instead. 36 | # Please note that the splash screen will be clipped to a circle on the center of the screen. 37 | # App icon with an icon background: This should be 960×960 pixels, and fit within a circle 38 | # 640 pixels in diameter. 39 | # App icon without an icon background: This should be 1152×1152 pixels, and fit within a circle 40 | # 768 pixels in diameter. 41 | image: assets/images/ic_splash.png 42 | 43 | # Splash screen background color. 44 | color: "#252941" 45 | 46 | # App icon background color. 47 | #icon_background_color: "#111111" 48 | 49 | # The image_dark parameter and icon_background_color_dark set the image and icon background 50 | # color when the device is in dark mode. If they are not specified, the app will use the 51 | # parameters from above. 52 | image_dark: assets/images/ic_splash.png 53 | color_dark: "#252941" 54 | #icon_background_color_dark: "#eeeeee" 55 | 56 | # The android, ios and web parameters can be used to disable generating a splash screen on a given 57 | # platform. 58 | android: true 59 | ios: true 60 | web: false 61 | 62 | # The position of the splash image can be set with android_gravity, ios_content_mode, and 63 | # web_image_mode parameters. All default to center. 64 | # 65 | # android_gravity can be one of the following Android Gravity (see 66 | # https://developer.android.com/reference/android/view/Gravity): bottom, center, 67 | # center_horizontal, center_vertical, clip_horizontal, clip_vertical, end, fill, fill_horizontal, 68 | # fill_vertical, left, right, start, or top. 69 | android_gravity: center 70 | # 71 | # ios_content_mode can be one of the following iOS UIView.ContentMode (see 72 | # https://developer.apple.com/documentation/uikit/uiview/contentmode): scaleToFill, 73 | # scaleAspectFit, scaleAspectFill, center, top, bottom, left, right, topLeft, topRight, 74 | # bottomLeft, or bottomRight. 75 | ios_content_mode: center 76 | # 77 | # web_image_mode can be one of the following modes: center, contain, stretch, and cover. 78 | #web_image_mode: center 79 | 80 | # The screen orientation can be set in Android with the android_screen_orientation parameter. 81 | # Valid parameters can be found here: 82 | # https://developer.android.com/guide/topics/manifest/activity-element#screen 83 | #android_screen_orientation: sensorLandscape 84 | 85 | # To hide the notification bar, use the fullscreen parameter. Has no effect in web since web 86 | # has no notification bar. Defaults to false. 87 | # NOTE: Unlike Android, iOS will not automatically show the notification bar when the app loads. 88 | # To show the notification bar, add the following code to your Flutter app: 89 | # WidgetsFlutterBinding.ensureInitialized(); 90 | # SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom, SystemUiOverlay.top]); 91 | #fullscreen: true 92 | 93 | # If you have changed the name(s) of your info.plist file(s), you can specify the filename(s) 94 | # with the info_plist_files parameter. Remove only the # characters in the three lines below, 95 | # do not remove any spaces: 96 | #info_plist_files: 97 | # - 'ios/Runner/Info-Debug.plist' 98 | # - 'ios/Runner/Info-Release.plist' -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 9.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - flutter_native_splash (0.0.1): 4 | - Flutter 5 | - shared_preferences_ios (0.0.1): 6 | - Flutter 7 | - url_launcher_ios (0.0.1): 8 | - Flutter 9 | 10 | DEPENDENCIES: 11 | - Flutter (from `Flutter`) 12 | - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) 13 | - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`) 14 | - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) 15 | 16 | EXTERNAL SOURCES: 17 | Flutter: 18 | :path: Flutter 19 | flutter_native_splash: 20 | :path: ".symlinks/plugins/flutter_native_splash/ios" 21 | shared_preferences_ios: 22 | :path: ".symlinks/plugins/shared_preferences_ios/ios" 23 | url_launcher_ios: 24 | :path: ".symlinks/plugins/url_launcher_ios/ios" 25 | 26 | SPEC CHECKSUMS: 27 | Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a 28 | flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef 29 | shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad 30 | url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de 31 | 32 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c 33 | 34 | COCOAPODS: 1.11.3 35 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/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/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "background.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "filename" : "darkbackground.png", 16 | "idiom" : "universal", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "appearances" : [ 25 | { 26 | "appearance" : "luminosity", 27 | "value" : "dark" 28 | } 29 | ], 30 | "idiom" : "universal", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "universal", 35 | "scale" : "3x" 36 | }, 37 | { 38 | "appearances" : [ 39 | { 40 | "appearance" : "luminosity", 41 | "value" : "dark" 42 | } 43 | ], 44 | "idiom" : "universal", 45 | "scale" : "3x" 46 | } 47 | ], 48 | "info" : { 49 | "author" : "xcode", 50 | "version" : 1 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "LaunchImage.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "filename" : "LaunchImageDark.png", 16 | "idiom" : "universal", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "filename" : "LaunchImage@2x.png", 21 | "idiom" : "universal", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "appearances" : [ 26 | { 27 | "appearance" : "luminosity", 28 | "value" : "dark" 29 | } 30 | ], 31 | "filename" : "LaunchImageDark@2x.png", 32 | "idiom" : "universal", 33 | "scale" : "2x" 34 | }, 35 | { 36 | "filename" : "LaunchImage@3x.png", 37 | "idiom" : "universal", 38 | "scale" : "3x" 39 | }, 40 | { 41 | "appearances" : [ 42 | { 43 | "appearance" : "luminosity", 44 | "value" : "dark" 45 | } 46 | ], 47 | "filename" : "LaunchImageDark@3x.png", 48 | "idiom" : "universal", 49 | "scale" : "3x" 50 | } 51 | ], 52 | "info" : { 53 | "author" : "xcode", 54 | "version" : 1 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png -------------------------------------------------------------------------------- /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 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleLocalizations 6 | 7 | en 8 | tr 9 | 10 | CFBundleDevelopmentRegion 11 | $(DEVELOPMENT_LANGUAGE) 12 | CFBundleDisplayName 13 | Rorty Flutter 14 | CFBundleExecutable 15 | $(EXECUTABLE_NAME) 16 | CFBundleIdentifier 17 | $(PRODUCT_BUNDLE_IDENTIFIER) 18 | CFBundleInfoDictionaryVersion 19 | 6.0 20 | CFBundleName 21 | rorty_flutter 22 | CFBundlePackageType 23 | APPL 24 | CFBundleShortVersionString 25 | $(FLUTTER_BUILD_NAME) 26 | CFBundleSignature 27 | ???? 28 | CFBundleVersion 29 | $(FLUTTER_BUILD_NUMBER) 30 | LSRequiresIPhoneOS 31 | 32 | UILaunchStoryboardName 33 | LaunchScreen 34 | UIMainStoryboardFile 35 | Main 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | UIViewControllerBasedStatusBarAppearance 50 | 51 | CADisableMinimumFrameDurationOnPhone 52 | 53 | UIStatusBarHidden 54 | 55 | 56 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/app/di/injector.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:get_it/get_it.dart'; 3 | import 'package:rorty_flutter/app/utils/constants.dart'; 4 | import 'package:rorty_flutter/data/remote/dio/dio_factory.dart'; 5 | import 'package:rorty_flutter/data/remote/service/character/character_service.dart'; 6 | import 'package:rorty_flutter/data/remote/service/episode/episode_service.dart'; 7 | import 'package:rorty_flutter/data/remote/service/location/location_service.dart'; 8 | import 'package:rorty_flutter/data/repository/character_repository.dart'; 9 | import 'package:rorty_flutter/data/repository/episode_repository.dart'; 10 | import 'package:rorty_flutter/data/repository/location_repository.dart'; 11 | import 'package:rorty_flutter/domain/character/get_character_detail.dart'; 12 | import 'package:rorty_flutter/domain/character/get_characters.dart'; 13 | import 'package:rorty_flutter/domain/episode/get_episode_detail.dart'; 14 | import 'package:rorty_flutter/domain/episode/get_episodes.dart'; 15 | import 'package:rorty_flutter/domain/location/get_location_detail.dart'; 16 | import 'package:rorty_flutter/domain/location/get_locations.dart'; 17 | import 'package:rorty_flutter/presentation/characters/detail/character_detail_view_model.dart'; 18 | 19 | final injector = GetIt.instance; 20 | 21 | Future initializeDependencies() async { 22 | // Dio client 23 | injector.registerSingleton(DioFactory(rBaseUrl).create()); 24 | 25 | // Data - Remote 26 | injector.registerSingleton(CharacterService(injector())); 27 | injector.registerSingleton(EpisodeService(injector())); 28 | injector.registerSingleton(LocationService(injector())); 29 | 30 | // Data - Local 31 | 32 | // Data - Repository 33 | injector.registerSingleton(CharacterRepository(injector())); 34 | injector.registerSingleton(EpisodeRepository(injector())); 35 | injector.registerSingleton(LocationRepository(injector())); 36 | 37 | // Domain 38 | injector.registerSingleton(GetCharacters(injector())); 39 | injector.registerSingleton(GetCharacterDetail(injector(), injector())); 40 | 41 | injector.registerSingleton(GetEpisodes(injector())); 42 | injector.registerSingleton(GetEpisodeDetail(injector(), injector())); 43 | 44 | injector.registerSingleton(GetLocations(injector())); 45 | injector.registerSingleton(GetLocationDetail(injector(), injector())); 46 | 47 | // ViewModel 48 | //injector.registerFactory(() => CharactersViewModel()); 49 | injector.registerFactory(() => CharacterDetailViewModel()); 50 | } 51 | -------------------------------------------------------------------------------- /lib/app/language/app_language_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AppLanguage { 5 | final Locale locale; 6 | final String language; 7 | 8 | AppLanguage(this.locale, this.language); 9 | } 10 | 11 | class AppLanguageProvider extends ChangeNotifier { 12 | static const turkish = Locale('tr', 'TR'); 13 | static const english = Locale('en', 'US'); 14 | 15 | final languageList = [ 16 | AppLanguage(turkish, tr("turkish")), 17 | AppLanguage(english, tr("english")) 18 | ]; 19 | 20 | Locale _locale = english; 21 | 22 | Locale get locale => _locale; 23 | 24 | void changeLanguage(Locale locale) async { 25 | _locale = locale; 26 | notifyListeners(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/app/language/language_manager.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | class LanguageManager { 4 | static LanguageManager? _instance; 5 | 6 | static LanguageManager? get instance { 7 | _instance ??= LanguageManager._init(); 8 | return _instance; 9 | } 10 | 11 | LanguageManager._init(); 12 | 13 | final enLocale = const Locale('en', 'US'); 14 | final trLocale = const Locale('tr', 'TR'); 15 | 16 | List get supportedLocales => [enLocale, trLocale]; 17 | } 18 | -------------------------------------------------------------------------------- /lib/app/theme/app_color.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | // 4 | // val Colors.navigationBackIconColor: Color 5 | // @Composable get() = if (isLight) navigationBackIconLight else navigationBackIconDark 6 | // 7 | // val Colors.dividerColor: Color 8 | // @Composable get() = if (isLight) DividerLight else DividerDark 9 | // 10 | // val Colors.backgroundColor: Color 11 | // @Composable get() = if (isLight) BackgroundLight else BackgroundDark 12 | // 13 | // val Colors.cardBackgroundColor: Color 14 | // @Composable get() = if (isLight) CardLight else CardDark 15 | 16 | class AppColor { 17 | static Color Black = const Color(0xFF000000); 18 | static Color White = const Color(0xFFFFFFFF); 19 | static Color Transparent = const Color(0x00000000); 20 | static Color Blue = const Color(0xFF252941); 21 | 22 | static Color BlueDark = const Color(0xFF05060B); 23 | static Color Red = const Color(0xFFD13438); 24 | static Color RedDark = const Color(0xFF982626); 25 | 26 | static Color CardDark = const Color(0xFF3B3E43); 27 | static Color CardLight = White; 28 | 29 | static Color BackgroundLight = const Color(0xFFF5F2F5); 30 | static Color BackgroundDark = const Color(0xFF24292E); 31 | 32 | static Color DividerLight = const Color(0xFFE0E0E0); 33 | static Color DividerDark = const Color(0xFF6E6E6E); 34 | 35 | static Color GrayCircle = const Color(0xFF919191); 36 | static Color RedCircle = const Color(0xFFD50000); 37 | static Color GreenCircle = const Color(0xFF00C853); 38 | static Color BorderLine = const Color(0xFFE5E5EA); 39 | 40 | static Color Red700 = const Color(0xFFD32F2F); 41 | 42 | static Color Gray25 = const Color(0xFFF8F8F8); 43 | static Color Gray50 = const Color(0xFFF1F1F1); 44 | static Color Gray75 = const Color(0xFFECECEC); 45 | static Color Gray100 = const Color(0xFFE1E1E1); 46 | static Color Gray200 = const Color(0xFFEEEEEE); 47 | static Color Gray300 = const Color(0xFFACACAC); 48 | static Color Gray400 = const Color(0xFF919191); 49 | static Color Gray500 = const Color(0xFF6E6E6E); 50 | static Color Gray600 = const Color(0xFF535353); 51 | static Color Gray700 = const Color(0xFF616161); 52 | static Color Gray800 = const Color(0xFF292929); 53 | static Color Gray900 = const Color(0xFF212121); 54 | static Color Gray950 = const Color(0xFF141414); 55 | 56 | static Color selectedBottomItemColor = Red; 57 | static Color unselectedBottomItemColor = Gray500; 58 | 59 | static Color navigationBackIconDark = White; 60 | static Color navigationBackIconLight = Black; 61 | } 62 | -------------------------------------------------------------------------------- /lib/app/theme/app_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | 4 | import 'app_color.dart'; 5 | 6 | class AppTheme { 7 | static ThemeData get lightTheme { 8 | return ThemeData( 9 | primaryColor: AppColor.White, 10 | primaryColorLight: AppColor.White, 11 | primaryColorDark: AppColor.Blue, 12 | appBarTheme: AppBarTheme( 13 | elevation: 2, 14 | iconTheme: IconThemeData(color: AppColor.Black), 15 | backgroundColor: AppColor.White, 16 | titleTextStyle: TextStyle( 17 | color: AppColor.Black, 18 | fontSize: 16, 19 | fontFamily: 'Raleway', 20 | fontWeight: FontWeight.w800), 21 | systemOverlayStyle: SystemUiOverlayStyle.dark 22 | .copyWith(statusBarColor: AppColor.White)), 23 | scaffoldBackgroundColor: AppColor.BackgroundLight, 24 | cardColor: AppColor.CardLight, 25 | bottomNavigationBarTheme: BottomNavigationBarThemeData( 26 | backgroundColor: AppColor.White, 27 | elevation: 8, 28 | selectedItemColor: AppColor.selectedBottomItemColor, 29 | unselectedItemColor: AppColor.unselectedBottomItemColor, 30 | type: BottomNavigationBarType.fixed, 31 | selectedLabelStyle: 32 | TextStyle(fontSize: 13, fontWeight: FontWeight.w500), 33 | unselectedLabelStyle: 34 | TextStyle(fontSize: 12, fontWeight: FontWeight.w500), 35 | ), 36 | dividerColor: AppColor.DividerLight, 37 | splashColor: AppColor.Transparent, 38 | iconTheme: IconThemeData(color: AppColor.Black), 39 | fontFamily: 'Raleway', 40 | textTheme: ThemeData.light().textTheme, 41 | progressIndicatorTheme: ProgressIndicatorThemeData(color: AppColor.Red700), 42 | buttonTheme: ButtonThemeData( 43 | shape: 44 | RoundedRectangleBorder(borderRadius: BorderRadius.circular(18.0)), 45 | buttonColor: AppColor.Red, 46 | )); 47 | } 48 | 49 | static ThemeData get darkTheme { 50 | return ThemeData( 51 | primaryColor: AppColor.Blue, 52 | primaryColorLight: AppColor.White, 53 | primaryColorDark: AppColor.Blue, 54 | appBarTheme: AppBarTheme( 55 | elevation: 2, 56 | iconTheme: IconThemeData(color: AppColor.White), 57 | backgroundColor: AppColor.Blue, 58 | titleTextStyle: TextStyle( 59 | color: AppColor.White, 60 | fontSize: 16, 61 | fontFamily: 'Raleway', 62 | fontWeight: FontWeight.w800), 63 | systemOverlayStyle: SystemUiOverlayStyle( 64 | systemNavigationBarColor: AppColor.Blue, 65 | statusBarColor: AppColor.Blue, 66 | statusBarBrightness: Brightness.dark, 67 | statusBarIconBrightness: Brightness.light)), 68 | scaffoldBackgroundColor: AppColor.BackgroundDark, 69 | cardColor: AppColor.CardDark, 70 | bottomNavigationBarTheme: BottomNavigationBarThemeData( 71 | backgroundColor: AppColor.Blue, 72 | elevation: 8, 73 | selectedItemColor: AppColor.selectedBottomItemColor, 74 | unselectedItemColor: AppColor.unselectedBottomItemColor, 75 | type: BottomNavigationBarType.fixed, 76 | selectedLabelStyle: 77 | TextStyle(fontSize: 13, fontWeight: FontWeight.w500), 78 | unselectedLabelStyle: 79 | TextStyle(fontSize: 12, fontWeight: FontWeight.w500), 80 | ), 81 | dividerColor: AppColor.DividerDark, 82 | splashColor: AppColor.Transparent, 83 | iconTheme: IconThemeData(color: AppColor.White), 84 | fontFamily: 'Raleway', 85 | textTheme: ThemeData.dark().textTheme, 86 | progressIndicatorTheme: ProgressIndicatorThemeData(color: AppColor.Red700), 87 | buttonTheme: ButtonThemeData( 88 | shape: 89 | RoundedRectangleBorder(borderRadius: BorderRadius.circular(18.0)), 90 | buttonColor: AppColor.Red, 91 | )); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/app/theme/app_theme_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:shared_preferences/shared_preferences.dart'; 3 | 4 | class AppThemeProvider extends ChangeNotifier { 5 | static const THEME_STATUS = "THEME_STATUS"; 6 | 7 | setTheme(bool value) async { 8 | SharedPreferences prefs = await SharedPreferences.getInstance(); 9 | prefs.setBool(THEME_STATUS, value); 10 | } 11 | 12 | Future getTheme() async { 13 | SharedPreferences prefs = await SharedPreferences.getInstance(); 14 | return prefs.getBool(THEME_STATUS) ?? false; 15 | } 16 | 17 | late bool _isDark; 18 | 19 | bool get isDark => _isDark; 20 | 21 | AppThemeProvider() { 22 | _isDark = false; 23 | getPreferences(); 24 | } 25 | 26 | //Switching themes in the flutter apps - Flutterant 27 | set isDark(bool value) { 28 | _isDark = value; 29 | setTheme(value); 30 | notifyListeners(); 31 | } 32 | 33 | getPreferences() async { 34 | _isDark = await getTheme(); 35 | notifyListeners(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/app/utils/constants.dart: -------------------------------------------------------------------------------- 1 | // API 2 | const String rBaseUrl = 'https://rickandmortyapi.com/api'; 3 | 4 | // Database 5 | const String rCharactersTableName = 'character_favorite'; 6 | const String rEpisodesTableName = 'episode_favorite'; 7 | const String rLocationsTableName = 'location_favorite'; 8 | 9 | const String rDatabaseName = 'RortyDb.db'; 10 | 11 | const LANGUAGE_ASSETS_PATH = 'assets/resources'; 12 | const githubLink = "https://github.com/developersancho"; 13 | const mediumLink = "https://medium.com/@developersancho"; 14 | -------------------------------------------------------------------------------- /lib/app/utils/extension/list_methods.dart: -------------------------------------------------------------------------------- 1 | extension ListExtensions on List? { 2 | List orEmpty() { 3 | return this ?? List.empty(); 4 | } 5 | } 6 | 7 | // public inline fun List?.orEmpty(): List = this ?: emptyList() -------------------------------------------------------------------------------- /lib/app/utils/extension/platform_extension.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:flutter/foundation.dart'; 3 | 4 | extension Target on Object { 5 | bool isAndroid() { 6 | return Platform.isAndroid; 7 | } 8 | 9 | bool isIOS() { 10 | return Platform.isIOS; 11 | } 12 | 13 | bool isLinux() { 14 | return Platform.isLinux; 15 | } 16 | 17 | bool isWindows() { 18 | return Platform.isWindows; 19 | } 20 | 21 | bool isMacOS() { 22 | return Platform.isMacOS; 23 | } 24 | 25 | bool isFuchsia() { 26 | return Platform.isFuchsia; 27 | } 28 | 29 | bool isWeb() { 30 | return kIsWeb; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/app/utils/extension/string_methods.dart: -------------------------------------------------------------------------------- 1 | extension StringExtensions on String? { 2 | /// Returns `true` if this nullable char sequence is either `null` or empty. 3 | bool isNullOrEmpty() { 4 | return this == null || this!.isEmpty; 5 | } 6 | 7 | /// Returns `false` if this nullable char sequence is either `null` or empty. 8 | bool isNotNullOrEmpty() { 9 | return this != null && this!.isNotEmpty; 10 | } 11 | 12 | /// Returns a progression that goes over the same range in the opposite direction with the same step. 13 | String reversed() { 14 | var res = ""; 15 | for (int i = this!.length; i >= 0; --i) { 16 | res = this![i]; 17 | } 18 | return res; 19 | } 20 | 21 | /// Returns the value of this number as an [int] 22 | int toInt() => int.parse(this!); 23 | 24 | /// Returns the value of this number as an [int] or null if can not be parsed. 25 | int? toIntOrNull() { 26 | if (this == null) return null; 27 | return int.tryParse(this!); 28 | } 29 | 30 | /// Returns the value of this number as an [double] 31 | double toDouble() => double.parse(this!); 32 | 33 | /// Returns the value of this number as an [double] or null if can not be parsed. 34 | double? toDoubleOrNull() { 35 | if (this == null) return null; 36 | return double.tryParse(this!); 37 | } 38 | 39 | /// Returns true if 'this' is "true", otherwise - false 40 | bool toBoolean() => this?.toLowerCase() == "true"; 41 | 42 | /// Replaces part of string after the first occurrence of given delimiter with the [replacement] string. 43 | /// If the string does not contain the delimiter, returns [defaultValue] which defaults to the original string. 44 | String? replaceAfter(String delimiter, String replacement, 45 | [String? defaultValue]) { 46 | if (this == null) return null; 47 | final index = this!.indexOf(delimiter); 48 | return (index == -1) 49 | ? defaultValue!.isNullOrEmpty() 50 | ? this 51 | : defaultValue 52 | : this!.replaceRange(index + 1, this!.length, replacement); 53 | } 54 | 55 | /// Replaces part of string before the first occurrence of given delimiter with the [replacement] string. 56 | /// If the string does not contain the delimiter, returns [missingDelimiterValue!] which defaults to the original string. 57 | String? replaceBefore(String delimiter, String replacement, 58 | [String? defaultValue]) { 59 | if (this == null) return null; 60 | final index = this!.indexOf(delimiter); 61 | return (index == -1) 62 | ? defaultValue!.isNullOrEmpty() 63 | ? this 64 | : defaultValue 65 | : this!.replaceRange(0, index, replacement); 66 | } 67 | 68 | ///Returns `true` if at least one element matches the given [predicate]. 69 | /// the [predicate] should have only one character 70 | bool anyChar(bool predicate(String element)) => 71 | this?.split('').any((s) => predicate(s)) ?? false; 72 | 73 | /// Returns last symbol of string or empty string if `this` is null or empty 74 | String get last { 75 | if (this.isNullOrEmpty()) return ""; 76 | return this![this!.length - 1]; 77 | } 78 | 79 | /// Returns `true` if strings are equals without matching case 80 | bool equalsIgnoreCase(String? other) => 81 | (this == null && other == null) || 82 | (this != null && 83 | other != null && 84 | this?.toLowerCase() == other.toLowerCase()); 85 | 86 | /// Returns `true` if string contains another without matching case 87 | bool containsIgnoreCase(String? other) { 88 | if (other == null) return false; 89 | return this?.toLowerCase().contains(other.toLowerCase()) ?? false; 90 | } 91 | 92 | String orEmpty() { 93 | return this ?? ""; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/app/widgets/app_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:go_router/go_router.dart'; 3 | 4 | class RortyAppBar extends StatelessWidget implements PreferredSizeWidget { 5 | final String title; 6 | 7 | const RortyAppBar({ 8 | Key? key, 9 | required this.title, 10 | }) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return AppBar( 15 | title: Text(title), 16 | centerTitle: true, 17 | ); 18 | } 19 | 20 | @override 21 | Size get preferredSize => const Size.fromHeight(56); 22 | } 23 | 24 | class RortyAppBarWithBack extends StatelessWidget implements PreferredSizeWidget { 25 | final String title; 26 | 27 | const RortyAppBarWithBack({ 28 | Key? key, 29 | required this.title, 30 | }) : super(key: key); 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | return AppBar( 35 | title: Text(title), 36 | centerTitle: true, 37 | leading: IconButton( 38 | icon: const Icon(Icons.arrow_back), 39 | onPressed: () { 40 | context.pop(); 41 | }, 42 | ), 43 | ); 44 | } 45 | 46 | @override 47 | Size get preferredSize => const Size.fromHeight(56); 48 | } 49 | -------------------------------------------------------------------------------- /lib/app/widgets/character_status_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:rorty_flutter/app/widgets/circular_dot_view.dart'; 3 | import 'package:rorty_flutter/data/model/dto/character/character_status.dart'; 4 | 5 | class CharacterStatusView extends StatelessWidget { 6 | final String status; 7 | 8 | const CharacterStatusView({ 9 | Key? key, 10 | required this.status, 11 | }) : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Row( 16 | children: [ 17 | CircularDotView( 18 | isAlive: status == CharacterStatus.alive.status, 19 | isDead: status == CharacterStatus.dead.status, 20 | ), 21 | const SizedBox(width: 8), 22 | Text( 23 | status, 24 | style: const TextStyle( 25 | fontWeight: FontWeight.bold, 26 | fontSize: 13, 27 | ), 28 | ), 29 | ], 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/app/widgets/circular_dot_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CircularDotView extends StatelessWidget { 4 | final bool isAlive; 5 | final bool isDead; 6 | 7 | const CircularDotView({ 8 | Key? key, 9 | required this.isAlive, 10 | required this.isDead, 11 | }) : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | if (isAlive) { 16 | return _greenDot(); 17 | } else if (isDead) { 18 | return _redDot(); 19 | } else { 20 | return _greyDot(); 21 | } 22 | } 23 | 24 | Widget _redDot() { 25 | return Container( 26 | width: 10, 27 | height: 10, 28 | decoration: const BoxDecoration( 29 | shape: BoxShape.circle, 30 | color: Colors.red, 31 | ), 32 | ); 33 | } 34 | 35 | Widget _greenDot() { 36 | return Container( 37 | width: 10, 38 | height: 10, 39 | decoration: const BoxDecoration( 40 | shape: BoxShape.circle, 41 | color: Colors.green, 42 | ), 43 | ); 44 | } 45 | 46 | Widget _greyDot() { 47 | return Container( 48 | width: 10, 49 | height: 10, 50 | decoration: const BoxDecoration( 51 | shape: BoxShape.circle, 52 | color: Colors.grey, 53 | ), 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/app/widgets/empty_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class EmptyScreen extends StatelessWidget { 4 | const EmptyScreen({Key? key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Center( 9 | child: Column( 10 | mainAxisAlignment: MainAxisAlignment.center, 11 | children: [ 12 | Text("No Data Found") 13 | ], 14 | )); 15 | } 16 | } -------------------------------------------------------------------------------- /lib/app/widgets/error_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ErrorScreen extends StatelessWidget { 4 | const ErrorScreen({Key? key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Center( 9 | child: Column( 10 | mainAxisAlignment: MainAxisAlignment.center, 11 | children: [ 12 | CircularProgressIndicator(), 13 | SizedBox(height: 8,), 14 | Text("Error...") 15 | ], 16 | )); 17 | } 18 | } -------------------------------------------------------------------------------- /lib/app/widgets/favorite_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FavoriteButton extends StatefulWidget { 4 | FavoriteButton({ 5 | double? iconSize, 6 | Color? iconColor, 7 | Color? iconDisabledColor, 8 | bool? isFavorite, 9 | required Function valueChanged, 10 | Key? key, 11 | }) : _iconSize = iconSize ?? 60.0, 12 | _iconColor = iconColor ?? Colors.red, 13 | _iconDisabledColor = iconDisabledColor ?? Colors.grey[400], 14 | _isFavorite = isFavorite ?? false, 15 | _valueChanged = valueChanged, 16 | super(key: key); 17 | 18 | final double _iconSize; 19 | final Color _iconColor; 20 | final bool _isFavorite; 21 | final Function _valueChanged; 22 | final Color? _iconDisabledColor; 23 | 24 | @override 25 | _FavoriteButtonState createState() => _FavoriteButtonState(); 26 | } 27 | 28 | class _FavoriteButtonState extends State 29 | with TickerProviderStateMixin { 30 | late AnimationController _controller; 31 | late Animation _colorAnimation; 32 | late Animation _sizeAnimation; 33 | 34 | late CurvedAnimation _curve; 35 | 36 | double _maxIconSize = 0.0; 37 | double _minIconSize = 0.0; 38 | 39 | final int _animationTime = 400; 40 | 41 | bool _isFavorite = false; 42 | bool _isAnimationCompleted = false; 43 | 44 | @override 45 | void initState() { 46 | super.initState(); 47 | 48 | _isFavorite = widget._isFavorite; 49 | _maxIconSize = (widget._iconSize < 20.0) 50 | ? 20.0 51 | : (widget._iconSize > 100.0) 52 | ? 100.0 53 | : widget._iconSize; 54 | final double _sizeDifference = _maxIconSize * 0.30; 55 | _minIconSize = _maxIconSize - _sizeDifference; 56 | 57 | _controller = AnimationController( 58 | vsync: this, 59 | duration: Duration(milliseconds: _animationTime), 60 | ); 61 | 62 | _curve = CurvedAnimation(curve: Curves.slowMiddle, parent: _controller); 63 | Animation _selectedColorAnimation = ColorTween( 64 | begin: widget._iconColor, 65 | end: widget._iconDisabledColor, 66 | ).animate(_curve); 67 | 68 | Animation _deSelectedColorAnimation = ColorTween( 69 | begin: widget._iconDisabledColor, 70 | end: widget._iconColor, 71 | ).animate(_curve); 72 | 73 | _colorAnimation = (_isFavorite == true) 74 | ? _selectedColorAnimation 75 | : _deSelectedColorAnimation; 76 | _sizeAnimation = TweenSequence( 77 | >[ 78 | TweenSequenceItem( 79 | tween: Tween( 80 | begin: _minIconSize, 81 | end: _maxIconSize, 82 | ), 83 | weight: 50, 84 | ), 85 | TweenSequenceItem( 86 | tween: Tween( 87 | begin: _maxIconSize, 88 | end: _minIconSize, 89 | ), 90 | weight: 50, 91 | ), 92 | ], 93 | ).animate(_curve); 94 | 95 | _controller.addStatusListener((status) { 96 | if (status == AnimationStatus.completed) { 97 | _isAnimationCompleted = true; 98 | _isFavorite = !_isFavorite; 99 | widget._valueChanged(_isFavorite); 100 | } else if (status == AnimationStatus.dismissed) { 101 | _isAnimationCompleted = false; 102 | _isFavorite = !_isFavorite; 103 | widget._valueChanged(_isFavorite); 104 | } 105 | }); 106 | } 107 | 108 | @override 109 | void dispose() { 110 | super.dispose(); 111 | _controller.dispose(); 112 | } 113 | 114 | @override 115 | Widget build(BuildContext context) { 116 | return AnimatedBuilder( 117 | animation: _controller, 118 | builder: (BuildContext context, _) { 119 | return InkResponse( 120 | onTap: () { 121 | setState(() { 122 | if (_isAnimationCompleted == true) { 123 | _controller.reverse(); 124 | } else { 125 | _controller.forward(); 126 | } 127 | }); 128 | }, 129 | child: Icon( 130 | (Icons.favorite), 131 | color: _colorAnimation.value, 132 | size: _sizeAnimation.value, 133 | ), 134 | ); 135 | }, 136 | ); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /lib/app/widgets/line_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LineView extends StatelessWidget { 4 | const LineView({Key? key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return const Padding( 9 | padding: EdgeInsets.only(top: 8), 10 | child: Divider( 11 | height: 1, 12 | thickness: 1.0, 13 | ), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/app/widgets/loading_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LoadingScreen extends StatelessWidget { 4 | const LoadingScreen({Key? key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Center( 9 | child: Column( 10 | mainAxisAlignment: MainAxisAlignment.center, 11 | children: [ 12 | CircularProgressIndicator(), 13 | SizedBox(height: 8,), 14 | Text("Loading...") 15 | ], 16 | )); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/core/base_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | abstract class BaseViewModel extends ChangeNotifier { 4 | final GlobalKey scaffoldKey = GlobalKey(); 5 | final BuildContext context; 6 | bool isDisposing = false; 7 | 8 | BaseViewModel(this.context); 9 | 10 | Future initViewmodel() async { 11 | isDisposing = false; 12 | return Future.value(); 13 | } 14 | 15 | void triggerNotify({bool force = false}) { 16 | if (!force && isDisposing) return; 17 | notifyListeners(); 18 | } 19 | 20 | @override 21 | void dispose() { 22 | isDisposing = true; 23 | super.dispose(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/core/use_case.dart: -------------------------------------------------------------------------------- 1 | abstract class UseCase { 2 | Future call({required P params}); 3 | } 4 | -------------------------------------------------------------------------------- /lib/core/view_state.dart: -------------------------------------------------------------------------------- 1 | enum ResponseState { EMPTY, LOADING, COMPLETE, ERROR } 2 | 3 | class ViewState { 4 | ResponseState state; 5 | T? data; 6 | String? exception; 7 | 8 | ViewState({required this.state, this.data, this.exception}); 9 | 10 | static ViewState empty() { 11 | return ViewState(state: ResponseState.EMPTY); 12 | } 13 | 14 | static ViewState loading() { 15 | return ViewState(state: ResponseState.LOADING); 16 | } 17 | 18 | static ViewState complete(T data) { 19 | return ViewState(state: ResponseState.COMPLETE, data: data); 20 | } 21 | 22 | static ViewState error(String exception) { 23 | return ViewState(state: ResponseState.ERROR, exception: exception); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/data/local/data_local_source.dart: -------------------------------------------------------------------------------- 1 | class DataLocalSource {} 2 | -------------------------------------------------------------------------------- /lib/data/model/dto/character/character_dto.dart: -------------------------------------------------------------------------------- 1 | import 'package:rorty_flutter/data/model/dto/episode/episode_dto.dart'; 2 | 3 | import 'character_location_dto.dart'; 4 | 5 | class CharacterDto { 6 | final int? id; 7 | final String? name; 8 | final String? status; 9 | final String? species; 10 | final String? type; 11 | final String? gender; 12 | final CharacterLocationDto? origin; 13 | final CharacterLocationDto? location; 14 | final String? image; 15 | final List? episodes; 16 | final String? url; 17 | final String? created; 18 | List episodeDtoList = []; 19 | 20 | CharacterDto( 21 | this.id, 22 | this.name, 23 | this.status, 24 | this.species, 25 | this.type, 26 | this.gender, 27 | this.origin, 28 | this.location, 29 | this.image, 30 | this.episodes, 31 | this.url, 32 | this.created); 33 | } 34 | -------------------------------------------------------------------------------- /lib/data/model/dto/character/character_dto_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:rorty_flutter/data/model/remote/character/CharacterInfo.dart'; 2 | import 'package:rorty_flutter/data/model/remote/character/Location.dart'; 3 | import 'package:rorty_flutter/data/model/remote/character/Origin.dart'; 4 | 5 | import 'character_dto.dart'; 6 | import 'character_location_dto.dart'; 7 | 8 | extension CharacterInfoExtension on CharacterInfo { 9 | CharacterDto toCharacterDto() { 10 | return CharacterDto( 11 | id, 12 | name, 13 | status, 14 | species, 15 | type, 16 | gender, 17 | origin?.toLocationDto(), 18 | location?.toLocationDto(), 19 | image, 20 | episode, 21 | url, 22 | created); 23 | } 24 | } 25 | 26 | extension CharacterInfoListExtension on List? { 27 | List toCharacterDtoList() { 28 | if (this != null || this!.isNotEmpty) { 29 | return this!.map((e) => e.toCharacterDto()).toList(); 30 | } 31 | return List.empty(); 32 | } 33 | } 34 | 35 | extension OriginExtension on Origin { 36 | CharacterLocationDto toLocationDto() { 37 | return CharacterLocationDto(url.toString().getIdFromUrl(), name, url); 38 | } 39 | } 40 | 41 | extension LocationExtension on Location { 42 | CharacterLocationDto toLocationDto() { 43 | return CharacterLocationDto(url.toString().getIdFromUrl(), name, url); 44 | } 45 | } 46 | 47 | extension StringExtension on String { 48 | int getIdFromUrl() { 49 | if (isNotEmpty) { 50 | return int.parse(substring(lastIndexOf("/") + 1)); 51 | } else { 52 | return 0; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/data/model/dto/character/character_location_dto.dart: -------------------------------------------------------------------------------- 1 | class CharacterLocationDto { 2 | final int? locationId; 3 | final String? name; 4 | final String? url; 5 | 6 | CharacterLocationDto(this.locationId, this.name, this.url); 7 | } 8 | -------------------------------------------------------------------------------- /lib/data/model/dto/character/character_status.dart: -------------------------------------------------------------------------------- 1 | enum CharacterStatus { 2 | alive("Alive"), 3 | dead("Dead"), 4 | unknown("unknown"); 5 | 6 | final String status; 7 | 8 | const CharacterStatus(this.status); 9 | } 10 | -------------------------------------------------------------------------------- /lib/data/model/dto/episode/episode_dto.dart: -------------------------------------------------------------------------------- 1 | import 'package:rorty_flutter/data/model/dto/character/character_dto.dart'; 2 | 3 | class EpisodeDto { 4 | final int? id; 5 | final String? name; 6 | final String? url; 7 | final String? airDate; 8 | final String? created; 9 | final String? episode; 10 | final List? characters; 11 | List characterDtoList = []; 12 | 13 | EpisodeDto(this.id, this.name, this.url, this.airDate, this.created, 14 | this.episode, this.characters); 15 | } 16 | -------------------------------------------------------------------------------- /lib/data/model/dto/episode/episode_dto_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:rorty_flutter/data/model/dto/episode/episode_dto.dart'; 2 | import 'package:rorty_flutter/data/model/remote/episode/EpisodeInfo.dart'; 3 | 4 | extension EpisodeInfoExtension on EpisodeInfo { 5 | EpisodeDto toEpisodeDto() { 6 | return EpisodeDto(id, name, url, airDate, created, episode, characters); 7 | } 8 | } 9 | 10 | extension EpisodeInfoListExtension on List? { 11 | List toEpisodeDtoList() { 12 | if (this != null || this!.isNotEmpty) { 13 | return this!.map((e) => e.toEpisodeDto()).toList(); 14 | } 15 | return List.empty(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/data/model/dto/location/location_dto.dart: -------------------------------------------------------------------------------- 1 | import 'package:rorty_flutter/data/model/dto/character/character_dto.dart'; 2 | 3 | class LocationDto { 4 | final int? id; 5 | final String? name; 6 | final String? type; 7 | final String? dimension; 8 | final List? residents; 9 | final String? url; 10 | final String? created; 11 | List residentDtoList = []; 12 | 13 | LocationDto(this.id, this.name, this.type, this.dimension, this.residents, 14 | this.url, this.created); 15 | } 16 | -------------------------------------------------------------------------------- /lib/data/model/dto/location/location_dto_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:rorty_flutter/data/model/dto/location/location_dto.dart'; 2 | import 'package:rorty_flutter/data/model/remote/location/LocationInfo.dart'; 3 | 4 | extension LocationInfoExtension on LocationInfo { 5 | LocationDto toLocationDto() { 6 | return LocationDto(id, name, type, dimension, residents, url, created); 7 | } 8 | } 9 | 10 | extension LocationInfoListExtension on List? { 11 | List toLocationDtoList() { 12 | if (this != null || this!.isNotEmpty) { 13 | return this!.map((e) => e.toLocationDto()).toList(); 14 | } 15 | return List.empty(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/data/model/remote/base/PageInfo.dart: -------------------------------------------------------------------------------- 1 | class PageInfo { 2 | int? count; 3 | int? pages; 4 | String? next; 5 | String? prev; 6 | 7 | PageInfo({this.count, this.pages, this.next, this.prev}); 8 | 9 | PageInfo.fromJson(dynamic json) { 10 | count = json['count']; 11 | pages = json['pages']; 12 | next = json['next']; 13 | prev = json['prev']; 14 | } 15 | 16 | Map toJson() { 17 | final map = {}; 18 | map['count'] = count; 19 | map['pages'] = pages; 20 | map['next'] = next; 21 | map['prev'] = prev; 22 | return map; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/data/model/remote/character/CharacterInfo.dart: -------------------------------------------------------------------------------- 1 | import 'Origin.dart'; 2 | import 'Location.dart'; 3 | 4 | class CharacterInfo { 5 | int? id; 6 | String? name; 7 | String? status; 8 | String? species; 9 | String? type; 10 | String? gender; 11 | Origin? origin; 12 | Location? location; 13 | String? image; 14 | List? episode; 15 | String? url; 16 | String? created; 17 | 18 | CharacterInfo( 19 | {this.id, 20 | this.name, 21 | this.status, 22 | this.species, 23 | this.type, 24 | this.gender, 25 | this.origin, 26 | this.location, 27 | this.image, 28 | this.episode, 29 | this.url, 30 | this.created}); 31 | 32 | CharacterInfo.fromJson(dynamic json) { 33 | id = json['id']; 34 | name = json['name']; 35 | status = json['status']; 36 | species = json['species']; 37 | type = json['type']; 38 | gender = json['gender']; 39 | origin = json['origin'] != null ? Origin.fromJson(json['origin']) : null; 40 | location = 41 | json['location'] != null ? Location.fromJson(json['location']) : null; 42 | image = json['image']; 43 | episode = json['episode'] != null ? json['episode'].cast() : []; 44 | url = json['url']; 45 | created = json['created']; 46 | } 47 | 48 | Map toJson() { 49 | final map = {}; 50 | map['id'] = id; 51 | map['name'] = name; 52 | map['status'] = status; 53 | map['species'] = species; 54 | map['type'] = type; 55 | map['gender'] = gender; 56 | if (origin != null) { 57 | map['origin'] = origin?.toJson(); 58 | } 59 | if (location != null) { 60 | map['location'] = location?.toJson(); 61 | } 62 | map['image'] = image; 63 | map['episode'] = episode; 64 | map['url'] = url; 65 | map['created'] = created; 66 | return map; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/data/model/remote/character/CharacterResponse.dart: -------------------------------------------------------------------------------- 1 | import 'package:rorty_flutter/data/model/remote/base/PageInfo.dart'; 2 | 3 | import 'CharacterInfo.dart'; 4 | 5 | class CharacterResponse { 6 | PageInfo? info; 7 | List? results; 8 | 9 | CharacterResponse({this.info, this.results}); 10 | 11 | CharacterResponse.fromJson(dynamic json) { 12 | info = json['info'] != null ? PageInfo.fromJson(json['info']) : null; 13 | if (json['results'] != null) { 14 | results = []; 15 | json['results'].forEach((v) { 16 | results?.add(CharacterInfo.fromJson(v)); 17 | }); 18 | } 19 | } 20 | 21 | Map toJson() { 22 | final map = {}; 23 | if (info != null) { 24 | map['info'] = info?.toJson(); 25 | } 26 | if (results != null) { 27 | map['results'] = results?.map((v) => v.toJson()).toList(); 28 | } 29 | return map; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/data/model/remote/character/Location.dart: -------------------------------------------------------------------------------- 1 | class Location { 2 | String? name; 3 | String? url; 4 | 5 | Location({this.name, this.url}); 6 | 7 | Location.fromJson(dynamic json) { 8 | name = json['name']; 9 | url = json['url']; 10 | } 11 | 12 | Map toJson() { 13 | final map = {}; 14 | map['name'] = name; 15 | map['url'] = url; 16 | return map; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/data/model/remote/character/Origin.dart: -------------------------------------------------------------------------------- 1 | class Origin { 2 | String? name; 3 | String? url; 4 | 5 | Origin({this.name, this.url}); 6 | 7 | Origin.fromJson(dynamic json) { 8 | name = json['name']; 9 | url = json['url']; 10 | } 11 | 12 | Map toJson() { 13 | final map = {}; 14 | map['name'] = name; 15 | map['url'] = url; 16 | return map; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/data/model/remote/episode/EpisodeInfo.dart: -------------------------------------------------------------------------------- 1 | class EpisodeInfo { 2 | int? id; 3 | String? name; 4 | String? airDate; 5 | String? episode; 6 | List? characters; 7 | String? url; 8 | String? created; 9 | 10 | EpisodeInfo({ 11 | this.id, 12 | this.name, 13 | this.airDate, 14 | this.episode, 15 | this.characters, 16 | this.url, 17 | this.created, 18 | }); 19 | 20 | EpisodeInfo.fromJson(dynamic json) { 21 | id = json['id']; 22 | name = json['name']; 23 | airDate = json['air_date']; 24 | episode = json['episode']; 25 | characters = 26 | json['characters'] != null ? json['characters'].cast() : []; 27 | url = json['url']; 28 | created = json['created']; 29 | } 30 | 31 | Map toJson() { 32 | final map = {}; 33 | map['id'] = id; 34 | map['name'] = name; 35 | map['air_date'] = airDate; 36 | map['episode'] = episode; 37 | map['characters'] = characters; 38 | map['url'] = url; 39 | map['created'] = created; 40 | return map; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/data/model/remote/episode/EpisodeResponse.dart: -------------------------------------------------------------------------------- 1 | import 'package:rorty_flutter/data/model/remote/base/PageInfo.dart'; 2 | import 'package:rorty_flutter/data/model/remote/episode/EpisodeInfo.dart'; 3 | 4 | class EpisodeResponse { 5 | PageInfo? info; 6 | List? results; 7 | 8 | EpisodeResponse({this.info, this.results}); 9 | 10 | EpisodeResponse.fromJson(dynamic json) { 11 | info = json['info'] != null ? PageInfo.fromJson(json['info']) : null; 12 | if (json['results'] != null) { 13 | results = []; 14 | json['results'].forEach((v) { 15 | results?.add(EpisodeInfo.fromJson(v)); 16 | }); 17 | } 18 | } 19 | 20 | Map toJson() { 21 | final map = {}; 22 | if (info != null) { 23 | map['info'] = info?.toJson(); 24 | } 25 | if (results != null) { 26 | map['results'] = results?.map((v) => v.toJson()).toList(); 27 | } 28 | return map; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/data/model/remote/location/LocationInfo.dart: -------------------------------------------------------------------------------- 1 | class LocationInfo { 2 | int? id; 3 | String? name; 4 | String? type; 5 | String? dimension; 6 | List? residents; 7 | String? url; 8 | String? created; 9 | 10 | LocationInfo({ 11 | this.id, 12 | this.name, 13 | this.type, 14 | this.dimension, 15 | this.residents, 16 | this.url, 17 | this.created, 18 | }); 19 | 20 | LocationInfo.fromJson(dynamic json) { 21 | id = json['id']; 22 | name = json['name']; 23 | type = json['type']; 24 | dimension = json['dimension']; 25 | residents = 26 | json['residents'] != null ? json['residents'].cast() : []; 27 | url = json['url']; 28 | created = json['created']; 29 | } 30 | 31 | Map toJson() { 32 | final map = {}; 33 | map['id'] = id; 34 | map['name'] = name; 35 | map['type'] = type; 36 | map['dimension'] = dimension; 37 | map['residents'] = residents; 38 | map['url'] = url; 39 | map['created'] = created; 40 | return map; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/data/model/remote/location/LocationResponse.dart: -------------------------------------------------------------------------------- 1 | import 'package:rorty_flutter/data/model/remote/base/PageInfo.dart'; 2 | import 'package:rorty_flutter/data/model/remote/location/LocationInfo.dart'; 3 | 4 | class LocationResponse { 5 | PageInfo? info; 6 | List? results; 7 | 8 | LocationResponse({this.info, this.results}); 9 | 10 | LocationResponse.fromJson(dynamic json) { 11 | info = json['info'] != null ? PageInfo.fromJson(json['info']) : null; 12 | if (json['results'] != null) { 13 | results = []; 14 | json['results'].forEach((v) { 15 | results?.add(LocationInfo.fromJson(v)); 16 | }); 17 | } 18 | } 19 | 20 | Map toJson() { 21 | final map = {}; 22 | if (info != null) { 23 | map['info'] = info?.toJson(); 24 | } 25 | if (results != null) { 26 | map['results'] = results?.map((v) => v.toJson()).toList(); 27 | } 28 | return map; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/data/remote/dio/data_state.dart: -------------------------------------------------------------------------------- 1 | abstract class DataState { 2 | final T? data; 3 | final String? error; 4 | 5 | const DataState({this.data, this.error}); 6 | } 7 | 8 | class DataSuccess extends DataState { 9 | const DataSuccess(T? data) : super(data: data); 10 | } 11 | 12 | class DataFailed extends DataState { 13 | const DataFailed(String? error) : super(error: error); 14 | } 15 | -------------------------------------------------------------------------------- /lib/data/remote/dio/dio_exception.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | 3 | class MyDioException implements Exception { 4 | late String errorMessage; 5 | 6 | MyDioException.fromDioError(DioException dioError) { 7 | switch (dioError.type) { 8 | case DioExceptionType.cancel: 9 | errorMessage = 'Request to the server was cancelled.'; 10 | break; 11 | case DioExceptionType.connectionTimeout: 12 | errorMessage = 'Connection timed out.'; 13 | break; 14 | case DioExceptionType.receiveTimeout: 15 | errorMessage = 'Receiving timeout occurred.'; 16 | break; 17 | case DioExceptionType.sendTimeout: 18 | errorMessage = 'Request send timeout.'; 19 | break; 20 | case DioExceptionType.badResponse: 21 | errorMessage = _handleStatusCode(dioError.response?.statusCode); 22 | break; 23 | case DioExceptionType.unknown: 24 | if (dioError.message!.contains('SocketException')) { 25 | errorMessage = 'No Internet.'; 26 | break; 27 | } 28 | errorMessage = 'Unexpected error occurred.'; 29 | break; 30 | default: 31 | errorMessage = 'Something went wrong'; 32 | break; 33 | } 34 | } 35 | 36 | String _handleStatusCode(int? statusCode) { 37 | switch (statusCode) { 38 | case 400: 39 | return 'Bad request.'; 40 | case 401: 41 | return 'Authentication failed.'; 42 | case 403: 43 | return 'The authenticated user is not allowed to access the specified API endpoint.'; 44 | case 404: 45 | return 'The requested resource does not exist.'; 46 | case 405: 47 | return 'Method not allowed. Please check the Allow header for the allowed HTTP methods.'; 48 | case 415: 49 | return 'Unsupported media type. The requested content type or version number is invalid.'; 50 | case 422: 51 | return 'Data validation failed.'; 52 | case 429: 53 | return 'Too many requests.'; 54 | case 500: 55 | return 'Internal server error.'; 56 | default: 57 | return 'Oops something went wrong!'; 58 | } 59 | } 60 | 61 | @override 62 | String toString() => errorMessage; 63 | } 64 | -------------------------------------------------------------------------------- /lib/data/remote/dio/dio_factory.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:rorty_flutter/data/remote/dio/logging_interceptor.dart'; 3 | 4 | class DioFactory { 5 | final String _baseUrl; 6 | 7 | DioFactory(this._baseUrl); 8 | 9 | BaseOptions _createBaseOptions() => BaseOptions( 10 | baseUrl: _baseUrl, 11 | receiveTimeout: const Duration(seconds: 5), 12 | sendTimeout: const Duration(seconds: 5), 13 | connectTimeout: const Duration(seconds: 5), 14 | ); 15 | 16 | Dio create() => Dio(_createBaseOptions()) 17 | ..interceptors.addAll([ 18 | LoggerInterceptor(), 19 | ]); 20 | } 21 | -------------------------------------------------------------------------------- /lib/data/remote/dio/logging_interceptor.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:logger/logger.dart'; 3 | 4 | class LoggerInterceptor extends Interceptor { 5 | Logger logger = Logger( 6 | // Customize the printer 7 | printer: PrettyPrinter( 8 | methodCount: 0, 9 | printTime: false, 10 | ), 11 | ); 12 | 13 | @override 14 | void onError(DioError err, ErrorInterceptorHandler handler) { 15 | final options = err.requestOptions; 16 | final requestPath = '${options.baseUrl}${options.path}'; 17 | logger.e('${options.method} request => $requestPath'); // Debug log 18 | logger.d('Error: ${err.error}, Message: ${err.message}'); // Error log 19 | return super.onError(err, handler); 20 | } 21 | 22 | @override 23 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) { 24 | final requestPath = '${options.baseUrl}${options.path}'; 25 | logger.i('${options.method} request => $requestPath'); // Info log 26 | return super.onRequest(options, handler); 27 | } 28 | 29 | @override 30 | void onResponse(Response response, ResponseInterceptorHandler handler) { 31 | logger.d( 32 | 'StatusCode: ${response.statusCode}, Data: ${response.data}'); // Debug log 33 | return super.onResponse(response, handler); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/data/remote/service/character/character_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart'; 3 | import 'package:rorty_flutter/data/model/remote/character/CharacterInfo.dart'; 4 | import 'package:rorty_flutter/data/model/remote/character/CharacterResponse.dart'; 5 | 6 | part 'character_service.g.dart'; 7 | 8 | @RestApi() 9 | abstract class CharacterService { 10 | factory CharacterService(Dio dio) = _CharacterService; 11 | 12 | @GET("/character") 13 | Future> getCharacters( 14 | @Query("page") int page, 15 | @Queries() Map? options, 16 | ); 17 | 18 | @GET("/character/{id}") 19 | Future> getCharacter(@Path("id") int id); 20 | } 21 | -------------------------------------------------------------------------------- /lib/data/remote/service/character/character_service.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'character_service.dart'; 4 | 5 | // ************************************************************************** 6 | // RetrofitGenerator 7 | // ************************************************************************** 8 | 9 | // ignore_for_file: unnecessary_brace_in_string_interps 10 | 11 | class _CharacterService implements CharacterService { 12 | _CharacterService(this._dio, {this.baseUrl}); 13 | 14 | final Dio _dio; 15 | 16 | String? baseUrl; 17 | 18 | @override 19 | Future> getCharacters(page, options) async { 20 | const _extra = {}; 21 | final queryParameters = {r'page': page}; 22 | queryParameters.addAll(options ?? {}); 23 | queryParameters.removeWhere((k, v) => v == null); 24 | final _headers = {}; 25 | final _data = {}; 26 | final _result = await _dio.fetch>( 27 | _setStreamType>( 28 | Options(method: 'GET', headers: _headers, extra: _extra) 29 | .compose(_dio.options, '/character', 30 | queryParameters: queryParameters, data: _data) 31 | .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); 32 | final value = CharacterResponse.fromJson(_result.data!); 33 | final httpResponse = HttpResponse(value, _result); 34 | return httpResponse; 35 | } 36 | 37 | @override 38 | Future> getCharacter(id) async { 39 | const _extra = {}; 40 | final queryParameters = {}; 41 | final _headers = {}; 42 | final _data = {}; 43 | final _result = await _dio.fetch>( 44 | _setStreamType>( 45 | Options(method: 'GET', headers: _headers, extra: _extra) 46 | .compose(_dio.options, '/character/${id}', 47 | queryParameters: queryParameters, data: _data) 48 | .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); 49 | final value = CharacterInfo.fromJson(_result.data!); 50 | final httpResponse = HttpResponse(value, _result); 51 | return httpResponse; 52 | } 53 | 54 | RequestOptions _setStreamType(RequestOptions requestOptions) { 55 | if (T != dynamic && 56 | !(requestOptions.responseType == ResponseType.bytes || 57 | requestOptions.responseType == ResponseType.stream)) { 58 | if (T == String) { 59 | requestOptions.responseType = ResponseType.plain; 60 | } else { 61 | requestOptions.responseType = ResponseType.json; 62 | } 63 | } 64 | return requestOptions; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/data/remote/service/episode/episode_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart'; 3 | import 'package:rorty_flutter/data/model/remote/episode/EpisodeInfo.dart'; 4 | import 'package:rorty_flutter/data/model/remote/episode/EpisodeResponse.dart'; 5 | 6 | part 'episode_service.g.dart'; 7 | 8 | @RestApi() 9 | abstract class EpisodeService { 10 | factory EpisodeService(Dio dio) = _EpisodeService; 11 | 12 | @GET("/episode") 13 | Future> getEpisodes( 14 | @Query("page") int page, 15 | @Queries() Map? options, 16 | ); 17 | 18 | @GET("/episode/{id}") 19 | Future> getEpisode(@Path("id") int id); 20 | } 21 | -------------------------------------------------------------------------------- /lib/data/remote/service/episode/episode_service.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'episode_service.dart'; 4 | 5 | // ************************************************************************** 6 | // RetrofitGenerator 7 | // ************************************************************************** 8 | 9 | // ignore_for_file: unnecessary_brace_in_string_interps 10 | 11 | class _EpisodeService implements EpisodeService { 12 | _EpisodeService(this._dio, {this.baseUrl}); 13 | 14 | final Dio _dio; 15 | 16 | String? baseUrl; 17 | 18 | @override 19 | Future> getEpisodes(page, options) async { 20 | const _extra = {}; 21 | final queryParameters = {r'page': page}; 22 | queryParameters.addAll(options ?? {}); 23 | queryParameters.removeWhere((k, v) => v == null); 24 | final _headers = {}; 25 | final _data = {}; 26 | final _result = await _dio.fetch>( 27 | _setStreamType>( 28 | Options(method: 'GET', headers: _headers, extra: _extra) 29 | .compose(_dio.options, '/episode', 30 | queryParameters: queryParameters, data: _data) 31 | .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); 32 | final value = EpisodeResponse.fromJson(_result.data!); 33 | final httpResponse = HttpResponse(value, _result); 34 | return httpResponse; 35 | } 36 | 37 | @override 38 | Future> getEpisode(id) async { 39 | const _extra = {}; 40 | final queryParameters = {}; 41 | final _headers = {}; 42 | final _data = {}; 43 | final _result = await _dio.fetch>( 44 | _setStreamType>( 45 | Options(method: 'GET', headers: _headers, extra: _extra) 46 | .compose(_dio.options, '/episode/${id}', 47 | queryParameters: queryParameters, data: _data) 48 | .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); 49 | final value = EpisodeInfo.fromJson(_result.data!); 50 | final httpResponse = HttpResponse(value, _result); 51 | return httpResponse; 52 | } 53 | 54 | RequestOptions _setStreamType(RequestOptions requestOptions) { 55 | if (T != dynamic && 56 | !(requestOptions.responseType == ResponseType.bytes || 57 | requestOptions.responseType == ResponseType.stream)) { 58 | if (T == String) { 59 | requestOptions.responseType = ResponseType.plain; 60 | } else { 61 | requestOptions.responseType = ResponseType.json; 62 | } 63 | } 64 | return requestOptions; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/data/remote/service/location/location_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart'; 3 | import 'package:rorty_flutter/data/model/remote/location/LocationInfo.dart'; 4 | import 'package:rorty_flutter/data/model/remote/location/LocationResponse.dart'; 5 | 6 | part 'location_service.g.dart'; 7 | 8 | @RestApi() 9 | abstract class LocationService { 10 | factory LocationService(Dio dio) = _LocationService; 11 | 12 | @GET("/location") 13 | Future> getLocations( 14 | @Query("page") int page, 15 | @Queries() Map? options, 16 | ); 17 | 18 | @GET("/location/{id}") 19 | Future> getLocation(@Path("id") int id); 20 | } 21 | -------------------------------------------------------------------------------- /lib/data/remote/service/location/location_service.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'location_service.dart'; 4 | 5 | // ************************************************************************** 6 | // RetrofitGenerator 7 | // ************************************************************************** 8 | 9 | // ignore_for_file: unnecessary_brace_in_string_interps 10 | 11 | class _LocationService implements LocationService { 12 | _LocationService(this._dio, {this.baseUrl}); 13 | 14 | final Dio _dio; 15 | 16 | String? baseUrl; 17 | 18 | @override 19 | Future> getLocations(page, options) async { 20 | const _extra = {}; 21 | final queryParameters = {r'page': page}; 22 | queryParameters.addAll(options ?? {}); 23 | queryParameters.removeWhere((k, v) => v == null); 24 | final _headers = {}; 25 | final _data = {}; 26 | final _result = await _dio.fetch>( 27 | _setStreamType>( 28 | Options(method: 'GET', headers: _headers, extra: _extra) 29 | .compose(_dio.options, '/location', 30 | queryParameters: queryParameters, data: _data) 31 | .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); 32 | final value = LocationResponse.fromJson(_result.data!); 33 | final httpResponse = HttpResponse(value, _result); 34 | return httpResponse; 35 | } 36 | 37 | @override 38 | Future> getLocation(id) async { 39 | const _extra = {}; 40 | final queryParameters = {}; 41 | final _headers = {}; 42 | final _data = {}; 43 | final _result = await _dio.fetch>( 44 | _setStreamType>( 45 | Options(method: 'GET', headers: _headers, extra: _extra) 46 | .compose(_dio.options, '/location/${id}', 47 | queryParameters: queryParameters, data: _data) 48 | .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); 49 | final value = LocationInfo.fromJson(_result.data!); 50 | final httpResponse = HttpResponse(value, _result); 51 | return httpResponse; 52 | } 53 | 54 | RequestOptions _setStreamType(RequestOptions requestOptions) { 55 | if (T != dynamic && 56 | !(requestOptions.responseType == ResponseType.bytes || 57 | requestOptions.responseType == ResponseType.stream)) { 58 | if (T == String) { 59 | requestOptions.responseType = ResponseType.plain; 60 | } else { 61 | requestOptions.responseType = ResponseType.json; 62 | } 63 | } 64 | return requestOptions; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/data/repository/character_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:retrofit/retrofit.dart'; 2 | import 'package:rorty_flutter/data/model/remote/character/CharacterInfo.dart'; 3 | import 'package:rorty_flutter/data/model/remote/character/CharacterResponse.dart'; 4 | import 'package:rorty_flutter/data/remote/service/character/character_service.dart'; 5 | 6 | class CharacterRepository { 7 | final CharacterService _characterService; 8 | 9 | CharacterRepository(this._characterService); 10 | 11 | Future> getCharacters( 12 | int page, 13 | Map? options, 14 | ) => _characterService.getCharacters(page, options); 15 | 16 | Future> getCharacter(int id) => 17 | _characterService.getCharacter(id); 18 | } 19 | -------------------------------------------------------------------------------- /lib/data/repository/episode_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:retrofit/retrofit.dart'; 2 | import 'package:rorty_flutter/data/model/remote/episode/EpisodeInfo.dart'; 3 | import 'package:rorty_flutter/data/model/remote/episode/EpisodeResponse.dart'; 4 | import 'package:rorty_flutter/data/remote/service/episode/episode_service.dart'; 5 | 6 | class EpisodeRepository { 7 | final EpisodeService _episodeService; 8 | 9 | EpisodeRepository(this._episodeService); 10 | 11 | Future> getEpisodes( 12 | int page, 13 | Map? options, 14 | ) => _episodeService.getEpisodes(page, options); 15 | 16 | Future> getEpisode(int id) => 17 | _episodeService.getEpisode(id); 18 | } 19 | -------------------------------------------------------------------------------- /lib/data/repository/location_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:retrofit/retrofit.dart'; 2 | import 'package:rorty_flutter/data/model/remote/location/LocationInfo.dart'; 3 | import 'package:rorty_flutter/data/model/remote/location/LocationResponse.dart'; 4 | import 'package:rorty_flutter/data/remote/service/location/location_service.dart'; 5 | 6 | class LocationRepository { 7 | final LocationService _locationService; 8 | 9 | LocationRepository(this._locationService); 10 | 11 | Future> getLocations( 12 | int page, 13 | Map? options, 14 | ) => _locationService.getLocations(page, options); 15 | 16 | Future> getLocation(int id) => 17 | _locationService.getLocation(id); 18 | } 19 | -------------------------------------------------------------------------------- /lib/domain/character/favorite/add_character_favorite.dart: -------------------------------------------------------------------------------- 1 | class AddCharacterFavorite {} 2 | -------------------------------------------------------------------------------- /lib/domain/character/favorite/delete_character_favorite.dart: -------------------------------------------------------------------------------- 1 | class DeleteCharacterFavorite {} 2 | -------------------------------------------------------------------------------- /lib/domain/character/favorite/get_character_favorites.dart: -------------------------------------------------------------------------------- 1 | class GetCharacterFavorites {} 2 | -------------------------------------------------------------------------------- /lib/domain/character/favorite/update_character_favorite.dart: -------------------------------------------------------------------------------- 1 | class UpdateCharacterFavorite {} 2 | -------------------------------------------------------------------------------- /lib/domain/character/get_character_detail.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:rorty_flutter/core/use_case.dart'; 6 | import 'package:rorty_flutter/data/model/dto/character/character_dto.dart'; 7 | import 'package:rorty_flutter/data/model/dto/character/character_dto_extension.dart'; 8 | import 'package:rorty_flutter/data/model/dto/episode/episode_dto_extension.dart'; 9 | import 'package:rorty_flutter/data/remote/dio/data_state.dart'; 10 | import 'package:rorty_flutter/data/remote/dio/dio_exception.dart'; 11 | import 'package:rorty_flutter/data/repository/character_repository.dart'; 12 | import 'package:rorty_flutter/data/repository/episode_repository.dart'; 13 | 14 | class GetCharacterDetail 15 | implements UseCase, GetCharacterDetailParams> { 16 | final CharacterRepository _characterRepository; 17 | final EpisodeRepository _episodeRepository; 18 | 19 | GetCharacterDetail(this._characterRepository, this._episodeRepository); 20 | 21 | @override 22 | Future> call( 23 | {required GetCharacterDetailParams params}) async { 24 | try { 25 | final httpResponse = 26 | await _characterRepository.getCharacter(params.characterId); 27 | 28 | if (httpResponse.response.statusCode == HttpStatus.ok) { 29 | CharacterDto dto = httpResponse.data.toCharacterDto(); 30 | if (dto.episodes != null && dto.episodes!.isNotEmpty) { 31 | for (var url in dto.episodes!) { 32 | int episodeId = url.getIdFromUrl(); 33 | final episode = await _episodeRepository.getEpisode(episodeId); 34 | if (episode.response.statusCode == HttpStatus.ok) { 35 | dto.episodeDtoList.add(episode.data.toEpisodeDto()); 36 | } 37 | } 38 | } 39 | return DataSuccess(dto); 40 | } 41 | return DataFailed(httpResponse.response.statusMessage); 42 | } on DioException catch (e) { 43 | final errorMessage = MyDioException.fromDioError(e).toString(); 44 | if (kDebugMode) { 45 | print(errorMessage); 46 | } 47 | return DataFailed(errorMessage); 48 | } catch (e) { 49 | if (kDebugMode) { 50 | print(e); 51 | } 52 | return DataFailed(e.toString()); 53 | } 54 | } 55 | } 56 | 57 | class GetCharacterDetailParams { 58 | final int characterId; 59 | 60 | GetCharacterDetailParams(this.characterId); 61 | } 62 | -------------------------------------------------------------------------------- /lib/domain/character/get_characters.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:rorty_flutter/core/use_case.dart'; 6 | import 'package:rorty_flutter/data/model/dto/character/character_dto.dart'; 7 | import 'package:rorty_flutter/data/model/dto/character/character_dto_extension.dart'; 8 | import 'package:rorty_flutter/data/remote/dio/data_state.dart'; 9 | import 'package:rorty_flutter/data/remote/dio/dio_exception.dart'; 10 | import 'package:rorty_flutter/data/repository/character_repository.dart'; 11 | 12 | class GetCharacters 13 | implements UseCase>, GetCharactersParams> { 14 | final CharacterRepository _characterRepository; 15 | 16 | GetCharacters(this._characterRepository); 17 | 18 | @override 19 | Future>> call( 20 | {required GetCharactersParams params}) async { 21 | try { 22 | final httpResponse = await _characterRepository.getCharacters( 23 | params.page, 24 | params.options, 25 | ); 26 | 27 | if (httpResponse.response.statusCode == HttpStatus.ok) { 28 | return DataSuccess(httpResponse.data.results.toCharacterDtoList()); 29 | } 30 | return DataFailed(httpResponse.response.statusMessage); 31 | } on DioException catch (e) { 32 | final errorMessage = MyDioException.fromDioError(e).toString(); 33 | if (kDebugMode) { 34 | print(errorMessage); 35 | } 36 | return DataFailed(errorMessage); 37 | } catch (e) { 38 | if (kDebugMode) { 39 | print(e); 40 | } 41 | return DataFailed(e.toString()); 42 | } 43 | } 44 | } 45 | 46 | class GetCharactersParams { 47 | final int page; 48 | final Map? options; 49 | 50 | GetCharactersParams(this.page, this.options); 51 | } 52 | -------------------------------------------------------------------------------- /lib/domain/episode/favorite/add_episode_favorite.dart: -------------------------------------------------------------------------------- 1 | class AddEpisodeFavorite {} 2 | -------------------------------------------------------------------------------- /lib/domain/episode/favorite/delete_episode_favorite.dart: -------------------------------------------------------------------------------- 1 | class DeleteEpisodeFavorite {} 2 | -------------------------------------------------------------------------------- /lib/domain/episode/favorite/get_episode_favorites.dart: -------------------------------------------------------------------------------- 1 | class GetEpisodeFavorites {} 2 | -------------------------------------------------------------------------------- /lib/domain/episode/favorite/update_episode_favorite.dart: -------------------------------------------------------------------------------- 1 | class UpdateEpisodeFavorite {} 2 | -------------------------------------------------------------------------------- /lib/domain/episode/get_episode_detail.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:rorty_flutter/core/use_case.dart'; 6 | import 'package:rorty_flutter/data/model/dto/character/character_dto_extension.dart'; 7 | import 'package:rorty_flutter/data/model/dto/episode/episode_dto.dart'; 8 | import 'package:rorty_flutter/data/model/dto/episode/episode_dto_extension.dart'; 9 | import 'package:rorty_flutter/data/remote/dio/data_state.dart'; 10 | import 'package:rorty_flutter/data/remote/dio/dio_exception.dart'; 11 | import 'package:rorty_flutter/data/repository/character_repository.dart'; 12 | import 'package:rorty_flutter/data/repository/episode_repository.dart'; 13 | 14 | class GetEpisodeDetail 15 | implements UseCase, GetEpisodeDetailParams> { 16 | final CharacterRepository _characterRepository; 17 | final EpisodeRepository _episodeRepository; 18 | 19 | GetEpisodeDetail(this._characterRepository, this._episodeRepository); 20 | 21 | @override 22 | Future> call( 23 | {required GetEpisodeDetailParams params}) async { 24 | try { 25 | final httpResponse = await _episodeRepository.getEpisode(params.id); 26 | 27 | if (httpResponse.response.statusCode == HttpStatus.ok) { 28 | EpisodeDto dto = httpResponse.data.toEpisodeDto(); 29 | if (dto.characters != null && dto.characters!.isNotEmpty) { 30 | for (var url in dto.characters!) { 31 | int id = url.getIdFromUrl(); 32 | final character = await _characterRepository.getCharacter(id); 33 | if (character.response.statusCode == HttpStatus.ok) { 34 | dto.characterDtoList.add(character.data.toCharacterDto()); 35 | } 36 | } 37 | } 38 | return DataSuccess(dto); 39 | } 40 | return DataFailed(httpResponse.response.statusMessage); 41 | } on DioException catch (e) { 42 | final errorMessage = MyDioException.fromDioError(e).toString(); 43 | if (kDebugMode) { 44 | print(errorMessage); 45 | } 46 | return DataFailed(errorMessage); 47 | } catch (e) { 48 | if (kDebugMode) { 49 | print(e); 50 | } 51 | return DataFailed(e.toString()); 52 | } 53 | } 54 | } 55 | 56 | class GetEpisodeDetailParams { 57 | final int id; 58 | 59 | GetEpisodeDetailParams(this.id); 60 | } 61 | -------------------------------------------------------------------------------- /lib/domain/episode/get_episodes.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:rorty_flutter/core/use_case.dart'; 6 | import 'package:rorty_flutter/data/model/dto/episode/episode_dto.dart'; 7 | import 'package:rorty_flutter/data/model/dto/episode/episode_dto_extension.dart'; 8 | import 'package:rorty_flutter/data/remote/dio/data_state.dart'; 9 | import 'package:rorty_flutter/data/remote/dio/dio_exception.dart'; 10 | import 'package:rorty_flutter/data/repository/episode_repository.dart'; 11 | 12 | class GetEpisodes 13 | implements UseCase>, GetEpisodesParams> { 14 | final EpisodeRepository _episodeRepository; 15 | 16 | GetEpisodes(this._episodeRepository); 17 | 18 | @override 19 | Future>> call( 20 | {required GetEpisodesParams params}) async { 21 | try { 22 | final httpResponse = await _episodeRepository.getEpisodes( 23 | params.page, 24 | params.options, 25 | ); 26 | 27 | if (httpResponse.response.statusCode == HttpStatus.ok) { 28 | return DataSuccess(httpResponse.data.results.toEpisodeDtoList()); 29 | } 30 | return DataFailed(httpResponse.response.statusMessage); 31 | } on DioException catch (e) { 32 | final errorMessage = MyDioException.fromDioError(e).toString(); 33 | if (kDebugMode) { 34 | print(errorMessage); 35 | } 36 | return DataFailed(errorMessage); 37 | } catch (e) { 38 | if (kDebugMode) { 39 | print(e); 40 | } 41 | return DataFailed(e.toString()); 42 | } 43 | } 44 | } 45 | 46 | class GetEpisodesParams { 47 | final int page; 48 | final Map? options; 49 | 50 | GetEpisodesParams(this.page, this.options); 51 | } 52 | -------------------------------------------------------------------------------- /lib/domain/location/favorite/add_location_favorite.dart: -------------------------------------------------------------------------------- 1 | class AddLocationFavorite {} 2 | -------------------------------------------------------------------------------- /lib/domain/location/favorite/delete_location_favorite.dart: -------------------------------------------------------------------------------- 1 | class DeleteLocationFavorite {} 2 | -------------------------------------------------------------------------------- /lib/domain/location/favorite/get_location_favorites.dart: -------------------------------------------------------------------------------- 1 | class GetLocationFavorites{} -------------------------------------------------------------------------------- /lib/domain/location/favorite/update_location_favorite.dart: -------------------------------------------------------------------------------- 1 | class UpdateLocationFavorite {} 2 | -------------------------------------------------------------------------------- /lib/domain/location/get_location_detail.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:rorty_flutter/core/use_case.dart'; 6 | import 'package:rorty_flutter/data/model/dto/character/character_dto_extension.dart'; 7 | import 'package:rorty_flutter/data/model/dto/location/location_dto.dart'; 8 | import 'package:rorty_flutter/data/model/dto/location/location_dto_extension.dart'; 9 | import 'package:rorty_flutter/data/remote/dio/data_state.dart'; 10 | import 'package:rorty_flutter/data/remote/dio/dio_exception.dart'; 11 | import 'package:rorty_flutter/data/repository/character_repository.dart'; 12 | import 'package:rorty_flutter/data/repository/location_repository.dart'; 13 | 14 | class GetLocationDetail 15 | implements UseCase, GetLocationDetailParams> { 16 | final CharacterRepository _characterRepository; 17 | final LocationRepository _locationRepository; 18 | 19 | GetLocationDetail(this._characterRepository, this._locationRepository); 20 | 21 | @override 22 | Future> call( 23 | {required GetLocationDetailParams params}) async { 24 | try { 25 | final httpResponse = await _locationRepository.getLocation(params.id); 26 | 27 | if (httpResponse.response.statusCode == HttpStatus.ok) { 28 | LocationDto dto = httpResponse.data.toLocationDto(); 29 | if (dto.residents != null && dto.residents!.isNotEmpty) { 30 | for (var url in dto.residents!) { 31 | int id = url.getIdFromUrl(); 32 | final resident = await _characterRepository.getCharacter(id); 33 | if (resident.response.statusCode == HttpStatus.ok) { 34 | dto.residentDtoList.add(resident.data.toCharacterDto()); 35 | } 36 | } 37 | } 38 | return DataSuccess(dto); 39 | } 40 | return DataFailed(httpResponse.response.statusMessage); 41 | } on DioException catch (e) { 42 | final errorMessage = MyDioException.fromDioError(e).toString(); 43 | if (kDebugMode) { 44 | print(errorMessage); 45 | } 46 | return DataFailed(errorMessage); 47 | } catch (e) { 48 | if (kDebugMode) { 49 | print(e); 50 | } 51 | return DataFailed(e.toString()); 52 | } 53 | } 54 | } 55 | 56 | class GetLocationDetailParams { 57 | final int id; 58 | 59 | GetLocationDetailParams(this.id); 60 | } 61 | -------------------------------------------------------------------------------- /lib/domain/location/get_locations.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:rorty_flutter/core/use_case.dart'; 6 | import 'package:rorty_flutter/data/model/dto/location/location_dto.dart'; 7 | import 'package:rorty_flutter/data/model/dto/location/location_dto_extension.dart'; 8 | import 'package:rorty_flutter/data/remote/dio/data_state.dart'; 9 | import 'package:rorty_flutter/data/remote/dio/dio_exception.dart'; 10 | import 'package:rorty_flutter/data/repository/location_repository.dart'; 11 | 12 | class GetLocations 13 | implements UseCase>, GetLocationsParams> { 14 | final LocationRepository _locationRepository; 15 | 16 | GetLocations(this._locationRepository); 17 | 18 | @override 19 | Future>> call( 20 | {required GetLocationsParams params}) async { 21 | try { 22 | final httpResponse = await _locationRepository.getLocations( 23 | params.page, 24 | params.options, 25 | ); 26 | 27 | if (httpResponse.response.statusCode == HttpStatus.ok) { 28 | return DataSuccess(httpResponse.data.results.toLocationDtoList()); 29 | } 30 | return DataFailed(httpResponse.response.statusMessage); 31 | } on DioException catch (e) { 32 | final errorMessage = MyDioException.fromDioError(e).toString(); 33 | if (kDebugMode) { 34 | print(errorMessage); 35 | } 36 | return DataFailed(errorMessage); 37 | } catch (e) { 38 | if (kDebugMode) { 39 | print(e); 40 | } 41 | return DataFailed(e.toString()); 42 | } 43 | } 44 | } 45 | 46 | class GetLocationsParams { 47 | final int page; 48 | final Map? options; 49 | 50 | GetLocationsParams(this.page, this.options); 51 | } 52 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: deprecated_member_use 2 | 3 | import 'package:easy_localization/easy_localization.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/services.dart'; 6 | import 'package:flutter_native_splash/flutter_native_splash.dart'; 7 | import 'package:go_router/go_router.dart'; 8 | import 'package:provider/provider.dart'; 9 | import 'package:rorty_flutter/app/di/injector.dart'; 10 | import 'package:rorty_flutter/app/language/app_language_provider.dart'; 11 | import 'package:rorty_flutter/app/language/language_manager.dart'; 12 | import 'package:rorty_flutter/app/theme/app_theme.dart'; 13 | import 'package:rorty_flutter/app/theme/app_theme_provider.dart'; 14 | import 'package:rorty_flutter/app/utils/constants.dart'; 15 | import 'package:rorty_flutter/presentation/characters/detail/character_detail_screen.dart'; 16 | import 'package:rorty_flutter/presentation/episodes/detail/episode_detail_screen.dart'; 17 | import 'package:rorty_flutter/presentation/home/home_screen.dart'; 18 | import 'package:rorty_flutter/presentation/locations/detail/location_detail_screen.dart'; 19 | import 'package:rorty_flutter/presentation/settings/about/about_screen.dart'; 20 | import 'package:rorty_flutter/presentation/settings/language/language_screen.dart'; 21 | 22 | Future main() async { 23 | WidgetsFlutterBinding.ensureInitialized(); 24 | 25 | await EasyLocalization.ensureInitialized(); 26 | 27 | await initializeDependencies(); 28 | 29 | FlutterNativeSplash.removeAfter(initialization); 30 | 31 | SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) 32 | .then((_) { 33 | runApp( 34 | EasyLocalization( 35 | supportedLocales: LanguageManager.instance!.supportedLocales, 36 | path: LANGUAGE_ASSETS_PATH, 37 | startLocale: LanguageManager.instance!.enLocale, 38 | child: RootApp()), 39 | ); 40 | }); 41 | } 42 | 43 | Future initialization(BuildContext? context) async { 44 | await Future.delayed(const Duration(seconds: 2)); 45 | } 46 | 47 | class RootApp extends StatelessWidget { 48 | RootApp({Key? key}) : super(key: key); 49 | 50 | final _router = GoRouter( 51 | initialLocation: HomeScreen.route, 52 | routes: [ 53 | GoRoute( 54 | path: HomeScreen.route, 55 | name: HomeScreen.route, 56 | builder: (context, state) => const HomeScreen(), 57 | ), 58 | GoRoute( 59 | path: CharacterDetailScreen.route, 60 | name: CharacterDetailScreen.route, 61 | builder: (context, state) => CharacterDetailScreen( 62 | characterId: state.pathParameters['characterId'] ?? ''), 63 | ), 64 | GoRoute( 65 | path: EpisodeDetailScreen.route, 66 | name: EpisodeDetailScreen.route, 67 | builder: (context, state) => 68 | EpisodeDetailScreen(episodeId: state.pathParameters['episodeId'] ?? ''), 69 | ), 70 | GoRoute( 71 | path: LocationDetailScreen.route, 72 | name: LocationDetailScreen.route, 73 | builder: (context, state) => 74 | LocationDetailScreen(locationId: state.pathParameters['locationId'] ?? ''), 75 | ), 76 | GoRoute( 77 | path: LanguageScreen.route, 78 | name: LanguageScreen.route, 79 | builder: (context, state) => LanguageScreen(), 80 | ), 81 | GoRoute( 82 | path: AboutScreen.route, 83 | name: AboutScreen.route, 84 | builder: (context, state) => const AboutScreen(), 85 | ), 86 | ], 87 | ); 88 | 89 | @override 90 | Widget build(BuildContext context) { 91 | // final themeProvider = Provider.of(context); 92 | return MultiProvider( 93 | providers: [ 94 | ChangeNotifierProvider(create: (_) => AppThemeProvider()), 95 | ], 96 | child: Consumer( 97 | builder: (context, AppThemeProvider themeNotifier, child) { 98 | return MaterialApp.router( 99 | routeInformationProvider: _router.routeInformationProvider, 100 | routeInformationParser: _router.routeInformationParser, 101 | routerDelegate: _router.routerDelegate, 102 | title: "Rorty", 103 | debugShowCheckedModeBanner: false, 104 | theme: 105 | themeNotifier.isDark ? AppTheme.darkTheme : AppTheme.lightTheme, 106 | darkTheme: AppTheme.darkTheme, 107 | localizationsDelegates: context.localizationDelegates, 108 | supportedLocales: context.supportedLocales, 109 | locale: context.locale, 110 | ); 111 | })); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /lib/presentation/characters/detail/character_detail_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:rorty_flutter/app/di/injector.dart'; 3 | import 'package:rorty_flutter/core/view_state.dart'; 4 | import 'package:rorty_flutter/data/model/dto/character/character_dto.dart'; 5 | import 'package:rorty_flutter/data/remote/dio/data_state.dart'; 6 | import 'package:rorty_flutter/domain/character/get_character_detail.dart'; 7 | 8 | class CharacterDetailViewModel extends ChangeNotifier { 9 | final GetCharacterDetail _getCharacterDetail = injector(); 10 | ViewState viewState = ViewState(state: ResponseState.EMPTY); 11 | 12 | CharacterDto? dto; 13 | 14 | void _setViewState(ViewState viewState) { 15 | this.viewState = viewState; 16 | notifyListeners(); 17 | } 18 | 19 | Future loadCharacterDetail(int characterId) async { 20 | _setViewState(ViewState.loading()); 21 | final detail = await _getCharacterDetail.call( 22 | params: GetCharacterDetailParams(characterId)); 23 | if (detail is DataSuccess) { 24 | dto = detail.data; 25 | _setViewState(ViewState.complete(dto!)); 26 | } 27 | if (detail is DataFailed) { 28 | if (kDebugMode) { 29 | print(detail.error); 30 | } 31 | _setViewState(ViewState.error(detail.error.toString())); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/presentation/characters/list/characters_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:rorty_flutter/app/di/injector.dart'; 3 | import 'package:rorty_flutter/core/view_state.dart'; 4 | import 'package:rorty_flutter/data/model/dto/character/character_dto.dart'; 5 | import 'package:rorty_flutter/data/remote/dio/data_state.dart'; 6 | import 'package:rorty_flutter/domain/character/get_characters.dart'; 7 | import 'package:stacked/stacked.dart'; 8 | 9 | const charactersBusyKey = 'characters'; 10 | 11 | class CharactersViewModel extends BaseViewModel { 12 | final GetCharacters _getCharacters = injector(); 13 | 14 | ViewState> viewState = 15 | ViewState(state: ResponseState.EMPTY); 16 | 17 | final List _characters = []; 18 | int _page = 1; 19 | static const int _pageSize = 20; 20 | bool hasMore = true; 21 | 22 | void _setViewState(ViewState> viewState) { 23 | this.viewState = viewState; 24 | setBusyForObject(charactersBusyKey, false); 25 | } 26 | 27 | void loadData() async { 28 | await loadMoreCharacters(); 29 | } 30 | 31 | Future loadMoreCharacters() async { 32 | if (_page == 1) _setViewState(ViewState.loading()); 33 | 34 | final characters = 35 | await _getCharacters.call(params: GetCharactersParams(_page, null)); 36 | 37 | if (characters is DataSuccess) { 38 | final list = characters.data ?? List.empty(); 39 | if (list.isEmpty) { 40 | hasMore = false; 41 | setBusyForObject(charactersBusyKey, false); 42 | } else { 43 | _characters.addAll(list); 44 | _page++; 45 | _setViewState(ViewState.complete(_characters)); 46 | } 47 | } 48 | if (characters is DataFailed) { 49 | if (kDebugMode) { 50 | print(characters.error); 51 | } 52 | _setViewState(ViewState.error(characters.error.toString())); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /lib/presentation/episodes/detail/episode_detail_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:rorty_flutter/app/di/injector.dart'; 3 | import 'package:rorty_flutter/core/view_state.dart'; 4 | import 'package:rorty_flutter/data/model/dto/episode/episode_dto.dart'; 5 | import 'package:rorty_flutter/data/remote/dio/data_state.dart'; 6 | import 'package:rorty_flutter/domain/episode/get_episode_detail.dart'; 7 | import 'package:stacked/stacked.dart'; 8 | 9 | class EpisodeDetailViewModel extends BaseViewModel { 10 | final GetEpisodeDetail _getEpisodeDetail = injector(); 11 | ViewState viewState = ViewState(state: ResponseState.EMPTY); 12 | 13 | EpisodeDto? dto; 14 | 15 | void _setViewState(ViewState viewState) { 16 | this.viewState = viewState; 17 | notifyListeners(); 18 | } 19 | 20 | Future loadDetail(int id) async { 21 | _setViewState(ViewState.loading()); 22 | final detail = 23 | await _getEpisodeDetail.call(params: GetEpisodeDetailParams(id)); 24 | if (detail is DataSuccess) { 25 | dto = detail.data; 26 | _setViewState(ViewState.complete(dto!)); 27 | } 28 | if (detail is DataFailed) { 29 | if (kDebugMode) { 30 | print(detail.error); 31 | } 32 | _setViewState(ViewState.error(detail.error.toString())); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/presentation/episodes/list/episodes_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:rorty_flutter/app/di/injector.dart'; 3 | import 'package:rorty_flutter/core/view_state.dart'; 4 | import 'package:rorty_flutter/data/model/dto/episode/episode_dto.dart'; 5 | import 'package:rorty_flutter/data/remote/dio/data_state.dart'; 6 | import 'package:rorty_flutter/domain/episode/get_episodes.dart'; 7 | import 'package:stacked/stacked.dart'; 8 | 9 | const episodesBusyKey = 'episodes'; 10 | 11 | class EpisodesViewModel extends BaseViewModel { 12 | final GetEpisodes _getEpisodes = injector(); 13 | 14 | ViewState> viewState = ViewState(state: ResponseState.EMPTY); 15 | 16 | final List _episodes = []; 17 | int _page = 1; 18 | bool hasMore = true; 19 | 20 | void _setViewState(ViewState> viewState) { 21 | this.viewState = viewState; 22 | setBusyForObject(episodesBusyKey, false); 23 | } 24 | 25 | void loadData() async { 26 | await loadMoreEpisodes(); 27 | } 28 | 29 | Future loadMoreEpisodes() async { 30 | if (_page == 1) _setViewState(ViewState.loading()); 31 | 32 | final episodes = 33 | await _getEpisodes.call(params: GetEpisodesParams(_page, null)); 34 | 35 | if (episodes is DataSuccess) { 36 | final list = episodes.data ?? List.empty(); 37 | if (list.isEmpty) { 38 | hasMore = false; 39 | setBusyForObject(episodesBusyKey, false); 40 | } else { 41 | _episodes.addAll(list); 42 | _page++; 43 | _setViewState(ViewState.complete(_episodes)); 44 | } 45 | } 46 | if (episodes is DataFailed) { 47 | if (kDebugMode) { 48 | print(episodes.error); 49 | } 50 | _setViewState(ViewState.error(episodes.error.toString())); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/presentation/home/home_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:stacked/stacked.dart'; 4 | 5 | import 'home_view_model.dart'; 6 | 7 | class HomeScreen extends StatelessWidget { 8 | static const route = '/'; 9 | 10 | const HomeScreen({Key? key}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return ViewModelBuilder.reactive( 15 | viewModelBuilder: () => HomeViewModel(), 16 | builder: (context, viewModel, child) { 17 | return Scaffold( 18 | body: viewModel.getPages(), 19 | bottomNavigationBar: BottomNavigationBar( 20 | items: [ 21 | BottomNavigationBarItem( 22 | icon: Icon(Icons.account_circle), label: "characters".tr()), 23 | BottomNavigationBarItem( 24 | icon: Icon(Icons.dashboard), label: "episodes".tr()), 25 | BottomNavigationBarItem( 26 | icon: Icon(Icons.location_city), label: "locations".tr()), 27 | BottomNavigationBarItem( 28 | icon: Icon(Icons.settings), label: "settings".tr()), 29 | ], 30 | onTap: viewModel.onItemTapped, 31 | currentIndex: viewModel.selectedIndex, 32 | ), 33 | ); 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/presentation/home/home_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:rorty_flutter/presentation/characters/list/characters_screen.dart'; 3 | import 'package:rorty_flutter/presentation/episodes/list/episodes_screen.dart'; 4 | import 'package:rorty_flutter/presentation/locations/list/locations_screen.dart'; 5 | import 'package:rorty_flutter/presentation/settings/settings_screen.dart'; 6 | import 'package:stacked/stacked.dart'; 7 | 8 | class HomeViewModel extends BaseViewModel { 9 | List pages = [ 10 | const CharactersScreen(), 11 | const EpisodesScreen(), 12 | const LocationsScreen(), 13 | const SettingsScreen() 14 | ]; 15 | 16 | int selectedIndex = 0; 17 | 18 | void onItemTapped(int index) { 19 | selectedIndex = index; 20 | notifyListeners(); 21 | } 22 | 23 | Widget getPages() => pages.elementAt(selectedIndex); 24 | } 25 | -------------------------------------------------------------------------------- /lib/presentation/locations/detail/location_detail_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:rorty_flutter/app/di/injector.dart'; 3 | import 'package:rorty_flutter/core/view_state.dart'; 4 | import 'package:rorty_flutter/data/model/dto/location/location_dto.dart'; 5 | import 'package:rorty_flutter/data/remote/dio/data_state.dart'; 6 | import 'package:rorty_flutter/domain/location/get_location_detail.dart'; 7 | import 'package:stacked/stacked.dart'; 8 | 9 | class LocationDetailViewModel extends BaseViewModel { 10 | final GetLocationDetail _getLocationDetail = injector(); 11 | ViewState viewState = ViewState(state: ResponseState.EMPTY); 12 | 13 | LocationDto? dto; 14 | 15 | void _setViewState(ViewState viewState) { 16 | this.viewState = viewState; 17 | notifyListeners(); 18 | } 19 | 20 | Future loadDetail(int id) async { 21 | _setViewState(ViewState.loading()); 22 | final detail = 23 | await _getLocationDetail.call(params: GetLocationDetailParams(id)); 24 | if (detail is DataSuccess) { 25 | dto = detail.data; 26 | _setViewState(ViewState.complete(dto!)); 27 | } 28 | if (detail is DataFailed) { 29 | if (kDebugMode) { 30 | print(detail.error); 31 | } 32 | _setViewState(ViewState.error(detail.error.toString())); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/presentation/locations/list/locations_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:rorty_flutter/app/di/injector.dart'; 3 | import 'package:rorty_flutter/core/view_state.dart'; 4 | import 'package:rorty_flutter/data/model/dto/location/location_dto.dart'; 5 | import 'package:rorty_flutter/data/remote/dio/data_state.dart'; 6 | import 'package:rorty_flutter/domain/location/get_locations.dart'; 7 | import 'package:stacked/stacked.dart'; 8 | 9 | const locationsBusyKey = 'locations'; 10 | 11 | class LocationsViewModel extends BaseViewModel { 12 | final GetLocations _getLocations = injector(); 13 | 14 | ViewState> viewState = 15 | ViewState(state: ResponseState.EMPTY); 16 | 17 | final List _locations = []; 18 | int _page = 1; 19 | bool hasMore = true; 20 | 21 | void _setViewState(ViewState> viewState) { 22 | this.viewState = viewState; 23 | setBusyForObject(locationsBusyKey, false); 24 | } 25 | 26 | void loadData() async { 27 | await loadMoreLocations(); 28 | } 29 | 30 | Future loadMoreLocations() async { 31 | if (_page == 1) _setViewState(ViewState.loading()); 32 | 33 | final locations = 34 | await _getLocations.call(params: GetLocationsParams(_page, null)); 35 | 36 | if (locations is DataSuccess) { 37 | final list = locations.data ?? List.empty(); 38 | if (list.isEmpty) { 39 | hasMore = false; 40 | setBusyForObject(locationsBusyKey, false); 41 | } else { 42 | _locations.addAll(list); 43 | _page++; 44 | _setViewState(ViewState.complete(_locations)); 45 | } 46 | } 47 | if (locations is DataFailed) { 48 | if (kDebugMode) { 49 | print(locations.error); 50 | } 51 | _setViewState(ViewState.error(locations.error.toString())); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/presentation/settings/about/about_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:rorty_flutter/app/utils/constants.dart'; 4 | import 'package:rorty_flutter/app/widgets/app_bar.dart'; 5 | import 'package:url_launcher/url_launcher_string.dart'; 6 | 7 | class AboutScreen extends StatelessWidget { 8 | static const route = '/about'; 9 | 10 | const AboutScreen({Key? key}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | appBar: _buildAppBar(), 16 | body: _buildBody(context), 17 | ); 18 | } 19 | 20 | RortyAppBarWithBack _buildAppBar() { 21 | return RortyAppBarWithBack(title: tr("abouts")); 22 | } 23 | 24 | Widget _buildBody(BuildContext context) { 25 | return SingleChildScrollView( 26 | child: Padding( 27 | padding: const EdgeInsets.all(8.0), 28 | child: Card( 29 | shape: 30 | RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)), 31 | elevation: 8, 32 | child: Center( 33 | child: Padding( 34 | padding: const EdgeInsets.all(8.0), 35 | child: Column( 36 | mainAxisAlignment: MainAxisAlignment.start, 37 | crossAxisAlignment: CrossAxisAlignment.center, 38 | children: [ 39 | Container( 40 | width: 150, 41 | height: 150, 42 | margin: const EdgeInsets.only(top: 16), 43 | decoration: BoxDecoration( 44 | borderRadius: BorderRadius.circular(80.0), 45 | image: const DecorationImage( 46 | image: AssetImage("assets/images/ic_profile.png"), 47 | fit: BoxFit.cover))), 48 | const SizedBox(height: 8), 49 | const Text("Mr.Sanchez", 50 | style: 51 | TextStyle(fontWeight: FontWeight.w800, fontSize: 16)), 52 | const SizedBox(height: 8), 53 | const Text("Android Developer"), 54 | const SizedBox(height: 8), 55 | const Text( 56 | "Developed By @developersancho", 57 | ), 58 | const SizedBox(height: 8), 59 | InkWell( 60 | onTap: () { 61 | launchUrlString(githubLink); 62 | }, 63 | child: const Text(githubLink, 64 | style: TextStyle(fontWeight: FontWeight.w500)), 65 | ), 66 | const SizedBox(height: 8), 67 | InkWell( 68 | onTap: () { 69 | launchUrlString(mediumLink); 70 | }, 71 | child: const Text(mediumLink, 72 | style: TextStyle(fontWeight: FontWeight.w500)), 73 | ) 74 | ], 75 | ), 76 | ), 77 | ), 78 | ), 79 | ), 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/presentation/settings/language/language_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:rorty_flutter/app/language/app_language_provider.dart'; 5 | import 'package:rorty_flutter/app/language/language_manager.dart'; 6 | import 'package:rorty_flutter/app/widgets/app_bar.dart'; 7 | 8 | class LanguageScreen extends StatelessWidget { 9 | static const route = '/language'; 10 | 11 | const LanguageScreen({Key? key}) : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: _buildAppBar(), 17 | body: _buildBody(context), 18 | ); 19 | } 20 | 21 | RortyAppBarWithBack _buildAppBar() { 22 | return RortyAppBarWithBack(title: tr("app_language")); 23 | } 24 | 25 | Widget _buildBody(BuildContext context) { 26 | return Card( 27 | child: ListTile( 28 | title: Text("languageChangeTitle".tr()), 29 | trailing: DropdownButton( 30 | items: [ 31 | DropdownMenuItem( 32 | child: Text(LanguageManager.instance!.trLocale.countryCode! 33 | .toUpperCase()), 34 | value: LanguageManager.instance!.trLocale), 35 | DropdownMenuItem( 36 | child: Text(LanguageManager.instance!.enLocale.countryCode! 37 | .toUpperCase()), 38 | value: LanguageManager.instance!.enLocale), 39 | ], 40 | onChanged: (value) { 41 | context.setLocale(value!); 42 | Provider.of(context).changeLanguage(value); 43 | }, 44 | value: context.locale, 45 | ), 46 | subtitle: Text("languageChangeSubtitle".tr())), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import shared_preferences_foundation 9 | import url_launcher_macos 10 | 11 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 12 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) 13 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 14 | } 15 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.11' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /macos/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FlutterMacOS (1.0.0) 3 | - shared_preferences_macos (0.0.1): 4 | - FlutterMacOS 5 | - url_launcher_macos (0.0.1): 6 | - FlutterMacOS 7 | 8 | DEPENDENCIES: 9 | - FlutterMacOS (from `Flutter/ephemeral`) 10 | - shared_preferences_macos (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos`) 11 | - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) 12 | 13 | EXTERNAL SOURCES: 14 | FlutterMacOS: 15 | :path: Flutter/ephemeral 16 | shared_preferences_macos: 17 | :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos 18 | url_launcher_macos: 19 | :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos 20 | 21 | SPEC CHECKSUMS: 22 | FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 23 | shared_preferences_macos: a64dc611287ed6cbe28fd1297898db1336975727 24 | url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3 25 | 26 | PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c 27 | 28 | COCOAPODS: 1.11.3 29 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = rorty_flutter 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.developersancho.rorty.rortyFlutter 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2022 com.developersancho.rorty. All rights reserved. 15 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | com.apple.security.network.client 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: rorty_flutter 2 | description: Rick and Morty 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=3.0.0 <4.0.0" 22 | 23 | # Dependencies specify other packages that your package needs in order to work. 24 | # To automatically upgrade your package dependencies to the latest versions 25 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 26 | # dependencies can be manually updated by changing the version numbers below to 27 | # the latest version available on pub.dev. To see which dependencies have newer 28 | # versions available, run `flutter pub outdated`. 29 | dependencies: 30 | flutter: 31 | sdk: flutter 32 | 33 | 34 | # The following adds the Cupertino Icons font to your application. 35 | # Use with the CupertinoIcons class for iOS style icons. 36 | cupertino_icons: ^1.0.6 37 | 38 | get_it: ^7.6.7 39 | retrofit: ^4.1.0 40 | dio: ^5.4.1 41 | logger: ^2.1.0 42 | equatable: ^2.0.5 43 | #flutter_bloc: ^8.0.1 44 | json_annotation: ^4.8.1 45 | hive: ^2.2.3 46 | go_router: ^13.2.0 47 | flutter_native_splash: ^2.3.5 48 | provider: ^6.1.2 49 | stacked: ^3.4.2 50 | #stacked_themes: ^0.3.8+1 51 | infinite_scroll_pagination: ^4.0.0 52 | flutter_switch: ^0.3.2 53 | shared_preferences: ^2.2.2 54 | easy_localization: ^3.0.5 55 | url_launcher: ^6.2.5 56 | file: ^7.0.0 57 | 58 | #floor: ^1.1.0 59 | 60 | dev_dependencies: 61 | build_runner: '>2.3.0 <4.0.0' 62 | flutter_test: 63 | sdk: flutter 64 | 65 | #floor_generator: ^1.1.0 66 | retrofit_generator: ^8.1.0 67 | 68 | 69 | # The "flutter_lints" package below contains a set of recommended lints to 70 | # encourage good coding practices. The lint set provided by the package is 71 | # activated in the `analysis_options.yaml` file located at the root of your 72 | # package. See that file for information about deactivating specific lint 73 | # rules and activating additional ones. 74 | flutter_lints: ^3.0.1 75 | 76 | # For information on the generic Dart part of this file, see the 77 | # following page: https://dart.dev/tools/pub/pubspec 78 | 79 | # The following section is specific to Flutter packages. 80 | flutter: 81 | 82 | # The following line ensures that the Material Icons font is 83 | # included with your application, so that you can use the icons in 84 | # the material Icons class. 85 | uses-material-design: true 86 | 87 | # To add assets to your application, add an assets section, like this: 88 | assets: 89 | - assets/images/ 90 | - assets/resources/ 91 | # Fonts 92 | fonts: 93 | - family: Raleway 94 | fonts: 95 | - asset: assets/fonts/raleway_regular.ttf 96 | - asset: assets/fonts/raleway_medium.ttf 97 | - asset: assets/fonts/raleway_semi_bold.ttf 98 | - asset: assets/fonts/raleway_bold.ttf -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | import 'package:rorty_flutter/main.dart'; 11 | 12 | void main() { 13 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 14 | // Build our app and trigger a frame. 15 | await tester.pumpWidget(RootApp()); 16 | 17 | // Verify that our counter starts at 0. 18 | expect(find.text('0'), findsOneWidget); 19 | expect(find.text('1'), findsNothing); 20 | 21 | // Tap the '+' icon and trigger a frame. 22 | await tester.tap(find.byIcon(Icons.add)); 23 | await tester.pump(); 24 | 25 | // Verify that our counter has incremented. 26 | expect(find.text('0'), findsNothing); 27 | expect(find.text('1'), findsOneWidget); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | rorty_flutter 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 65 | 66 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rorty_flutter", 3 | "short_name": "rorty_flutter", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "Rick and Morty", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /web/splash/img/dark-1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/splash/img/dark-1x.png -------------------------------------------------------------------------------- /web/splash/img/dark-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/splash/img/dark-2x.png -------------------------------------------------------------------------------- /web/splash/img/dark-3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/splash/img/dark-3x.png -------------------------------------------------------------------------------- /web/splash/img/dark-4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/splash/img/dark-4x.png -------------------------------------------------------------------------------- /web/splash/img/light-1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/splash/img/light-1x.png -------------------------------------------------------------------------------- /web/splash/img/light-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/splash/img/light-2x.png -------------------------------------------------------------------------------- /web/splash/img/light-3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/splash/img/light-3x.png -------------------------------------------------------------------------------- /web/splash/img/light-4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developersancho/Rorty.Flutter/267945b10f4b8b3b5e96106e21fa34c8225dfe35/web/splash/img/light-4x.png -------------------------------------------------------------------------------- /web/splash/splash.js: -------------------------------------------------------------------------------- 1 | function removeSplashFromWeb() { 2 | const elem = document.getElementById("splash"); 3 | if (elem) { 4 | elem.remove(); 5 | } 6 | document.body.style.background = "transparent"; 7 | } 8 | -------------------------------------------------------------------------------- /web/splash/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin:0; 3 | height:100%; 4 | background: #252941; 5 | 6 | background-size: 100% 100%; 7 | } 8 | 9 | .center { 10 | margin: 0; 11 | position: absolute; 12 | top: 50%; 13 | left: 50%; 14 | -ms-transform: translate(-50%, -50%); 15 | transform: translate(-50%, -50%); 16 | } 17 | 18 | .contain { 19 | display:block; 20 | width:100%; height:100%; 21 | object-fit: contain; 22 | } 23 | 24 | .stretch { 25 | display:block; 26 | width:100%; height:100%; 27 | } 28 | 29 | .cover { 30 | display:block; 31 | width:100%; height:100%; 32 | object-fit: cover; 33 | } 34 | 35 | @media (prefers-color-scheme: dark) { 36 | body { 37 | margin:0; 38 | height:100%; 39 | background: #252941; 40 | 41 | background-size: 100% 100%; 42 | } 43 | } 44 | --------------------------------------------------------------------------------