├── .github
├── FUNDING.yml
├── PULL_REQUEST_TEMPLATE.md
├── dependabot.yml
└── workflows
│ └── flutter-ci.yml
├── .gitignore
├── .idea
├── .gitignore
└── runConfigurations
│ ├── development.xml
│ └── production.xml
├── .metadata
├── .vscode
└── launch.json
├── CODE_OF_CONDUCT.md
├── LICENSE
├── Makefile
├── README.md
├── analysis_options.yaml
├── android
├── app
│ ├── build.gradle
│ ├── signingConfigs
│ │ ├── debug.gradle
│ │ ├── debug.keystore
│ │ ├── release.gradle
│ │ └── release.keystore
│ └── src
│ │ ├── development
│ │ ├── AndroidManifest.xml
│ │ ├── google-services.json
│ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── jp
│ │ │ │ └── wasabeef
│ │ │ │ └── app
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── production
│ │ ├── AndroidManifest.xml
│ │ ├── google-services.json
│ │ └── res
│ │ └── values
│ │ └── strings.xml
├── app_android.iml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── app.iml
├── assets
├── fonts
│ └── Rotunda-Bold.otf
├── images
│ ├── 2.0x
│ │ ├── article_placeholder.webp
│ │ └── icon_placeholder.jpg
│ ├── 3.0x
│ │ ├── article_placeholder.webp
│ │ └── icon_placeholder.jpg
│ ├── article_placeholder.webp
│ └── icon_placeholder.jpg
└── svgs
│ └── firebase.svg
├── bitrise.yml
├── codecov.yml
├── codemagic.yaml
├── ios
├── Config
│ ├── Development.xcconfig
│ └── Production.xcconfig
├── Flutter
│ └── AppFrameworkInfo.plist
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── Development.xcscheme
│ │ ├── Production.xcscheme
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
├── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ ├── Resources
│ │ └── Firebase
│ │ │ ├── Development
│ │ │ └── GoogleService-Info.plist
│ │ │ └── Production
│ │ │ └── GoogleService-Info.plist
│ ├── Runner-Bridging-Header.h
│ └── ja.lproj
│ │ ├── LaunchScreen.strings
│ │ └── Main.strings
└── Scripts
│ └── copy_google_service.sh
├── l10n.yaml
├── lib
├── app.dart
├── constants.dart
├── data
│ ├── app_error.dart
│ ├── local
│ │ ├── app_shared_preferences.dart
│ │ ├── theme_data_source.dart
│ │ └── theme_data_source_impl.dart
│ ├── model
│ │ ├── article.dart
│ │ ├── article.freezed.dart
│ │ ├── article.g.dart
│ │ ├── news.dart
│ │ ├── news.freezed.dart
│ │ ├── news.g.dart
│ │ ├── result.dart
│ │ ├── result.freezed.dart
│ │ ├── source.dart
│ │ ├── source.freezed.dart
│ │ └── source.g.dart
│ ├── provider
│ │ ├── app_shared_preferences_provider.dart
│ │ ├── auth_data_source_provider.dart
│ │ ├── auth_repository_provider.dart
│ │ ├── dio_provider.dart
│ │ ├── firebase_auth_provider.dart
│ │ ├── news_data_source_provider.dart
│ │ ├── news_repository_provider.dart
│ │ ├── theme_data_source_provider.dart
│ │ └── theme_repository_provider.dart
│ ├── remote
│ │ ├── app_dio.dart
│ │ ├── auth_data_source.dart
│ │ ├── auth_data_source_impl.dart
│ │ ├── news_data_source.dart
│ │ └── news_data_source_impl.dart
│ └── repository
│ │ ├── auth_repository.dart
│ │ ├── auth_repository_impl.dart
│ │ ├── news_repository.dart
│ │ ├── news_repository_impl.dart
│ │ ├── theme_repository.dart
│ │ └── theme_repository_impl.dart
├── gen
│ ├── assets.gen.dart
│ └── fonts.gen.dart
├── l10n
│ ├── intl_messages_en.arb
│ └── intl_messages_ja.arb
├── main.dart
├── ui
│ ├── app_theme.dart
│ ├── component
│ │ ├── article_item.dart
│ │ ├── container_with_loading.dart
│ │ ├── dialog.dart
│ │ ├── image.dart
│ │ ├── loading.dart
│ │ └── network_image.dart
│ ├── detail
│ │ └── detail_page.dart
│ ├── home
│ │ ├── home_page.dart
│ │ └── home_view_model.dart
│ ├── loading_state_view_model.dart
│ ├── signIn
│ │ └── sign_in_page.dart
│ └── user_view_model.dart
└── util
│ ├── error_snackbar.dart
│ └── ext
│ ├── async_snapshot.dart
│ └── date_time.dart
├── package-lock.json
├── package.json
├── pubspec.lock
├── pubspec.yaml
├── scripts
└── codecov.sh
├── test
├── data
│ ├── app_error_test.dart
│ ├── dummy
│ │ ├── dummy_article.dart
│ │ ├── dummy_news.dart
│ │ └── dummy_response_news_api.dart
│ ├── local
│ │ └── fake_theme_data_source_impl.dart
│ ├── remote
│ │ ├── fake_app_dio.dart
│ │ └── fake_news_data_source_impl.dart
│ └── repository
│ │ └── fake_news_repository_impl.dart
├── ui
│ ├── app_theme_test.dart
│ ├── view_model_test.dart
│ └── widget_test.dart
└── util
│ └── ext
│ └── date_time_test.dart
└── web
├── favicon.png
├── icons
├── Icon-192.png
└── Icon-512.png
├── index.html
└── manifest.json
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: wasabeef # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### What does this change?
2 |
3 | ### What is the value of this and can you measure success?
4 |
5 | ### Screenshots (Optional)
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: npm
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | time: "20:00"
8 | open-pull-requests-limit: 10
9 | - package-ecosystem: github-actions
10 | directory: "/"
11 | schedule:
12 | interval: daily
13 | time: "20:00"
14 | open-pull-requests-limit: 10
15 |
--------------------------------------------------------------------------------
/.github/workflows/flutter-ci.yml:
--------------------------------------------------------------------------------
1 | name: Flutter CI
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | build:
11 | runs-on: macos-latest
12 | steps:
13 | - uses: actions/checkout@v2
14 | - uses: subosito/flutter-action@v1
15 | with:
16 | channel: 'beta'
17 | # TODO: Workaround https://github.com/flutter/flutter/issues/72737
18 | flutter-version: 1.24.0-10.2.pre
19 |
20 | - name: Cache Gradle modules
21 | uses: actions/cache@v2
22 | env:
23 | cache-number: ${{ secrets.CACHE_NUMBER }}
24 | with:
25 | path: |
26 | ~/android/.gradle
27 | ~/.gradle/cache
28 | # ~/.gradle/wrapper
29 | key: ${{ runner.os }}-gradle-${{ env.cache-number }}-${{ hashFiles('android/build.gradle') }}-${{ hashFiles('android/app/build.gradle') }}
30 | restore-keys: |
31 | ${{ runner.os }}-gradle-${{ env.cache-name }}-${{ hashFiles('android/build.gradle') }}
32 | ${{ runner.os }}-gradle-${{ env.cache-name }}-
33 | ${{ runner.os }}-gradle-
34 | ${{ runner.os }}-
35 |
36 | - name: Cache CocoaPods modules
37 | uses: actions/cache@v2
38 | env:
39 | cache-number: ${{ secrets.CACHE_NUMBER }}
40 | with:
41 | path: Pods
42 | key: ${{ runner.os }}-pods-${{ env.cache-number }}-${{ hashFiles('ios/Podfile.lock') }}
43 | restore-keys: |
44 | ${{ runner.os }}-pods-${{ env.cache-name }}-
45 | ${{ runner.os }}-pods-
46 | ${{ runner.os }}-
47 |
48 | - name: Cache Flutter modules
49 | uses: actions/cache@v2
50 | env:
51 | cache-number: ${{ secrets.CACHE_NUMBER }}
52 | with:
53 | path: |
54 | /Users/runner/hostedtoolcache/flutter
55 | # ~/.pub-cache
56 | key: ${{ runner.os }}-pub-${{ env.cache-number }}-${{ env.flutter_version }}-${{ hashFiles('pubspec.lock') }}
57 | restore-keys: |
58 | ${{ runner.os }}-pub-${{ env.flutter_version }}-
59 | ${{ runner.os }}-pub-
60 | ${{ runner.os }}-
61 |
62 | - name: Get flutter dependencies.
63 | run: make dependencies
64 |
65 | - name: Check for any formatting and statically analyze the code.
66 | run: make format-analyze
67 |
68 | - name: Run widget tests for our flutter project.
69 | env:
70 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
71 | run: |
72 | make unit-test
73 | make codecov
74 |
75 | - name: Build ipa and apk
76 | run: |
77 | make build-android-prd
78 | make build-ios-prd
79 |
80 | - name: Slack Notification
81 | uses: homoluctus/slatify@master
82 | if: always()
83 | with:
84 | type: ${{ job.status }}
85 | job_name: '*Flutter Build*'
86 | mention: 'here'
87 | mention_if: 'failure'
88 | channel: '#develop'
89 | username: 'Github Actions'
90 | icon_emoji: ':octocat:'
91 | url: ${{ secrets.SLACK_WEBHOOK_URL }}
92 | commit: true
93 | token: ${{ secrets.GITHUB_TOKEN }}
94 |
95 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://www.dartlang.org/guides/libraries/private-files
2 |
3 | # Miscellaneous
4 | *.class
5 | *.log
6 | *.pyc
7 | *.swp
8 | .DS_Store
9 | .atom/
10 | .buildlog/
11 | .history
12 | .svn/
13 |
14 | # IntelliJ related
15 | *.iml
16 | *.ipr
17 | *.iws
18 |
19 | .idea/.gitignore
20 | .idea/dictionaries/
21 | .idea/libraries/
22 | .idea/misc.xml
23 | .idea/modules.xml
24 | .idea/vcs.xml
25 | .idea/workspace.xml
26 | .idea/saveactions_settings.xml
27 | android/.idea/
28 | ios/.idea/
29 |
30 | # The .vscode folder contains launch configuration and tasks you configure in
31 | # VS Code which you may wish to be included in version control, so this line
32 | # is commented out by default.
33 | #.vscode/
34 |
35 | # Flutter/Dart/Pub related
36 | **/doc/api/
37 | .dart_tool/
38 | .flutter-plugins
39 | .flutter-plugins-dependencies
40 | .packages
41 | .pub-cache/
42 | .pub/
43 | /build/
44 | generated_plugin_registrant.dart
45 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
46 |
47 | # Fastlane related
48 | android/fastlane/report.xml
49 | ios/fastlane/report.xml
50 |
51 | # Android related
52 | **/android/**/gradle-wrapper.jar
53 | **/android/.gradle
54 | **/android/captures/
55 | **/android/gradlew
56 | **/android/gradlew.bat
57 | **/android/local.properties
58 | **/android/settings_aar.gradle
59 | **/android/**/GeneratedPluginRegistrant.java
60 | **/android/**/gen
61 |
62 | # iOS/XCode related
63 | **/ios/**/*.mode1v3
64 | **/ios/**/*.mode2v3
65 | **/ios/**/*.moved-aside
66 | **/ios/**/*.pbxuser
67 | **/ios/**/*.perspectivev3
68 | **/ios/**/*sync/
69 | **/ios/**/.sconsign.dblite
70 | **/ios/**/.tags*
71 | **/ios/**/.vagrant/
72 | **/ios/**/DerivedData/
73 | **/ios/**/Icon?
74 | **/ios/**/Pods/
75 | **/ios/**/.symlinks/
76 | **/ios/**/profile
77 | **/ios/**/xcuserdata
78 | **/ios/.generated/
79 | **/ios/build/
80 | **/ios/Flutter/.last_build_id
81 | **/ios/Flutter/App.framework
82 | **/ios/Flutter/Flutter.framework
83 | **/ios/Flutter/Generated.xcconfig
84 | **/ios/Flutter/app.flx
85 | **/ios/Flutter/app.zip
86 | **/ios/Flutter/flutter_assets/
87 | **/ios/Flutter/flutter_export_environment.sh
88 | **/ios/Flutter/Flutter.podspec
89 | **/ios/ServiceDefinitions.json
90 | **/ios/Runner/GeneratedPluginRegistrant.*
91 | **/ios/Runner/GoogleService-Info.plist
92 | !**/ios/**/default.mode1v3
93 | !**/ios/**/default.mode2v3
94 | !**/ios/**/default.pbxuser
95 | !**/ios/**/default.perspectivev3
96 |
97 | # Web related
98 | *.dart.js
99 | *.info.json # Produced by the --dump-info flag.
100 | *.js # When generated by dart2js. Don't specify *.js if your
101 | # project includes source files written in JavaScript.
102 | *.js_
103 | *.js.deps
104 | *.js.map
105 | node_modules/
106 |
107 | ## Generated code
108 | # **/*.g.dart
109 | #lib/l10n/messages_*
110 | #l10n-arb/intl_messages.arb
111 |
112 | ## Test coverage
113 | coverage/
114 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/development.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/production.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: e606910f28be51c8151f6169072afe3b3a8b3c5e
8 | channel: beta
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Flutter development",
6 | "program": "lib/main.dart",
7 | "request": "launch",
8 | "type": "dart",
9 | "args": [
10 | "--dart-define=FLAVOR=development",
11 | "--flavor",
12 | "development"
13 | ]
14 | },
15 | {
16 | "name": "Flutter production",
17 | "program": "lib/main.dart",
18 | "request": "launch",
19 | "type": "dart",
20 | "args": [
21 | "--dart-define=FLAVOR=production",
22 | "--flavor",
23 | "production"
24 | ]
25 | }
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | [INSERT CONTACT METHOD].
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Daichi Furiya
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: setup
2 | setup:
3 | flutter channel beta
4 | flutter upgrade
5 | flutter pub get
6 | npm install
7 | gem update cocoapods
8 | cd ios/ && pod install && cd ..
9 |
10 | .PHONY: dependencies
11 | dependencies:
12 | flutter pub get
13 |
14 | .PHONY: analyze
15 | analyze:
16 | flutter analyze
17 |
18 | .PHONY: format
19 | format:
20 | flutter format lib/
21 |
22 | .PHONY: format-analyze
23 | format-analyze:
24 | flutter format --dry-run lib/
25 | flutter analyze
26 |
27 | .PHONY: build-runner
28 | build-runner:
29 | flutter packages pub run build_runner build --delete-conflicting-outputs
30 |
31 | .PHONY: run-dev
32 | run-dev:
33 | flutter run --flavor development --dart-define=FLAVOR=development --target lib/main.dart
34 |
35 | .PHONY: run-prd
36 | run-prd:
37 | flutter run --release --flavor production --dart-define=FLAVOR=production --target lib/main.dart
38 |
39 | .PHONY: build-android-dev
40 | build-android-dev:
41 | flutter build apk --flavor development --dart-define=FLAVOR=development --target lib/main.dart
42 |
43 | .PHONY: build-android-prd
44 | build-android-prd:
45 | flutter build apk --release --flavor production --dart-define=FLAVOR=production --target lib/main.dart
46 |
47 | .PHONY: build-ios-dev
48 | build-ios-dev:
49 | cd ios/ && pod install && cd ..
50 | flutter build ios --no-codesign --flavor development --dart-define=FLAVOR=development --target lib/main.dart
51 |
52 | .PHONY: build-ios-prd
53 | build-ios-prd:
54 | cd ios/ && pod install && cd ..
55 | flutter build ios --release --no-codesign --flavor production --dart-define=FLAVOR=production --target lib/main.dart
56 |
57 | .PHONY: unit-test
58 | unit-test:
59 | flutter test --coverage --coverage-path=./coverage/lcov.info
60 |
61 | .PHONY: codecov
62 | codecov:
63 | ./scripts/codecov.sh ${CODECOV_TOKEN}
64 |
65 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter Architecture Blueprints
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 | Flutter Architecture Blueprints is a project that introduces MVVM architecture and project structure approaches to developing Flutter apps.
28 |
29 | ## Documentation
30 |
31 | - [Install Flutter](https://flutter.dev/get-started/)
32 | - [Flutter documentation](https://flutter.dev/docs)
33 | - [Contributing to Flutter](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/CONTRIBUTING.md)
34 |
35 | ## Requirements
36 |
37 | - [Flutter 1.22.0+ (beta channel)](https://flutter.dev/docs/get-started/install)
38 | - [Dart 2.10.0+](https://github.com/dart-lang/sdk/wiki/Installing-beta-and-dev-releases-with-brew,-choco,-and-apt-get#installing)
39 | - [npm](https://treehouse.github.io/installation-guides/mac/node-mac.html)
40 |
41 | ## Environment
42 |
43 |
44 |
45 | **iOS**
46 | - iOS 13+
47 |
48 | **Android**
49 | - Android 5.1+
50 | - minSdkVersion 22
51 | - targetSdkVersion 30
52 |
53 | ## App architecture
54 | - Base on [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel) + [Repository](https://docs.microsoft.com/ja-jp/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design)
55 |
56 | ## Code Style
57 | - [Effective Dart](https://dart.dev/guides/language/effective-dart)
58 |
59 | ## Assets, Fonts
60 |
61 | **If added some assets or fonts**
62 |
63 | - Use [FlutterGen](https://github.com/FlutterGen/flutter_gen/)
64 |
65 | ## Models
66 |
67 | **If added some models for api results**
68 |
69 | - Use [Freezed](https://pub.dev/packages/freezed)
70 |
71 | ## Localizations
72 |
73 | **If added some localizations (i.g. edited [*.arb](https://github.com/wasabeef/flutter-architecture-blueprints/tree/main/lib/l10n))**
74 |
75 | - Use [Official Flutter localization package](https://docs.google.com/document/d/10e0saTfAv32OZLRmONy866vnaw0I2jwL8zukykpgWBc)
76 |
77 | ## Git Commit message style
78 |
79 | - [Semantic Commit Messages](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716)
80 |
81 | ## Code collections
82 |
83 | #### Project settings
84 | |Working status|Category|Description|Codes|
85 | |:---:|---|---|---|
86 | | ✅ | Dart | Dart version | [pubspec.yaml](https://github.com/wasabeef/flutter-architecture-blueprints/blob/aed5d8fab3dee4fa8a967a8ecd7092fd2f727d5f/pubspec.yaml#L20-L22) |
87 | | ✅ | Dart | Switching between Development and Production environment | [constants.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/constants.dart), [runConfigurations](https://github.com/wasabeef/flutter-architecture-blueprints/tree/main/.idea/runConfigurations), [Makefile](https://github.com/wasabeef/flutter-architecture-blueprints/blob/be26dc3f7ff27ee2710326abe8ed09893a35386c/Makefile#L25-L41) |
88 | | ✅ | Dart | Lint / Analyze | [analysis_options.yaml](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/analysis_options.yaml) |
89 | | ✅ | Android | Kotlin version | [build.gradle](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/android/build.gradle#L2) |
90 | | ✅ | Android | Apk attributes | build.gradle ([compileSdkVersion](https://github.com/wasabeef/flutter-architecture-blueprints/blob/be26dc3f7ff27ee2710326abe8ed09893a35386c/android/app/build.gradle#L30), [applicationId](https://github.com/wasabeef/flutter-architecture-blueprints/blob/be26dc3f7ff27ee2710326abe8ed09893a35386c/android/app/build.gradle#L43), [minSdkVersion](https://github.com/wasabeef/flutter-architecture-blueprints/blob/be26dc3f7ff27ee2710326abe8ed09893a35386c/android/app/build.gradle#L44), [targetSdkVersion](https://github.com/wasabeef/flutter-architecture-blueprints/blob/be26dc3f7ff27ee2710326abe8ed09893a35386c/android/app/build.gradle#L45)) |
91 | | ✅ | Android | Switching between Development and Production environment | [build.gradle](https://github.com/wasabeef/flutter-architecture-blueprints/blob/be26dc3f7ff27ee2710326abe8ed09893a35386c/android/app/build.gradle#L50-L75), [Flavor dirs](https://github.com/wasabeef/flutter-architecture-blueprints/tree/main/android/app/src), [signingConfigs](https://github.com/wasabeef/flutter-architecture-blueprints/tree/main/android/app/signingConfigs) |
92 | | ✅ | iOS | Xcode version | [compatibilityVersion](https://github.com/wasabeef/flutter-architecture-blueprints/blob/3ae7135cc040fecf5bbb2100a353f6594037752d/ios/Runner.xcodeproj/project.pbxproj#L182) |
93 | | ✅ | iOS | Podfile | [Podfile](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/ios/Podfile) |
94 | | ✅ | iOS | Switching between Development and Production environment | [xcconfig](https://github.com/wasabeef/flutter-architecture-blueprints/tree/main/ios/Config), [Podfile](https://github.com/wasabeef/flutter-architecture-blueprints/blob/be26dc3f7ff27ee2710326abe8ed09893a35386c/ios/Podfile#L7-L12) |
95 | | ✅ | [Firebase](https://firebase.flutter.dev/docs/overview) | [Android] Switching between Development and Production google-service.json using flavors | [development and production](https://github.com/wasabeef/flutter-architecture-blueprints/tree/main/android/app/src) |
96 | | ✅ | [Firebase](https://firebase.flutter.dev/docs/overview) | [iOS] Switching between Development and Production GoogleService-Info.plist using run script| [copy_google_service.sh](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/ios/Scripts/copy_google_service.sh), [development and production](https://github.com/wasabeef/flutter-architecture-blueprints/tree/main/ios/Runner/Resources/Firebase) |
97 | | ✅ | [Firebase Auth](https://firebase.flutter.dev/docs/auth/overview) | SignIn, SignOut | [auth_data_source_impl.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/data/remote/auth_data_source_impl.dart) |
98 | | ✅ | [Firebase Crashlytics](https://firebase.flutter.dev/docs/crashlytics/overview) | Crash Reports | [main.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/main.dart) |
99 | | ✅ | [Firebase Performance](https://firebase.flutter.dev/docs/performance/overview) | Network monitoring with [dio_firebase_performance](https://pub.dev/packages/dio_firebase_performance) | [app_dio.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/eb749c742216088cbf2ff821f463e3de02d7d3b3/lib/data/remote/app_dio.dart#L27-L28) |
100 |
101 | #### Architecture
102 |
103 | |Working status|Category|Description|Codes|
104 | |:---:|---|---|---|
105 | | ✅ | Base | Using [Riverpod](https://pub.dev/packages/riverpod) + [Hooks](https://pub.dev/packages/flutter_hooks) + [ChangeNotifier](https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#changenotifier) + MVVM | [home_page.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/ui/home/home_page.dart#L41-L47), [home_view_model.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/ui/home/home_view_model.dart), [news_repository.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/data/repository/news_repository.dart), [news_data_source.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/data/remote/news_data_source.dart) |
106 | | ✅ | Networking | Using [dio](https://pub.dev/packages/dio) | [app_dio.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/data/remote/app_dio.dart), [news_data_source_impl.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/be26dc3f7ff27ee2710326abe8ed09893a35386c/lib/data/remote/news_data_source_impl.dart#L16-L33) |
107 | | ✅ | Caching | Using [dio_http_cache](https://pub.dev/packages/dio_http_cache) | [app_dio.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/data/remote/app_dio.dart#L26-L30), [news_data_source_impl.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/data/remote/news_data_source_impl.dart#L35) |
108 | | ✅ | Data | Using [Freezed](https://pub.dev/packages/freezed) | [model classes](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/data/model) |
109 | | ✅ | Persist Data | Using [shared_preferences](https://pub.dev/packages/shared_preferences) | [theme_data_source_impl.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/data/local/theme_data_source_impl.dart) |
110 | | ✅ | Constants | Define constants and route names | [constants.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/constants.dart) |
111 | | ✅ | Localization | Switching between two languages with [Intl package](https://docs.google.com/document/d/10e0saTfAv32OZLRmONy866vnaw0I2jwL8zukykpgWBc/edit) | [*.arb](https://github.com/wasabeef/flutter-architecture-blueprints/tree/main/lib/l10n) |
112 | | ✅ | Error handling | Using Result pattern - A value that represents either a success or a failure, including an associated value in each case. | [result.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/data/model/result.dart), [news_repository_impl.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/data/repository/news_repository_impl.dart#L16), [home_page.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/e8f0ed78a62e5b27609e60206bd121295a13faac/lib/ui/home/home_page.dart#L51-L63) |
113 |
114 | #### UI
115 | |Working status|Category|Description|Codes|
116 | |:---:|---|---|---|
117 | | ✅ | Theme | Dynamically Switch between light and dark themes | [app_theme.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/app.dart#L22-L24) |
118 | | ✅ | Font | Using [Google font](https://pub.dev/packages/google_fonts) | [app_theme.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/lib/ui/app_theme.dart#L62) |
119 | | ✅ | Transition | Simple animation between screens using [Hero](https://flutter.dev/docs/development/ui/animations/hero-animations) | [article_item.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/be26dc3f7ff27ee2710326abe8ed09893a35386c/lib/ui/component/article_item.dart#L28), [detail_page.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/be26dc3f7ff27ee2710326abe8ed09893a35386c/lib/ui/detail/datail_page.dart#L13-L24) |
120 |
121 | #### Testing
122 | |Working status|Category|Description|Codes|
123 | |:---:|---|---|---|
124 | | ✅ | API(Repositories) | Using [Mockito](https://pub.dev/packages/mockito) | [view_mode_test.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/test/ui/view_model_test.dart), [app_theme_test.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/test/ui/app_theme_test.dart) |
125 | | ✅️ | UI | Using [Mockito](https://pub.dev/packages/mockito) | [widget_test.dart](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/test/ui/widget_test.dart) |
126 | | ✅ | Coverage reports | Send the report to [Codecov](https://codecov.io/) on CI |[codecov.yml](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/codecov.yml), [codecov.sh](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/scripts/codecov.sh), [flutte-ci.yml](https://github.com/wasabeef/flutter-architecture-blueprints/blob/8e2a373af5e4603aaa75d3c9b9af8150400ab46e/.github/workflows/flutter-ci.yml#L66-L71) |
127 |
128 | #### CI
129 | |Working status|Category|Description|Codes|
130 | |:---:|---|---|---|
131 | | ✅ | Git | Git hooks for format and analyze | [package.json](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/package.json#L4-L11), [Makefile](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/Makefile#L9-L12)|
132 | | ✅ | Git | .gitignore settings | [.gitignore](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/.gitignore) |
133 | | ✅ | Build | Using [Codemagic](https://codemagic.io/) |[codemagic.yaml](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/codemagic.yaml)|
134 | | ✅ | Build | Using [Bitrise](https://www.bitrise.io/) |[bitrise.yml](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/bitrise.yml)|
135 | | ✅ | Build | Using [Github Actions](https://github.com/features/actions) | [.github/workflows/flutter-ci.yml](https://github.com/wasabeef/flutter-architecture-blueprints/blob/main/.github/workflows/flutter-ci.yml) |
136 |
137 | ## Getting Started
138 |
139 |
140 |
141 | ### Setup
142 |
143 | ```shell script
144 | $ make setup
145 | $ make build-runner
146 | ```
147 |
148 | ### Make .apk and .ipa file
149 |
150 | Android
151 | ```shell script
152 | $ make build-android-dev
153 | $ make build-android-prd
154 | ```
155 |
156 | iOS
157 | ```shell script
158 | $ make build-ios-dev
159 | $ make build-ios-prd
160 | ```
161 |
162 | ### Run app
163 | ```shell script
164 | $ make run-dev
165 | $ make run-prd
166 | ```
167 |
168 |
169 |
170 | ### How to add assets(images..)
171 | 1. Add assets
172 | 2. Run [FlutterGen](https://github.com/fluttergen)
173 |
174 | ### How to add localizations
175 | 1. Edit [*.arb](https://github.com/wasabeef/flutter-architecture-blueprints/tree/main/lib/l10n) files.
176 | 2. Run generate the `flutter pub get`
177 |
178 | ## Special Thanks.
179 |
180 | - [News API](https://newsapi.org/)
181 |
182 | **Contributors**
183 | - [lcdsmao](https://github.com/lcdsmao)
184 |
185 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:effective_dart/analysis_options.yaml
2 | analyzer:
3 | exclude:
4 | - "lib/generated_plugin_registrant.dart"
5 | - "lib/l10n/messages_*.dart"
6 | - "lib/data/model/*.g.dart"
7 | - "lib/data/model/*.freezed.dart"
8 |
9 | linter:
10 | rules:
11 | public_member_api_docs: false
12 | prefer_const_constructors: true
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 | apply plugin: 'com.google.firebase.crashlytics'
28 |
29 | android {
30 | // Workaround for support to multiple CIs (Bitrise and Codemagic).
31 | compileSdkVersion System.getenv('ANDROID_SDK_VERSION') ? System.getenv('ANDROID_SDK_VERSION').toInteger() : 30
32 |
33 | sourceSets {
34 | main.java.srcDirs += 'src/main/kotlin'
35 | }
36 |
37 | lintOptions {
38 | disable 'InvalidPackage'
39 | checkReleaseBuilds false // issue https://github.com/flutter/flutter/issues/22397
40 | }
41 |
42 | defaultConfig {
43 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
44 | applicationId "jp.wasabeef.app"
45 | minSdkVersion 22
46 | targetSdkVersion 30
47 | versionCode flutterVersionCode.toInteger()
48 | versionName flutterVersionName
49 | }
50 |
51 | // SigningConfigs
52 | apply from: 'signingConfigs/debug.gradle', to: android
53 | apply from: 'signingConfigs/release.gradle', to: android
54 |
55 | buildTypes {
56 | release {
57 | signingConfig signingConfigs.release
58 | }
59 | debug {
60 | debuggable true
61 | signingConfig signingConfigs.debug
62 | }
63 | }
64 |
65 | flavorDimensions "environment"
66 | productFlavors {
67 | development {
68 | dimension "environment"
69 | applicationIdSuffix ".dev"
70 | versionNameSuffix "-Dev"
71 | }
72 |
73 | production {
74 | dimension "environment"
75 | }
76 | }
77 | }
78 |
79 | flutter {
80 | source '../..'
81 | }
82 |
83 | apply plugin: 'com.google.gms.google-services'
--------------------------------------------------------------------------------
/android/app/signingConfigs/debug.gradle:
--------------------------------------------------------------------------------
1 | signingConfigs {
2 | debug {
3 | storeFile file("debug.keystore")
4 | storePassword "android"
5 | keyAlias "androiddebugkey"
6 | keyPassword "android"
7 | }
8 | }
9 |
10 | // $ keytool -v -list -keystore
11 | // Certificate fingerprints:
12 | // MD5: 28:22:7C:A4:B9:2F:6E:C7:D5:58:62:48:EB:7E:82:C3
13 | // SHA1: 94:25:A9:50:9C:0E:AE:AA:00:37:5E:D6:71:E3:BC:ED:17:E5:0C:A3
14 | // SHA256: 04:92:39:09:3D:1C:B6:16:BE:55:58:A3:5F:3B:BB:CB:0B:E7:F1:DA:AA:26:C5:2D:BD:2F:44:CF:AE:47:CF:87
--------------------------------------------------------------------------------
/android/app/signingConfigs/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/android/app/signingConfigs/debug.keystore
--------------------------------------------------------------------------------
/android/app/signingConfigs/release.gradle:
--------------------------------------------------------------------------------
1 | // TODO Must be re-created.
2 | signingConfigs {
3 | release {
4 | storeFile file("release.keystore")
5 | storePassword "aabbccdd"
6 | keyAlias "fab"
7 | keyPassword "aabbccdd"
8 | }
9 | }
10 |
11 | // $ keytool -v -list -keystore
12 | // Certificate fingerprints:
13 | // MD5: 9A:69:D4:B6:BF:BE:C1:A5:C5:BB:05:7B:36:84:D7:5C
14 | // SHA1: AA:88:1A:A8:47:7A:90:73:16:D6:F1:B7:D5:25:7B:92:BC:C9:4B:FD
15 | // SHA256: 22:39:5E:46:8C:55:00:6C:3A:4B:68:7D:66:20:0A:42:07:75:90:71:29:31:DA:1C:6E:48:FC:60:58:6E:0C:2D
--------------------------------------------------------------------------------
/android/app/signingConfigs/release.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/android/app/signingConfigs/release.keystore
--------------------------------------------------------------------------------
/android/app/src/development/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/development/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "339920746703",
4 | "firebase_url": "https://flutter-arch-blueprints-dev.firebaseio.com",
5 | "project_id": "flutter-arch-blueprints-dev",
6 | "storage_bucket": "flutter-arch-blueprints-dev.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:339920746703:android:5a97ba145b698f05ee9fba",
12 | "android_client_info": {
13 | "package_name": "jp.wasabeef.app.dev"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "339920746703-28cfben1heai5p0aqk8p3nl73toi4n03.apps.googleusercontent.com",
19 | "client_type": 1,
20 | "android_info": {
21 | "package_name": "jp.wasabeef.app.dev",
22 | "certificate_hash": "aa881aa8477a907316d6f1b7d5257b92bcc94bfd"
23 | }
24 | },
25 | {
26 | "client_id": "339920746703-itjdedk624qhvhjjfipgdp62ororfho1.apps.googleusercontent.com",
27 | "client_type": 1,
28 | "android_info": {
29 | "package_name": "jp.wasabeef.app.dev",
30 | "certificate_hash": "9425a9509c0eaeaa00375ed671e3bced17e50ca3"
31 | }
32 | },
33 | {
34 | "client_id": "339920746703-g2k3mt9j2bva5v555d9ps2j2ord7ecba.apps.googleusercontent.com",
35 | "client_type": 3
36 | }
37 | ],
38 | "api_key": [
39 | {
40 | "current_key": "AIzaSyDmkQUMEuXgB4FM50dcizxumL12DUQG8ng"
41 | }
42 | ],
43 | "services": {
44 | "appinvite_service": {
45 | "other_platform_oauth_client": [
46 | {
47 | "client_id": "339920746703-g2k3mt9j2bva5v555d9ps2j2ord7ecba.apps.googleusercontent.com",
48 | "client_type": 3
49 | },
50 | {
51 | "client_id": "339920746703-140i3bhk3lqtpn2p2e7035btcp61p32i.apps.googleusercontent.com",
52 | "client_type": 2,
53 | "ios_info": {
54 | "bundle_id": "jp.wasabeef.app.dev"
55 | }
56 | }
57 | ]
58 | }
59 | }
60 | }
61 | ],
62 | "configuration_version": "1"
63 | }
--------------------------------------------------------------------------------
/android/app/src/development/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | FAB Dev
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
9 |
10 |
11 |
15 |
22 |
26 |
30 |
35 |
39 |
40 |
41 |
42 |
43 |
44 |
46 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/jp/wasabeef/app/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package jp.wasabeef.app
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/production/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/production/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "208498828836",
4 | "firebase_url": "https://flutter-arc-blueprints.firebaseio.com",
5 | "project_id": "flutter-arc-blueprints",
6 | "storage_bucket": "flutter-arc-blueprints.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:208498828836:android:58145629940ce4a96b5ab1",
12 | "android_client_info": {
13 | "package_name": "jp.wasabeef.app"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "208498828836-3323hr2v1b84i3s8sv4921462l1vtc1i.apps.googleusercontent.com",
19 | "client_type": 1,
20 | "android_info": {
21 | "package_name": "jp.wasabeef.app",
22 | "certificate_hash": "9425a9509c0eaeaa00375ed671e3bced17e50ca3"
23 | }
24 | },
25 | {
26 | "client_id": "208498828836-it7b64n6biakq3u964s0sudjbnklmkl2.apps.googleusercontent.com",
27 | "client_type": 1,
28 | "android_info": {
29 | "package_name": "jp.wasabeef.app",
30 | "certificate_hash": "aa881aa8477a907316d6f1b7d5257b92bcc94bfd"
31 | }
32 | },
33 | {
34 | "client_id": "208498828836-rbgoklet6680lrcccnov4a25vs9k5du8.apps.googleusercontent.com",
35 | "client_type": 3
36 | }
37 | ],
38 | "api_key": [
39 | {
40 | "current_key": "AIzaSyAzj4n6ihX9kVt_KI24xEgqFtfO7GOdZEE"
41 | }
42 | ],
43 | "services": {
44 | "appinvite_service": {
45 | "other_platform_oauth_client": [
46 | {
47 | "client_id": "208498828836-rbgoklet6680lrcccnov4a25vs9k5du8.apps.googleusercontent.com",
48 | "client_type": 3
49 | },
50 | {
51 | "client_id": "208498828836-139a9k718tbf1ijjmplm9sef21crjqv9.apps.googleusercontent.com",
52 | "client_type": 2,
53 | "ios_info": {
54 | "bundle_id": "jp.wasabeef.app"
55 | }
56 | }
57 | ]
58 | }
59 | }
60 | }
61 | ],
62 | "configuration_version": "1"
63 | }
--------------------------------------------------------------------------------
/android/app/src/production/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | FAB
4 |
5 |
--------------------------------------------------------------------------------
/android/app_android.iml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.4.20'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.1.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | classpath 'com.google.gms:google-services:4.3.4'
12 | classpath 'com.google.firebase:firebase-crashlytics-gradle:2.4.1'
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | google()
19 | jcenter()
20 | }
21 | }
22 |
23 | rootProject.buildDir = '../build'
24 | subprojects {
25 | project.buildDir = "${rootProject.buildDir}/${project.name}"
26 | }
27 | subprojects {
28 | project.evaluationDependsOn(':app')
29 | }
30 |
31 | task clean(type: Delete) {
32 | delete rootProject.buildDir
33 | }
34 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 | kotlin.stdlib.default.dependency=false
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/assets/fonts/Rotunda-Bold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/assets/fonts/Rotunda-Bold.otf
--------------------------------------------------------------------------------
/assets/images/2.0x/article_placeholder.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/assets/images/2.0x/article_placeholder.webp
--------------------------------------------------------------------------------
/assets/images/2.0x/icon_placeholder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/assets/images/2.0x/icon_placeholder.jpg
--------------------------------------------------------------------------------
/assets/images/3.0x/article_placeholder.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/assets/images/3.0x/article_placeholder.webp
--------------------------------------------------------------------------------
/assets/images/3.0x/icon_placeholder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/assets/images/3.0x/icon_placeholder.jpg
--------------------------------------------------------------------------------
/assets/images/article_placeholder.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/assets/images/article_placeholder.webp
--------------------------------------------------------------------------------
/assets/images/icon_placeholder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/assets/images/icon_placeholder.jpg
--------------------------------------------------------------------------------
/bitrise.yml:
--------------------------------------------------------------------------------
1 | ---
2 | format_version: '8'
3 | default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
4 | project_type: flutter
5 | trigger_map:
6 | - push_branch: main
7 | workflow: main-build
8 | - pull_request_source_branch: "*"
9 | workflow: pull-request-build
10 | workflows:
11 | main-build:
12 | steps:
13 | - activate-ssh-key@4:
14 | run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
15 | - git-clone@4: {}
16 | - script@1:
17 | title: Do anything with Script step
18 | - flutter-installer@0:
19 | inputs:
20 | - version: beta
21 | - cache-pull@2: {}
22 | - flutter-analyze@0.2:
23 | inputs:
24 | - project_location: "$BITRISE_FLUTTER_PROJECT_LOCATION"
25 | - flutter-test@0:
26 | inputs:
27 | - additional_params: "--coverage-path=./coverage/lcov.info"
28 | - generate_code_coverage_files: 'yes'
29 | - project_location: "$BITRISE_FLUTTER_PROJECT_LOCATION"
30 | - codecov@1:
31 | inputs:
32 | - CODECOV_TOKEN: "$CODECOV_TOKEN"
33 | - flutter-build@0:
34 | inputs:
35 | - ios_additional_params: "--release --no-codesign --flavor production --dart-define=FLAVOR=production
36 | --target lib/main.dart"
37 | - is_debug_mode: 'true'
38 | - ios_output_pattern: |-
39 | *build/ios/iphoneos/*.app
40 | *build/ios/iphoneos/*.ipa
41 | - android_additional_params: "--release --flavor production --dart-define=FLAVOR=production
42 | --target lib/main.dart"
43 | - deploy-to-bitrise-io@1: {}
44 | - cache-push@2: {}
45 | - slack@3:
46 | inputs:
47 | - webhook_url: "$SLACK_WEBHOOK_URL"
48 | pull-request-build:
49 | steps:
50 | - activate-ssh-key@4:
51 | run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
52 | - git-clone@4: {}
53 | - script@1:
54 | title: Do anything with Script step
55 | - flutter-installer@0:
56 | inputs:
57 | - version: beta
58 | - cache-pull@2: {}
59 | - flutter-analyze@0.2:
60 | inputs:
61 | - project_location: "$BITRISE_FLUTTER_PROJECT_LOCATION"
62 | - flutter-test@0:
63 | inputs:
64 | - additional_params: "--coverage-path=./coverage/lcov.info"
65 | - generate_code_coverage_files: 'yes'
66 | - project_location: "$BITRISE_FLUTTER_PROJECT_LOCATION"
67 | - codecov@1:
68 | inputs:
69 | - CODECOV_TOKEN: "$CODECOV_TOKEN"
70 | - flutter-build@0:
71 | inputs:
72 | - ios_additional_params: "--no-codesign --flavor development --dart-define=FLAVOR=development
73 | --target lib/main.dart"
74 | - is_debug_mode: 'true'
75 | - ios_output_pattern: |-
76 | *build/ios/iphoneos/*.app
77 | *build/ios/iphoneos/*.ipa
78 | - android_additional_params: "--flavor development --dart-define=FLAVOR=development
79 | --target lib/main.dart"
80 | - deploy-to-bitrise-io@1: {}
81 | - cache-push@2: {}
82 | - slack@3:
83 | inputs:
84 | - webhook_url: "$SLACK_WEBHOOK_URL"
85 | app:
86 | envs:
87 | - opts:
88 | is_expand: false
89 | BITRISE_FLUTTER_PROJECT_LOCATION: "."
90 | - opts:
91 | is_expand: false
92 | BITRISE_PROJECT_PATH: ios/Runner.xcworkspace
93 | - opts:
94 | is_expand: false
95 | BITRISE_SCHEME: Production
96 | - opts:
97 | is_expand: false
98 | BITRISE_EXPORT_METHOD: production
99 | - opts:
100 | is_expand: false
101 | ANDROID_SDK_VERSION: 29
102 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | # https://docs.codecov.io/docs/commit-status
2 | codecov:
3 | notify:
4 | require_ci_to_pass: yes
5 |
6 | coverage:
7 | status:
8 | project:
9 | default:
10 | # basic
11 | target: 0%
12 | threshold: 0%
13 | base: 0%
14 | # advanced
15 | branches: null
16 | if_no_uploads: error
17 | if_not_found: success
18 | if_ci_failed: error
19 | only_pulls: false
20 | flags: null
21 | paths: null
22 |
23 | ignore:
24 | - "**/*.g.dart"
25 | - "**/*.freezed.dart"
--------------------------------------------------------------------------------
/codemagic.yaml:
--------------------------------------------------------------------------------
1 | # Automatically generated on 2020-08-07 UTC from https://codemagic.io/app/5f2c1b6a8ff73d000f7bc1e1/settings
2 | # Note that this configuration is not an exact match to UI settings. Review and adjust as necessary.
3 |
4 | workflows:
5 | main-merge:
6 | name: Main Workflow
7 | max_build_duration: 60
8 | environment:
9 | vars:
10 | FCI_FLUTTER_SCHEME: Production
11 | ANDROID_SDK_VERSION: 30
12 | CODECOV_TOKEN: Encrypted(Z0FBQUFBQmZMOXV6aEw2a0VyRWE0VTljem1XeG95MVFQRm5YNUhUaU94SE1FcU5pdDRya1ZnM29DR2FQOGpJS1dydm14UkU4eFE4TzdReDZZWlIxU1lEcU13dm8zRHdQd211R3pTNGFIeHJwUXE3N3VxTk1iMndYLWFnSE1JMHA2TndHVkw3MWRmbU0=)
13 | flutter: beta
14 | xcode: latest
15 | cocoapods: default
16 | cache:
17 | cache_paths:
18 | - $FLUTTER_ROOT/.pub-cache
19 | - $FCI_BUILD_DIR/ios/Pods
20 | - $FCI_BUILD_DIR/android/.gradle
21 | triggering:
22 | events:
23 | - push
24 | - pull_request
25 | - tag
26 | branch_patterns:
27 | - pattern: main
28 | include: true
29 | source: true
30 | scripts:
31 | - name: Setup local properties
32 | script: |
33 | # set up local properties
34 | echo "flutter.sdk=$HOME/programs/flutter" > "$FCI_BUILD_DIR/android/local.properties"
35 |
36 | - name: Flutter pub get
37 | script: make dependencies
38 |
39 | - name: Flutte Analysis
40 | script: make analyze
41 |
42 | - name: Flutter Unit test
43 | script: make unit-test
44 |
45 | - name: Codecov upload
46 | script: make codecov
47 |
48 | - name: Build
49 | script: |
50 | #!/bin/sh
51 | set -e # exit on first failed commandset
52 | set -x # print all executed commands to the log
53 | /usr/bin/plutil -replace CFBundleIdentifier -string jp.wasabeef.app ios/Runner/Info.plist
54 | make build-android-prd
55 | make build-ios-prd
56 |
57 | artifacts:
58 | - build/**/outputs/**/*.apk
59 | - build/**/outputs/**/*.aab
60 | - build/**/outputs/**/mapping.txt
61 | - build/ios/ipa/*.ipa
62 | - /tmp/xcodebuild_logs/*.log
63 | - flutter_drive.log
64 |
65 | publishing:
66 | slack:
67 | channel: '#develop'
68 | notify_on_build_start: false
69 | github_releases:
70 | prerelease: false
71 | artifact_patterns:
72 | - 'app-production-release.apk'
73 | - 'Runner.ipa'
--------------------------------------------------------------------------------
/ios/Config/Development.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Flutter/Generated.xcconfig"
2 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release-development.xcconfig"
3 | TRACK_WIDGET_CREATION=
4 |
5 | FLUTTER_FLAVOR=pevelopment
6 | FLUTTER_TARGET=$PROJECT_DIR/../lib/main.dart
7 | PRODUCT_BUNDLE_IDENTIFIER=jp.wasabeef.app.dev
8 | DISPLAY_NAME=FAB-dev
9 |
10 | FIREBASE_DIR=$PROJECT_DIR/$PROJECT_NAME/Resources/Firebase/Development
11 |
12 | // GOOGLE prefix key configs were copied from GoogleService-Info.plist
13 | GOOGLE_REVERSED_CLIENT_ID = com.googleusercontent.apps.339920746703-140i3bhk3lqtpn2p2e7035btcp61p32i
14 |
--------------------------------------------------------------------------------
/ios/Config/Production.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Flutter/Generated.xcconfig"
2 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release-production.xcconfig"
3 | TRACK_WIDGET_CREATION=
4 |
5 | FLUTTER_FLAVOR=production
6 | FLUTTER_TARGET=$PROJECT_DIR/../lib/main.dart
7 | PRODUCT_BUNDLE_IDENTIFIER=jp.wasabeef.app
8 | DISPLAY_NAME=FAB
9 |
10 | FIREBASE_DIR=$PROJECT_DIR/$PROJECT_NAME/Resources/Firebase/Production
11 |
12 | // GOOGLE prefix key configs were copied from GoogleService-Info.plist
13 | GOOGLE_REVERSED_CLIENT_ID = com.googleusercontent.apps.208498828836-139a9k718tbf1ijjmplm9sef21crjqv9
14 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/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-Development' => :debug,
9 | 'Debug-Production' => :debug,
10 | 'Release-Development' => :release,
11 | 'Release-Production' => :release,
12 | }
13 |
14 | def flutter_root
15 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
16 | unless File.exist?(generated_xcode_build_settings_path)
17 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
18 | end
19 |
20 | File.foreach(generated_xcode_build_settings_path) do |line|
21 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
22 | return matches[1].strip if matches
23 | end
24 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
25 | end
26 |
27 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
28 |
29 | flutter_ios_podfile_setup
30 |
31 | target 'Runner' do
32 | use_frameworks!
33 | use_modular_headers!
34 |
35 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
36 | end
37 |
38 | post_install do |installer|
39 | installer.pods_project.targets.each do |target|
40 | flutter_additional_ios_build_settings(target)
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - AppAuth (1.4.0):
3 | - AppAuth/Core (= 1.4.0)
4 | - AppAuth/ExternalUserAgent (= 1.4.0)
5 | - AppAuth/Core (1.4.0)
6 | - AppAuth/ExternalUserAgent (1.4.0)
7 | - Firebase/Auth (6.33.0):
8 | - Firebase/CoreOnly
9 | - FirebaseAuth (~> 6.9.2)
10 | - Firebase/CoreOnly (6.33.0):
11 | - FirebaseCore (= 6.10.3)
12 | - Firebase/Crashlytics (6.33.0):
13 | - Firebase/CoreOnly
14 | - FirebaseCrashlytics (~> 4.6.1)
15 | - Firebase/Performance (6.33.0):
16 | - Firebase/CoreOnly
17 | - FirebasePerformance (~> 3.3.0)
18 | - firebase_auth (0.18.4-1):
19 | - Firebase/Auth (~> 6.33.0)
20 | - Firebase/CoreOnly (~> 6.33.0)
21 | - firebase_core
22 | - Flutter
23 | - firebase_core (0.5.3):
24 | - Firebase/CoreOnly (~> 6.33.0)
25 | - Flutter
26 | - firebase_crashlytics (0.2.4):
27 | - Firebase/CoreOnly (~> 6.33.0)
28 | - Firebase/Crashlytics (~> 6.33.0)
29 | - firebase_core
30 | - firebase_performance (0.4.3):
31 | - Firebase/CoreOnly (~> 6.33.0)
32 | - Firebase/Performance (~> 6.33.0)
33 | - firebase_core
34 | - Flutter
35 | - FirebaseABTesting (4.2.0):
36 | - FirebaseCore (~> 6.10)
37 | - FirebaseAuth (6.9.2):
38 | - FirebaseCore (~> 6.10)
39 | - GoogleUtilities/AppDelegateSwizzler (~> 6.7)
40 | - GoogleUtilities/Environment (~> 6.7)
41 | - GTMSessionFetcher/Core (~> 1.1)
42 | - FirebaseCore (6.10.3):
43 | - FirebaseCoreDiagnostics (~> 1.6)
44 | - GoogleUtilities/Environment (~> 6.7)
45 | - GoogleUtilities/Logger (~> 6.7)
46 | - FirebaseCoreDiagnostics (1.7.0):
47 | - GoogleDataTransport (~> 7.4)
48 | - GoogleUtilities/Environment (~> 6.7)
49 | - GoogleUtilities/Logger (~> 6.7)
50 | - nanopb (~> 1.30906.0)
51 | - FirebaseCrashlytics (4.6.2):
52 | - FirebaseCore (~> 6.10)
53 | - FirebaseInstallations (~> 1.6)
54 | - GoogleDataTransport (~> 7.2)
55 | - nanopb (~> 1.30906.0)
56 | - PromisesObjC (~> 1.2)
57 | - FirebaseInstallations (1.7.0):
58 | - FirebaseCore (~> 6.10)
59 | - GoogleUtilities/Environment (~> 6.7)
60 | - GoogleUtilities/UserDefaults (~> 6.7)
61 | - PromisesObjC (~> 1.2)
62 | - FirebasePerformance (3.3.2):
63 | - FirebaseCore (~> 6.9)
64 | - FirebaseInstallations (~> 1.5)
65 | - FirebaseRemoteConfig (~> 4.7)
66 | - GoogleDataTransport (~> 7.0)
67 | - GoogleToolboxForMac/Logger (~> 2.1)
68 | - "GoogleToolboxForMac/NSData+zlib (~> 2.1)"
69 | - GoogleUtilities/Environment (~> 6.2)
70 | - GoogleUtilities/ISASwizzler (~> 6.2)
71 | - GoogleUtilities/MethodSwizzler (~> 6.2)
72 | - GTMSessionFetcher/Core (~> 1.1)
73 | - Protobuf (~> 3.12)
74 | - FirebaseRemoteConfig (4.9.1):
75 | - FirebaseABTesting (~> 4.2)
76 | - FirebaseCore (~> 6.10)
77 | - FirebaseInstallations (~> 1.6)
78 | - GoogleUtilities/Environment (~> 6.7)
79 | - "GoogleUtilities/NSData+zlib (~> 6.7)"
80 | - Flutter (1.0.0)
81 | - FMDB (2.7.5):
82 | - FMDB/standard (= 2.7.5)
83 | - FMDB/standard (2.7.5)
84 | - google_sign_in (0.0.1):
85 | - Flutter
86 | - GoogleSignIn (~> 5.0)
87 | - GoogleDataTransport (7.5.1):
88 | - nanopb (~> 1.30906.0)
89 | - GoogleSignIn (5.0.2):
90 | - AppAuth (~> 1.2)
91 | - GTMAppAuth (~> 1.0)
92 | - GTMSessionFetcher/Core (~> 1.1)
93 | - GoogleToolboxForMac/Defines (2.3.0)
94 | - GoogleToolboxForMac/Logger (2.3.0):
95 | - GoogleToolboxForMac/Defines (= 2.3.0)
96 | - "GoogleToolboxForMac/NSData+zlib (2.3.0)":
97 | - GoogleToolboxForMac/Defines (= 2.3.0)
98 | - GoogleUtilities/AppDelegateSwizzler (6.7.2):
99 | - GoogleUtilities/Environment
100 | - GoogleUtilities/Logger
101 | - GoogleUtilities/Network
102 | - GoogleUtilities/Environment (6.7.2):
103 | - PromisesObjC (~> 1.2)
104 | - GoogleUtilities/ISASwizzler (6.7.2)
105 | - GoogleUtilities/Logger (6.7.2):
106 | - GoogleUtilities/Environment
107 | - GoogleUtilities/MethodSwizzler (6.7.2):
108 | - GoogleUtilities/Logger
109 | - GoogleUtilities/Network (6.7.2):
110 | - GoogleUtilities/Logger
111 | - "GoogleUtilities/NSData+zlib"
112 | - GoogleUtilities/Reachability
113 | - "GoogleUtilities/NSData+zlib (6.7.2)"
114 | - GoogleUtilities/Reachability (6.7.2):
115 | - GoogleUtilities/Logger
116 | - GoogleUtilities/UserDefaults (6.7.2):
117 | - GoogleUtilities/Logger
118 | - GTMAppAuth (1.1.0):
119 | - AppAuth/Core (~> 1.4)
120 | - GTMSessionFetcher (~> 1.4)
121 | - GTMSessionFetcher (1.5.0):
122 | - GTMSessionFetcher/Full (= 1.5.0)
123 | - GTMSessionFetcher/Core (1.5.0)
124 | - GTMSessionFetcher/Full (1.5.0):
125 | - GTMSessionFetcher/Core (= 1.5.0)
126 | - nanopb (1.30906.0):
127 | - nanopb/decode (= 1.30906.0)
128 | - nanopb/encode (= 1.30906.0)
129 | - nanopb/decode (1.30906.0)
130 | - nanopb/encode (1.30906.0)
131 | - path_provider (0.0.1):
132 | - Flutter
133 | - PromisesObjC (1.2.11)
134 | - Protobuf (3.13.0)
135 | - shared_preferences (0.0.1):
136 | - Flutter
137 | - sqflite (0.0.2):
138 | - Flutter
139 | - FMDB (>= 2.7.5)
140 | - ua_client_hints (1.0.3):
141 | - Flutter
142 |
143 | DEPENDENCIES:
144 | - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`)
145 | - firebase_core (from `.symlinks/plugins/firebase_core/ios`)
146 | - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
147 | - firebase_performance (from `.symlinks/plugins/firebase_performance/ios`)
148 | - Flutter (from `Flutter`)
149 | - google_sign_in (from `.symlinks/plugins/google_sign_in/ios`)
150 | - path_provider (from `.symlinks/plugins/path_provider/ios`)
151 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
152 | - sqflite (from `.symlinks/plugins/sqflite/ios`)
153 | - ua_client_hints (from `.symlinks/plugins/ua_client_hints/ios`)
154 |
155 | SPEC REPOS:
156 | trunk:
157 | - AppAuth
158 | - Firebase
159 | - FirebaseABTesting
160 | - FirebaseAuth
161 | - FirebaseCore
162 | - FirebaseCoreDiagnostics
163 | - FirebaseCrashlytics
164 | - FirebaseInstallations
165 | - FirebasePerformance
166 | - FirebaseRemoteConfig
167 | - FMDB
168 | - GoogleDataTransport
169 | - GoogleSignIn
170 | - GoogleToolboxForMac
171 | - GoogleUtilities
172 | - GTMAppAuth
173 | - GTMSessionFetcher
174 | - nanopb
175 | - PromisesObjC
176 | - Protobuf
177 |
178 | EXTERNAL SOURCES:
179 | firebase_auth:
180 | :path: ".symlinks/plugins/firebase_auth/ios"
181 | firebase_core:
182 | :path: ".symlinks/plugins/firebase_core/ios"
183 | firebase_crashlytics:
184 | :path: ".symlinks/plugins/firebase_crashlytics/ios"
185 | firebase_performance:
186 | :path: ".symlinks/plugins/firebase_performance/ios"
187 | Flutter:
188 | :path: Flutter
189 | google_sign_in:
190 | :path: ".symlinks/plugins/google_sign_in/ios"
191 | path_provider:
192 | :path: ".symlinks/plugins/path_provider/ios"
193 | shared_preferences:
194 | :path: ".symlinks/plugins/shared_preferences/ios"
195 | sqflite:
196 | :path: ".symlinks/plugins/sqflite/ios"
197 | ua_client_hints:
198 | :path: ".symlinks/plugins/ua_client_hints/ios"
199 |
200 | SPEC CHECKSUMS:
201 | AppAuth: 31bcec809a638d7bd2f86ea8a52bd45f6e81e7c7
202 | Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
203 | firebase_auth: d5159db3873478d1ac839af7b10d2f831516136a
204 | firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659
205 | firebase_crashlytics: 7b37f8e79a82175606a3447852c9efa8e10034b3
206 | firebase_performance: 05238feeae91e4ce494ec8f772e7bf05b15ec178
207 | FirebaseABTesting: 8a9d8df3acc2b43f4a22014ddf9f601bca6af699
208 | FirebaseAuth: c92d49ada7948d1a23466e3db17bc4c2039dddc3
209 | FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
210 | FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
211 | FirebaseCrashlytics: 1a747c9cc084a24dc6d9511c991db1cd078154eb
212 | FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2
213 | FirebasePerformance: 34de2b03ddfddbca26a716468a50877fd065fbe5
214 | FirebaseRemoteConfig: 35a729305f254fb15a2e541d4b36f3a379da7fdc
215 | Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
216 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
217 | google_sign_in: 6bd214b9c154f881422f5fe27b66aaa7bbd580cc
218 | GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833
219 | GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
220 | GoogleToolboxForMac: 1350d40e86a76f7863928d63bcb0b89c84c521c5
221 | GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
222 | GTMAppAuth: 197a8dabfea5d665224aa00d17f164fc2248dab9
223 | GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
224 | nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
225 | path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
226 | PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f
227 | Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748
228 | shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
229 | sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
230 | ua_client_hints: 21afb74063bbc16dd66a09d7a21fba69075c250a
231 |
232 | PODFILE CHECKSUM: 118f96eff828f227e97a23ba2f91700fae9664fb
233 |
234 | COCOAPODS: 1.10.0
235 |
--------------------------------------------------------------------------------
/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/Development.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Production.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 | PreviewsEnabled
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/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/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huskyjp/flutter-mvvp-riverpod-architecture/1c264e2ae5614805416b5da8736d97a6f8a96733/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | $(DISPLAY_NAME)
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | app
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleURLTypes
24 |
25 |
26 | CFBundleIdentifier
27 |
28 | CFBundleTypeRole
29 | Editor
30 | CFBundleURLName
31 | SNS Sign In
32 | CFBundleURLSchemes
33 |
34 | $(GOOGLE_REVERSED_CLIENT_ID)
35 |
36 |
37 |
38 | CFBundleVersion
39 | $(FLUTTER_BUILD_NUMBER)
40 | LSRequiresIPhoneOS
41 |
42 | UILaunchStoryboardName
43 | LaunchScreen
44 | UIMainStoryboardFile
45 | Main
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 | UIViewControllerBasedStatusBarAppearance
60 |
61 | io.flutter.embedded_views_preview
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/ios/Runner/Resources/Firebase/Development/GoogleService-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CLIENT_ID
6 | 339920746703-140i3bhk3lqtpn2p2e7035btcp61p32i.apps.googleusercontent.com
7 | REVERSED_CLIENT_ID
8 | com.googleusercontent.apps.339920746703-140i3bhk3lqtpn2p2e7035btcp61p32i
9 | ANDROID_CLIENT_ID
10 | 339920746703-1omo33mfc8f7cfjm8pa8qutqpu2q3h7c.apps.googleusercontent.com
11 | API_KEY
12 | AIzaSyCxPP2BfUCFmWkYSNswVtT3PQrVXnAQJkg
13 | GCM_SENDER_ID
14 | 339920746703
15 | PLIST_VERSION
16 | 1
17 | BUNDLE_ID
18 | jp.wasabeef.app.dev
19 | PROJECT_ID
20 | flutter-arch-blueprints-dev
21 | STORAGE_BUCKET
22 | flutter-arch-blueprints-dev.appspot.com
23 | IS_ADS_ENABLED
24 |
25 | IS_ANALYTICS_ENABLED
26 |
27 | IS_APPINVITE_ENABLED
28 |
29 | IS_GCM_ENABLED
30 |
31 | IS_SIGNIN_ENABLED
32 |
33 | GOOGLE_APP_ID
34 | 1:339920746703:ios:96090bb3427da435ee9fba
35 | DATABASE_URL
36 | https://flutter-arch-blueprints-dev.firebaseio.com
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Resources/Firebase/Production/GoogleService-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CLIENT_ID
6 | 208498828836-139a9k718tbf1ijjmplm9sef21crjqv9.apps.googleusercontent.com
7 | REVERSED_CLIENT_ID
8 | com.googleusercontent.apps.208498828836-139a9k718tbf1ijjmplm9sef21crjqv9
9 | ANDROID_CLIENT_ID
10 | 208498828836-3323hr2v1b84i3s8sv4921462l1vtc1i.apps.googleusercontent.com
11 | API_KEY
12 | AIzaSyAjP8sr4gOdweOwfbrXKY0ya_hqP7GS2nY
13 | GCM_SENDER_ID
14 | 208498828836
15 | PLIST_VERSION
16 | 1
17 | BUNDLE_ID
18 | jp.wasabeef.app
19 | PROJECT_ID
20 | flutter-arc-blueprints
21 | STORAGE_BUCKET
22 | flutter-arc-blueprints.appspot.com
23 | IS_ADS_ENABLED
24 |
25 | IS_ANALYTICS_ENABLED
26 |
27 | IS_APPINVITE_ENABLED
28 |
29 | IS_GCM_ENABLED
30 |
31 | IS_SIGNIN_ENABLED
32 |
33 | GOOGLE_APP_ID
34 | 1:208498828836:ios:f3fcdda35b7c7aa16b5ab1
35 | DATABASE_URL
36 | https://flutter-arc-blueprints.firebaseio.com
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/ios/Runner/ja.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ios/Runner/ja.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ios/Scripts/copy_google_service.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | BASE_PATH=$PROJECT_DIR/$PROJECT_NAME
4 |
5 | echo execute copy GoogleService-Info.plist
6 | FIREBASE_INFO_PLIST="GoogleService-Info.plist"
7 | FIREBASE_INFO_PLIST_DST=$BASE_PATH/$FIREBASE_INFO_PLIST
8 | FIREBASE_INFO_PLIST_SRC=$FIREBASE_DIR/$FIREBASE_INFO_PLIST
9 |
10 | echo $FIREBASE_INFO_PLIST_SRC
11 | cp -Rf $FIREBASE_INFO_PLIST_SRC $FIREBASE_INFO_PLIST_DST
12 |
--------------------------------------------------------------------------------
/l10n.yaml:
--------------------------------------------------------------------------------
1 | arb-dir: lib/l10n
2 | template-arb-file: intl_messages_en.arb
3 | output-localization-file: l10n.dart
4 | output-class: L10n
5 |
--------------------------------------------------------------------------------
/lib/app.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_gen/gen_l10n/l10n.dart';
3 | import 'package:flutter_hooks/flutter_hooks.dart';
4 | import 'package:get/get.dart';
5 | import 'package:hooks_riverpod/hooks_riverpod.dart';
6 |
7 | import 'constants.dart';
8 | import 'ui/app_theme.dart';
9 | import 'ui/detail/detail_page.dart';
10 | import 'ui/home/home_page.dart';
11 | import 'ui/signIn/sign_in_page.dart';
12 |
13 | class App extends HookWidget {
14 | @override
15 | Widget build(BuildContext context) {
16 | final appTheme = context.read(appThemeNotifierProvider);
17 | final setting =
18 | useProvider(appThemeNotifierProvider.select((value) => value.setting));
19 | useFuture(useMemoized(appTheme.themeMode, [setting]));
20 | return GetMaterialApp(
21 | title: 'Flutter Architecture Blueprints',
22 | theme: lightTheme,
23 | darkTheme: darkTheme,
24 | themeMode: setting ?? ThemeMode.light,
25 | home: HomePage(),
26 | localizationsDelegates: L10n.localizationsDelegates,
27 | supportedLocales: L10n.supportedLocales,
28 | routes: {
29 | Constants.pageHome: (context) => HomePage(),
30 | Constants.pageSignIn: (context) => SignInPage(),
31 | Constants.pageDetail: (context) => DetailPage(),
32 | },
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/constants.dart:
--------------------------------------------------------------------------------
1 | import 'package:enum_to_string/enum_to_string.dart';
2 | import 'package:flutter/foundation.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | enum Flavor { development, production }
6 |
7 | @immutable
8 | class Constants {
9 | const Constants({
10 | @required this.endpoint,
11 | @required this.apiKey,
12 | });
13 |
14 | factory Constants.of() {
15 | if (_instance != null) {
16 | return _instance;
17 | }
18 |
19 | final flavor = EnumToString.fromString(
20 | Flavor.values,
21 | const String.fromEnvironment('FLAVOR'),
22 | );
23 |
24 | switch (flavor) {
25 | case Flavor.development:
26 | _instance = Constants._dev();
27 | break;
28 | case Flavor.production:
29 | default:
30 | _instance = Constants._prd();
31 | }
32 | return _instance;
33 | }
34 |
35 | factory Constants._dev() {
36 | return const Constants(
37 | endpoint: 'https://newsapi.org',
38 | apiKey: '98c8df982b8b4da8b86cd70e851fc521',
39 | );
40 | }
41 |
42 | factory Constants._prd() {
43 | return const Constants(
44 | endpoint: 'https://newsapi.org',
45 | apiKey: '4bc454db94464956aea4cbb01f4bf9f4',
46 | );
47 | }
48 |
49 | // Routing name
50 | static const String pageHome = '/home';
51 | static const String pageSignIn = '/signIn';
52 | static const String pageDetail = '/detail';
53 |
54 | static Constants _instance;
55 |
56 | final String endpoint;
57 | final String apiKey;
58 | }
59 |
--------------------------------------------------------------------------------
/lib/data/app_error.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:dio/dio.dart';
4 | import 'package:flutter/foundation.dart';
5 |
6 | enum AppErrorType {
7 | network,
8 | badRequest,
9 | unauthorized,
10 | cancel,
11 | timeout,
12 | server,
13 | unknown,
14 | }
15 |
16 | class AppError {
17 | String message;
18 | AppErrorType type;
19 |
20 | AppError(Exception error) {
21 | if (error is DioError) {
22 | debugPrint('AppError(DioError): '
23 | 'type is ${error.type}, message is ${error.message}');
24 | message = error.message;
25 | switch (error.type) {
26 | case DioErrorType.DEFAULT:
27 | if (error.error is SocketException) {
28 | // SocketException: Failed host lookup: '***'
29 | // (OS Error: No address associated with hostname, errno = 7)
30 | type = AppErrorType.network;
31 | } else {
32 | type = AppErrorType.unknown;
33 | }
34 | break;
35 | case DioErrorType.CONNECT_TIMEOUT:
36 | case DioErrorType.RECEIVE_TIMEOUT:
37 | type = AppErrorType.timeout;
38 | break;
39 | case DioErrorType.SEND_TIMEOUT:
40 | type = AppErrorType.network;
41 | break;
42 | case DioErrorType.RESPONSE:
43 | // TODO(api): need define more http status;
44 | switch (error.response.statusCode) {
45 | case HttpStatus.badRequest: // 400
46 | type = AppErrorType.badRequest;
47 | break;
48 | case HttpStatus.unauthorized: // 401
49 | type = AppErrorType.unauthorized;
50 | break;
51 | case HttpStatus.internalServerError: // 500
52 | case HttpStatus.badGateway: // 502
53 | case HttpStatus.serviceUnavailable: // 503
54 | case HttpStatus.gatewayTimeout: // 504
55 | type = AppErrorType.server;
56 | break;
57 | default:
58 | type = AppErrorType.unknown;
59 | break;
60 | }
61 | break;
62 | case DioErrorType.CANCEL:
63 | type = AppErrorType.cancel;
64 | break;
65 | default:
66 | type = AppErrorType.unknown;
67 | }
68 | } else {
69 | debugPrint('AppError(UnKnown): $error');
70 | type = AppErrorType.unknown;
71 | message = 'AppError: $error';
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/data/local/app_shared_preferences.dart:
--------------------------------------------------------------------------------
1 | import 'package:shared_preferences/shared_preferences.dart';
2 |
3 | class AppSharedPreferences {
4 | SharedPreferences _prefs;
5 |
6 | Future getInstance() async {
7 | _prefs ??= await SharedPreferences.getInstance();
8 | return _prefs;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/data/local/theme_data_source.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | abstract class ThemeDataSource {
4 | Future loadThemeMode();
5 |
6 | Future saveThemeMode(ThemeMode theme);
7 | }
8 |
--------------------------------------------------------------------------------
/lib/data/local/theme_data_source_impl.dart:
--------------------------------------------------------------------------------
1 | import 'package:enum_to_string/enum_to_string.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | import 'app_shared_preferences.dart';
5 | import 'theme_data_source.dart';
6 |
7 | class ThemeDataSourceImpl extends ThemeDataSource {
8 | ThemeDataSourceImpl(this._prefs);
9 |
10 | static const String keyThemeMode = 'theme_mode';
11 |
12 | final AppSharedPreferences _prefs;
13 |
14 | @override
15 | Future loadThemeMode() async {
16 | final prefs = await _prefs.getInstance();
17 | return EnumToString.fromString(
18 | ThemeMode.values, prefs.getString(keyThemeMode));
19 | }
20 |
21 | @override
22 | Future saveThemeMode(ThemeMode theme) async {
23 | final prefs = await _prefs.getInstance();
24 | return prefs.setString(keyThemeMode, EnumToString.convertToString(theme));
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/data/model/article.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | import 'source.dart';
4 |
5 | part 'article.freezed.dart';
6 |
7 | part 'article.g.dart';
8 |
9 | @freezed
10 | abstract class Article with _$Article {
11 | factory Article({
12 | Source source,
13 | String author,
14 | String title,
15 | String description,
16 | String url,
17 | String urlToImage,
18 | DateTime publishedAt,
19 | String content,
20 | }) = _Article;
21 |
22 | factory Article.fromJson(Map json) =>
23 | _$ArticleFromJson(json);
24 | }
25 |
--------------------------------------------------------------------------------
/lib/data/model/article.freezed.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // ignore_for_file: deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies
3 |
4 | part of 'article.dart';
5 |
6 | // **************************************************************************
7 | // FreezedGenerator
8 | // **************************************************************************
9 |
10 | T _$identity(T value) => value;
11 | Article _$ArticleFromJson(Map json) {
12 | return _Article.fromJson(json);
13 | }
14 |
15 | /// @nodoc
16 | class _$ArticleTearOff {
17 | const _$ArticleTearOff();
18 |
19 | // ignore: unused_element
20 | _Article call(
21 | {Source source,
22 | String author,
23 | String title,
24 | String description,
25 | String url,
26 | String urlToImage,
27 | DateTime publishedAt,
28 | String content}) {
29 | return _Article(
30 | source: source,
31 | author: author,
32 | title: title,
33 | description: description,
34 | url: url,
35 | urlToImage: urlToImage,
36 | publishedAt: publishedAt,
37 | content: content,
38 | );
39 | }
40 |
41 | // ignore: unused_element
42 | Article fromJson(Map json) {
43 | return Article.fromJson(json);
44 | }
45 | }
46 |
47 | /// @nodoc
48 | // ignore: unused_element
49 | const $Article = _$ArticleTearOff();
50 |
51 | /// @nodoc
52 | mixin _$Article {
53 | Source get source;
54 | String get author;
55 | String get title;
56 | String get description;
57 | String get url;
58 | String get urlToImage;
59 | DateTime get publishedAt;
60 | String get content;
61 |
62 | Map toJson();
63 | $ArticleCopyWith get copyWith;
64 | }
65 |
66 | /// @nodoc
67 | abstract class $ArticleCopyWith<$Res> {
68 | factory $ArticleCopyWith(Article value, $Res Function(Article) then) =
69 | _$ArticleCopyWithImpl<$Res>;
70 | $Res call(
71 | {Source source,
72 | String author,
73 | String title,
74 | String description,
75 | String url,
76 | String urlToImage,
77 | DateTime publishedAt,
78 | String content});
79 |
80 | $SourceCopyWith<$Res> get source;
81 | }
82 |
83 | /// @nodoc
84 | class _$ArticleCopyWithImpl<$Res> implements $ArticleCopyWith<$Res> {
85 | _$ArticleCopyWithImpl(this._value, this._then);
86 |
87 | final Article _value;
88 | // ignore: unused_field
89 | final $Res Function(Article) _then;
90 |
91 | @override
92 | $Res call({
93 | Object source = freezed,
94 | Object author = freezed,
95 | Object title = freezed,
96 | Object description = freezed,
97 | Object url = freezed,
98 | Object urlToImage = freezed,
99 | Object publishedAt = freezed,
100 | Object content = freezed,
101 | }) {
102 | return _then(_value.copyWith(
103 | source: source == freezed ? _value.source : source as Source,
104 | author: author == freezed ? _value.author : author as String,
105 | title: title == freezed ? _value.title : title as String,
106 | description:
107 | description == freezed ? _value.description : description as String,
108 | url: url == freezed ? _value.url : url as String,
109 | urlToImage:
110 | urlToImage == freezed ? _value.urlToImage : urlToImage as String,
111 | publishedAt:
112 | publishedAt == freezed ? _value.publishedAt : publishedAt as DateTime,
113 | content: content == freezed ? _value.content : content as String,
114 | ));
115 | }
116 |
117 | @override
118 | $SourceCopyWith<$Res> get source {
119 | if (_value.source == null) {
120 | return null;
121 | }
122 | return $SourceCopyWith<$Res>(_value.source, (value) {
123 | return _then(_value.copyWith(source: value));
124 | });
125 | }
126 | }
127 |
128 | /// @nodoc
129 | abstract class _$ArticleCopyWith<$Res> implements $ArticleCopyWith<$Res> {
130 | factory _$ArticleCopyWith(_Article value, $Res Function(_Article) then) =
131 | __$ArticleCopyWithImpl<$Res>;
132 | @override
133 | $Res call(
134 | {Source source,
135 | String author,
136 | String title,
137 | String description,
138 | String url,
139 | String urlToImage,
140 | DateTime publishedAt,
141 | String content});
142 |
143 | @override
144 | $SourceCopyWith<$Res> get source;
145 | }
146 |
147 | /// @nodoc
148 | class __$ArticleCopyWithImpl<$Res> extends _$ArticleCopyWithImpl<$Res>
149 | implements _$ArticleCopyWith<$Res> {
150 | __$ArticleCopyWithImpl(_Article _value, $Res Function(_Article) _then)
151 | : super(_value, (v) => _then(v as _Article));
152 |
153 | @override
154 | _Article get _value => super._value as _Article;
155 |
156 | @override
157 | $Res call({
158 | Object source = freezed,
159 | Object author = freezed,
160 | Object title = freezed,
161 | Object description = freezed,
162 | Object url = freezed,
163 | Object urlToImage = freezed,
164 | Object publishedAt = freezed,
165 | Object content = freezed,
166 | }) {
167 | return _then(_Article(
168 | source: source == freezed ? _value.source : source as Source,
169 | author: author == freezed ? _value.author : author as String,
170 | title: title == freezed ? _value.title : title as String,
171 | description:
172 | description == freezed ? _value.description : description as String,
173 | url: url == freezed ? _value.url : url as String,
174 | urlToImage:
175 | urlToImage == freezed ? _value.urlToImage : urlToImage as String,
176 | publishedAt:
177 | publishedAt == freezed ? _value.publishedAt : publishedAt as DateTime,
178 | content: content == freezed ? _value.content : content as String,
179 | ));
180 | }
181 | }
182 |
183 | @JsonSerializable()
184 |
185 | /// @nodoc
186 | class _$_Article implements _Article {
187 | _$_Article(
188 | {this.source,
189 | this.author,
190 | this.title,
191 | this.description,
192 | this.url,
193 | this.urlToImage,
194 | this.publishedAt,
195 | this.content});
196 |
197 | factory _$_Article.fromJson(Map json) =>
198 | _$_$_ArticleFromJson(json);
199 |
200 | @override
201 | final Source source;
202 | @override
203 | final String author;
204 | @override
205 | final String title;
206 | @override
207 | final String description;
208 | @override
209 | final String url;
210 | @override
211 | final String urlToImage;
212 | @override
213 | final DateTime publishedAt;
214 | @override
215 | final String content;
216 |
217 | @override
218 | String toString() {
219 | return 'Article(source: $source, author: $author, title: $title, description: $description, url: $url, urlToImage: $urlToImage, publishedAt: $publishedAt, content: $content)';
220 | }
221 |
222 | @override
223 | bool operator ==(dynamic other) {
224 | return identical(this, other) ||
225 | (other is _Article &&
226 | (identical(other.source, source) ||
227 | const DeepCollectionEquality().equals(other.source, source)) &&
228 | (identical(other.author, author) ||
229 | const DeepCollectionEquality().equals(other.author, author)) &&
230 | (identical(other.title, title) ||
231 | const DeepCollectionEquality().equals(other.title, title)) &&
232 | (identical(other.description, description) ||
233 | const DeepCollectionEquality()
234 | .equals(other.description, description)) &&
235 | (identical(other.url, url) ||
236 | const DeepCollectionEquality().equals(other.url, url)) &&
237 | (identical(other.urlToImage, urlToImage) ||
238 | const DeepCollectionEquality()
239 | .equals(other.urlToImage, urlToImage)) &&
240 | (identical(other.publishedAt, publishedAt) ||
241 | const DeepCollectionEquality()
242 | .equals(other.publishedAt, publishedAt)) &&
243 | (identical(other.content, content) ||
244 | const DeepCollectionEquality().equals(other.content, content)));
245 | }
246 |
247 | @override
248 | int get hashCode =>
249 | runtimeType.hashCode ^
250 | const DeepCollectionEquality().hash(source) ^
251 | const DeepCollectionEquality().hash(author) ^
252 | const DeepCollectionEquality().hash(title) ^
253 | const DeepCollectionEquality().hash(description) ^
254 | const DeepCollectionEquality().hash(url) ^
255 | const DeepCollectionEquality().hash(urlToImage) ^
256 | const DeepCollectionEquality().hash(publishedAt) ^
257 | const DeepCollectionEquality().hash(content);
258 |
259 | @override
260 | _$ArticleCopyWith<_Article> get copyWith =>
261 | __$ArticleCopyWithImpl<_Article>(this, _$identity);
262 |
263 | @override
264 | Map toJson() {
265 | return _$_$_ArticleToJson(this);
266 | }
267 | }
268 |
269 | abstract class _Article implements Article {
270 | factory _Article(
271 | {Source source,
272 | String author,
273 | String title,
274 | String description,
275 | String url,
276 | String urlToImage,
277 | DateTime publishedAt,
278 | String content}) = _$_Article;
279 |
280 | factory _Article.fromJson(Map json) = _$_Article.fromJson;
281 |
282 | @override
283 | Source get source;
284 | @override
285 | String get author;
286 | @override
287 | String get title;
288 | @override
289 | String get description;
290 | @override
291 | String get url;
292 | @override
293 | String get urlToImage;
294 | @override
295 | DateTime get publishedAt;
296 | @override
297 | String get content;
298 | @override
299 | _$ArticleCopyWith<_Article> get copyWith;
300 | }
301 |
--------------------------------------------------------------------------------
/lib/data/model/article.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'article.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | _$_Article _$_$_ArticleFromJson(Map json) {
10 | return _$_Article(
11 | source: json['source'] == null
12 | ? null
13 | : Source.fromJson(json['source'] as Map),
14 | author: json['author'] as String,
15 | title: json['title'] as String,
16 | description: json['description'] as String,
17 | url: json['url'] as String,
18 | urlToImage: json['urlToImage'] as String,
19 | publishedAt: json['publishedAt'] == null
20 | ? null
21 | : DateTime.parse(json['publishedAt'] as String),
22 | content: json['content'] as String,
23 | );
24 | }
25 |
26 | Map _$_$_ArticleToJson(_$_Article instance) =>
27 | {
28 | 'source': instance.source,
29 | 'author': instance.author,
30 | 'title': instance.title,
31 | 'description': instance.description,
32 | 'url': instance.url,
33 | 'urlToImage': instance.urlToImage,
34 | 'publishedAt': instance.publishedAt?.toIso8601String(),
35 | 'content': instance.content,
36 | };
37 |
--------------------------------------------------------------------------------
/lib/data/model/news.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | import 'article.dart';
4 |
5 | part 'news.freezed.dart';
6 |
7 | part 'news.g.dart';
8 |
9 | @freezed
10 | abstract class News with _$News {
11 | factory News({
12 | @required String status,
13 | @required int totalResults,
14 | List articles,
15 | }) = _News;
16 |
17 | factory News.fromJson(Map json) => _$NewsFromJson(json);
18 | }
19 |
--------------------------------------------------------------------------------
/lib/data/model/news.freezed.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // ignore_for_file: deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies
3 |
4 | part of 'news.dart';
5 |
6 | // **************************************************************************
7 | // FreezedGenerator
8 | // **************************************************************************
9 |
10 | T _$identity(T value) => value;
11 | News _$NewsFromJson(Map json) {
12 | return _News.fromJson(json);
13 | }
14 |
15 | /// @nodoc
16 | class _$NewsTearOff {
17 | const _$NewsTearOff();
18 |
19 | // ignore: unused_element
20 | _News call(
21 | {@required String status,
22 | @required int totalResults,
23 | List articles}) {
24 | return _News(
25 | status: status,
26 | totalResults: totalResults,
27 | articles: articles,
28 | );
29 | }
30 |
31 | // ignore: unused_element
32 | News fromJson(Map json) {
33 | return News.fromJson(json);
34 | }
35 | }
36 |
37 | /// @nodoc
38 | // ignore: unused_element
39 | const $News = _$NewsTearOff();
40 |
41 | /// @nodoc
42 | mixin _$News {
43 | String get status;
44 | int get totalResults;
45 | List get articles;
46 |
47 | Map toJson();
48 | $NewsCopyWith get copyWith;
49 | }
50 |
51 | /// @nodoc
52 | abstract class $NewsCopyWith<$Res> {
53 | factory $NewsCopyWith(News value, $Res Function(News) then) =
54 | _$NewsCopyWithImpl<$Res>;
55 | $Res call({String status, int totalResults, List articles});
56 | }
57 |
58 | /// @nodoc
59 | class _$NewsCopyWithImpl<$Res> implements $NewsCopyWith<$Res> {
60 | _$NewsCopyWithImpl(this._value, this._then);
61 |
62 | final News _value;
63 | // ignore: unused_field
64 | final $Res Function(News) _then;
65 |
66 | @override
67 | $Res call({
68 | Object status = freezed,
69 | Object totalResults = freezed,
70 | Object articles = freezed,
71 | }) {
72 | return _then(_value.copyWith(
73 | status: status == freezed ? _value.status : status as String,
74 | totalResults:
75 | totalResults == freezed ? _value.totalResults : totalResults as int,
76 | articles:
77 | articles == freezed ? _value.articles : articles as List,
78 | ));
79 | }
80 | }
81 |
82 | /// @nodoc
83 | abstract class _$NewsCopyWith<$Res> implements $NewsCopyWith<$Res> {
84 | factory _$NewsCopyWith(_News value, $Res Function(_News) then) =
85 | __$NewsCopyWithImpl<$Res>;
86 | @override
87 | $Res call({String status, int totalResults, List articles});
88 | }
89 |
90 | /// @nodoc
91 | class __$NewsCopyWithImpl<$Res> extends _$NewsCopyWithImpl<$Res>
92 | implements _$NewsCopyWith<$Res> {
93 | __$NewsCopyWithImpl(_News _value, $Res Function(_News) _then)
94 | : super(_value, (v) => _then(v as _News));
95 |
96 | @override
97 | _News get _value => super._value as _News;
98 |
99 | @override
100 | $Res call({
101 | Object status = freezed,
102 | Object totalResults = freezed,
103 | Object articles = freezed,
104 | }) {
105 | return _then(_News(
106 | status: status == freezed ? _value.status : status as String,
107 | totalResults:
108 | totalResults == freezed ? _value.totalResults : totalResults as int,
109 | articles:
110 | articles == freezed ? _value.articles : articles as List,
111 | ));
112 | }
113 | }
114 |
115 | @JsonSerializable()
116 |
117 | /// @nodoc
118 | class _$_News implements _News {
119 | _$_News({@required this.status, @required this.totalResults, this.articles})
120 | : assert(status != null),
121 | assert(totalResults != null);
122 |
123 | factory _$_News.fromJson(Map json) =>
124 | _$_$_NewsFromJson(json);
125 |
126 | @override
127 | final String status;
128 | @override
129 | final int totalResults;
130 | @override
131 | final List articles;
132 |
133 | @override
134 | String toString() {
135 | return 'News(status: $status, totalResults: $totalResults, articles: $articles)';
136 | }
137 |
138 | @override
139 | bool operator ==(dynamic other) {
140 | return identical(this, other) ||
141 | (other is _News &&
142 | (identical(other.status, status) ||
143 | const DeepCollectionEquality().equals(other.status, status)) &&
144 | (identical(other.totalResults, totalResults) ||
145 | const DeepCollectionEquality()
146 | .equals(other.totalResults, totalResults)) &&
147 | (identical(other.articles, articles) ||
148 | const DeepCollectionEquality()
149 | .equals(other.articles, articles)));
150 | }
151 |
152 | @override
153 | int get hashCode =>
154 | runtimeType.hashCode ^
155 | const DeepCollectionEquality().hash(status) ^
156 | const DeepCollectionEquality().hash(totalResults) ^
157 | const DeepCollectionEquality().hash(articles);
158 |
159 | @override
160 | _$NewsCopyWith<_News> get copyWith =>
161 | __$NewsCopyWithImpl<_News>(this, _$identity);
162 |
163 | @override
164 | Map toJson() {
165 | return _$_$_NewsToJson(this);
166 | }
167 | }
168 |
169 | abstract class _News implements News {
170 | factory _News(
171 | {@required String status,
172 | @required int totalResults,
173 | List articles}) = _$_News;
174 |
175 | factory _News.fromJson(Map json) = _$_News.fromJson;
176 |
177 | @override
178 | String get status;
179 | @override
180 | int get totalResults;
181 | @override
182 | List get articles;
183 | @override
184 | _$NewsCopyWith<_News> get copyWith;
185 | }
186 |
--------------------------------------------------------------------------------
/lib/data/model/news.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'news.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | _$_News _$_$_NewsFromJson(Map json) {
10 | return _$_News(
11 | status: json['status'] as String,
12 | totalResults: json['totalResults'] as int,
13 | articles: (json['articles'] as List)
14 | ?.map((e) =>
15 | e == null ? null : Article.fromJson(e as Map))
16 | ?.toList(),
17 | );
18 | }
19 |
20 | Map _$_$_NewsToJson(_$_News instance) => {
21 | 'status': instance.status,
22 | 'totalResults': instance.totalResults,
23 | 'articles': instance.articles,
24 | };
25 |
--------------------------------------------------------------------------------
/lib/data/model/result.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 |
4 | import '../app_error.dart';
5 |
6 | part 'result.freezed.dart';
7 |
8 | @freezed
9 | abstract class Result with _$Result {
10 | const Result._();
11 |
12 | const factory Result.success({T data}) = Success;
13 |
14 | const factory Result.failure({@required AppError error}) = Failure;
15 |
16 | static Result guard(T Function() body) {
17 | try {
18 | return Result.success(data: body());
19 | } on Exception catch (e) {
20 | return Result.failure(error: AppError(e));
21 | }
22 | }
23 |
24 | static Future> guardFuture(Future Function() future) async {
25 | try {
26 | return Result.success(data: await future());
27 | } on Exception catch (e) {
28 | return Result.failure(error: AppError(e));
29 | }
30 | }
31 |
32 | bool get isSuccess => when(success: (data) => true, failure: (e) => false);
33 |
34 | bool get isFailure => !isSuccess;
35 |
36 | void ifSuccess(Function(T data) body) {
37 | maybeWhen(
38 | success: (data) => body(data),
39 | orElse: () {
40 | // no-op
41 | },
42 | );
43 | }
44 |
45 | void ifFailure(Function(AppError e) body) {
46 | maybeWhen(
47 | failure: (e) => body(e),
48 | orElse: () {
49 | // no-op
50 | },
51 | );
52 | }
53 |
54 | T get dataOrThrow {
55 | return when(
56 | success: (data) => data,
57 | failure: (e) => throw e,
58 | );
59 | }
60 | }
61 |
62 | extension ResultObjectExt on T {
63 | Result get asSuccess => Result.success(data: this);
64 |
65 | Result asFailure(Exception e) => Result.failure(error: AppError(e));
66 | }
67 |
--------------------------------------------------------------------------------
/lib/data/model/result.freezed.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // ignore_for_file: deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies
3 |
4 | part of 'result.dart';
5 |
6 | // **************************************************************************
7 | // FreezedGenerator
8 | // **************************************************************************
9 |
10 | T _$identity(T value) => value;
11 |
12 | /// @nodoc
13 | class _$ResultTearOff {
14 | const _$ResultTearOff();
15 |
16 | // ignore: unused_element
17 | Success success({T data}) {
18 | return Success(
19 | data: data,
20 | );
21 | }
22 |
23 | // ignore: unused_element
24 | Failure failure({@required AppError error}) {
25 | return Failure(
26 | error: error,
27 | );
28 | }
29 | }
30 |
31 | /// @nodoc
32 | // ignore: unused_element
33 | const $Result = _$ResultTearOff();
34 |
35 | /// @nodoc
36 | mixin _$Result {
37 | @optionalTypeArgs
38 | Result when({
39 | @required Result success(T data),
40 | @required Result failure(AppError error),
41 | });
42 | @optionalTypeArgs
43 | Result maybeWhen({
44 | Result success(T data),
45 | Result failure(AppError error),
46 | @required Result orElse(),
47 | });
48 | @optionalTypeArgs
49 | Result map({
50 | @required Result success(Success value),
51 | @required Result failure(Failure value),
52 | });
53 | @optionalTypeArgs
54 | Result maybeMap({
55 | Result success(Success value),
56 | Result failure(Failure value),
57 | @required Result orElse(),
58 | });
59 | }
60 |
61 | /// @nodoc
62 | abstract class $ResultCopyWith {
63 | factory $ResultCopyWith(Result value, $Res Function(Result) then) =
64 | _$ResultCopyWithImpl;
65 | }
66 |
67 | /// @nodoc
68 | class _$ResultCopyWithImpl implements $ResultCopyWith {
69 | _$ResultCopyWithImpl(this._value, this._then);
70 |
71 | final Result _value;
72 | // ignore: unused_field
73 | final $Res Function(Result) _then;
74 | }
75 |
76 | /// @nodoc
77 | abstract class $SuccessCopyWith {
78 | factory $SuccessCopyWith(Success value, $Res Function(Success) then) =
79 | _$SuccessCopyWithImpl;
80 | $Res call({T data});
81 | }
82 |
83 | /// @nodoc
84 | class _$SuccessCopyWithImpl extends _$ResultCopyWithImpl
85 | implements $SuccessCopyWith {
86 | _$SuccessCopyWithImpl(Success _value, $Res Function(Success) _then)
87 | : super(_value, (v) => _then(v as Success));
88 |
89 | @override
90 | Success get _value => super._value as Success;
91 |
92 | @override
93 | $Res call({
94 | Object data = freezed,
95 | }) {
96 | return _then(Success(
97 | data: data == freezed ? _value.data : data as T,
98 | ));
99 | }
100 | }
101 |
102 | /// @nodoc
103 | class _$Success extends Success with DiagnosticableTreeMixin {
104 | const _$Success({this.data}) : super._();
105 |
106 | @override
107 | final T data;
108 |
109 | @override
110 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
111 | return 'Result<$T>.success(data: $data)';
112 | }
113 |
114 | @override
115 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
116 | super.debugFillProperties(properties);
117 | properties
118 | ..add(DiagnosticsProperty('type', 'Result<$T>.success'))
119 | ..add(DiagnosticsProperty('data', data));
120 | }
121 |
122 | @override
123 | bool operator ==(dynamic other) {
124 | return identical(this, other) ||
125 | (other is Success &&
126 | (identical(other.data, data) ||
127 | const DeepCollectionEquality().equals(other.data, data)));
128 | }
129 |
130 | @override
131 | int get hashCode =>
132 | runtimeType.hashCode ^ const DeepCollectionEquality().hash(data);
133 |
134 | @override
135 | $SuccessCopyWith> get copyWith =>
136 | _$SuccessCopyWithImpl>(this, _$identity);
137 |
138 | @override
139 | @optionalTypeArgs
140 | Result when({
141 | @required Result success(T data),
142 | @required Result failure(AppError error),
143 | }) {
144 | assert(success != null);
145 | assert(failure != null);
146 | return success(data);
147 | }
148 |
149 | @override
150 | @optionalTypeArgs
151 | Result maybeWhen({
152 | Result success(T data),
153 | Result failure(AppError error),
154 | @required Result orElse(),
155 | }) {
156 | assert(orElse != null);
157 | if (success != null) {
158 | return success(data);
159 | }
160 | return orElse();
161 | }
162 |
163 | @override
164 | @optionalTypeArgs
165 | Result map({
166 | @required Result success(Success value),
167 | @required Result failure(Failure value),
168 | }) {
169 | assert(success != null);
170 | assert(failure != null);
171 | return success(this);
172 | }
173 |
174 | @override
175 | @optionalTypeArgs
176 | Result maybeMap({
177 | Result success(Success value),
178 | Result failure(Failure value),
179 | @required Result orElse(),
180 | }) {
181 | assert(orElse != null);
182 | if (success != null) {
183 | return success(this);
184 | }
185 | return orElse();
186 | }
187 | }
188 |
189 | abstract class Success extends Result {
190 | const Success._() : super._();
191 | const factory Success({T data}) = _$Success;
192 |
193 | T get data;
194 | $SuccessCopyWith> get copyWith;
195 | }
196 |
197 | /// @nodoc
198 | abstract class $FailureCopyWith {
199 | factory $FailureCopyWith(Failure value, $Res Function(Failure) then) =
200 | _$FailureCopyWithImpl;
201 | $Res call({AppError error});
202 | }
203 |
204 | /// @nodoc
205 | class _$FailureCopyWithImpl extends _$ResultCopyWithImpl
206 | implements $FailureCopyWith {
207 | _$FailureCopyWithImpl(Failure _value, $Res Function(Failure) _then)
208 | : super(_value, (v) => _then(v as Failure));
209 |
210 | @override
211 | Failure get _value => super._value as Failure;
212 |
213 | @override
214 | $Res call({
215 | Object error = freezed,
216 | }) {
217 | return _then(Failure(
218 | error: error == freezed ? _value.error : error as AppError,
219 | ));
220 | }
221 | }
222 |
223 | /// @nodoc
224 | class _$Failure extends Failure with DiagnosticableTreeMixin {
225 | const _$Failure({@required this.error})
226 | : assert(error != null),
227 | super._();
228 |
229 | @override
230 | final AppError error;
231 |
232 | @override
233 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
234 | return 'Result<$T>.failure(error: $error)';
235 | }
236 |
237 | @override
238 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
239 | super.debugFillProperties(properties);
240 | properties
241 | ..add(DiagnosticsProperty('type', 'Result<$T>.failure'))
242 | ..add(DiagnosticsProperty('error', error));
243 | }
244 |
245 | @override
246 | bool operator ==(dynamic other) {
247 | return identical(this, other) ||
248 | (other is Failure &&
249 | (identical(other.error, error) ||
250 | const DeepCollectionEquality().equals(other.error, error)));
251 | }
252 |
253 | @override
254 | int get hashCode =>
255 | runtimeType.hashCode ^ const DeepCollectionEquality().hash(error);
256 |
257 | @override
258 | $FailureCopyWith> get copyWith =>
259 | _$FailureCopyWithImpl>(this, _$identity);
260 |
261 | @override
262 | @optionalTypeArgs
263 | Result when({
264 | @required Result success(T data),
265 | @required Result failure(AppError error),
266 | }) {
267 | assert(success != null);
268 | assert(failure != null);
269 | return failure(error);
270 | }
271 |
272 | @override
273 | @optionalTypeArgs
274 | Result maybeWhen({
275 | Result success(T data),
276 | Result failure(AppError error),
277 | @required Result orElse(),
278 | }) {
279 | assert(orElse != null);
280 | if (failure != null) {
281 | return failure(error);
282 | }
283 | return orElse();
284 | }
285 |
286 | @override
287 | @optionalTypeArgs
288 | Result map({
289 | @required Result success(Success value),
290 | @required Result failure(Failure value),
291 | }) {
292 | assert(success != null);
293 | assert(failure != null);
294 | return failure(this);
295 | }
296 |
297 | @override
298 | @optionalTypeArgs
299 | Result maybeMap({
300 | Result success(Success value),
301 | Result failure(Failure value),
302 | @required Result orElse(),
303 | }) {
304 | assert(orElse != null);
305 | if (failure != null) {
306 | return failure(this);
307 | }
308 | return orElse();
309 | }
310 | }
311 |
312 | abstract class Failure extends Result {
313 | const Failure._() : super._();
314 | const factory Failure({@required AppError error}) = _$Failure;
315 |
316 | AppError get error;
317 | $FailureCopyWith> get copyWith;
318 | }
319 |
--------------------------------------------------------------------------------
/lib/data/model/source.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 |
4 | part 'source.freezed.dart';
5 |
6 | part 'source.g.dart';
7 |
8 | @freezed
9 | abstract class Source with _$Source {
10 | factory Source({
11 | String id,
12 | String name,
13 | }) = _Source;
14 |
15 | factory Source.fromJson(Map json) => _$SourceFromJson(json);
16 | }
17 |
--------------------------------------------------------------------------------
/lib/data/model/source.freezed.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 | // ignore_for_file: deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies
3 |
4 | part of 'source.dart';
5 |
6 | // **************************************************************************
7 | // FreezedGenerator
8 | // **************************************************************************
9 |
10 | T _$identity(T value) => value;
11 | Source _$SourceFromJson(Map json) {
12 | return _Source.fromJson(json);
13 | }
14 |
15 | /// @nodoc
16 | class _$SourceTearOff {
17 | const _$SourceTearOff();
18 |
19 | // ignore: unused_element
20 | _Source call({String id, String name}) {
21 | return _Source(
22 | id: id,
23 | name: name,
24 | );
25 | }
26 |
27 | // ignore: unused_element
28 | Source fromJson(Map json) {
29 | return Source.fromJson(json);
30 | }
31 | }
32 |
33 | /// @nodoc
34 | // ignore: unused_element
35 | const $Source = _$SourceTearOff();
36 |
37 | /// @nodoc
38 | mixin _$Source {
39 | String get id;
40 | String get name;
41 |
42 | Map toJson();
43 | $SourceCopyWith get copyWith;
44 | }
45 |
46 | /// @nodoc
47 | abstract class $SourceCopyWith<$Res> {
48 | factory $SourceCopyWith(Source value, $Res Function(Source) then) =
49 | _$SourceCopyWithImpl<$Res>;
50 | $Res call({String id, String name});
51 | }
52 |
53 | /// @nodoc
54 | class _$SourceCopyWithImpl<$Res> implements $SourceCopyWith<$Res> {
55 | _$SourceCopyWithImpl(this._value, this._then);
56 |
57 | final Source _value;
58 | // ignore: unused_field
59 | final $Res Function(Source) _then;
60 |
61 | @override
62 | $Res call({
63 | Object id = freezed,
64 | Object name = freezed,
65 | }) {
66 | return _then(_value.copyWith(
67 | id: id == freezed ? _value.id : id as String,
68 | name: name == freezed ? _value.name : name as String,
69 | ));
70 | }
71 | }
72 |
73 | /// @nodoc
74 | abstract class _$SourceCopyWith<$Res> implements $SourceCopyWith<$Res> {
75 | factory _$SourceCopyWith(_Source value, $Res Function(_Source) then) =
76 | __$SourceCopyWithImpl<$Res>;
77 | @override
78 | $Res call({String id, String name});
79 | }
80 |
81 | /// @nodoc
82 | class __$SourceCopyWithImpl<$Res> extends _$SourceCopyWithImpl<$Res>
83 | implements _$SourceCopyWith<$Res> {
84 | __$SourceCopyWithImpl(_Source _value, $Res Function(_Source) _then)
85 | : super(_value, (v) => _then(v as _Source));
86 |
87 | @override
88 | _Source get _value => super._value as _Source;
89 |
90 | @override
91 | $Res call({
92 | Object id = freezed,
93 | Object name = freezed,
94 | }) {
95 | return _then(_Source(
96 | id: id == freezed ? _value.id : id as String,
97 | name: name == freezed ? _value.name : name as String,
98 | ));
99 | }
100 | }
101 |
102 | @JsonSerializable()
103 |
104 | /// @nodoc
105 | class _$_Source with DiagnosticableTreeMixin implements _Source {
106 | _$_Source({this.id, this.name});
107 |
108 | factory _$_Source.fromJson(Map json) =>
109 | _$_$_SourceFromJson(json);
110 |
111 | @override
112 | final String id;
113 | @override
114 | final String name;
115 |
116 | @override
117 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
118 | return 'Source(id: $id, name: $name)';
119 | }
120 |
121 | @override
122 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
123 | super.debugFillProperties(properties);
124 | properties
125 | ..add(DiagnosticsProperty('type', 'Source'))
126 | ..add(DiagnosticsProperty('id', id))
127 | ..add(DiagnosticsProperty('name', name));
128 | }
129 |
130 | @override
131 | bool operator ==(dynamic other) {
132 | return identical(this, other) ||
133 | (other is _Source &&
134 | (identical(other.id, id) ||
135 | const DeepCollectionEquality().equals(other.id, id)) &&
136 | (identical(other.name, name) ||
137 | const DeepCollectionEquality().equals(other.name, name)));
138 | }
139 |
140 | @override
141 | int get hashCode =>
142 | runtimeType.hashCode ^
143 | const DeepCollectionEquality().hash(id) ^
144 | const DeepCollectionEquality().hash(name);
145 |
146 | @override
147 | _$SourceCopyWith<_Source> get copyWith =>
148 | __$SourceCopyWithImpl<_Source>(this, _$identity);
149 |
150 | @override
151 | Map toJson() {
152 | return _$_$_SourceToJson(this);
153 | }
154 | }
155 |
156 | abstract class _Source implements Source {
157 | factory _Source({String id, String name}) = _$_Source;
158 |
159 | factory _Source.fromJson(Map json) = _$_Source.fromJson;
160 |
161 | @override
162 | String get id;
163 | @override
164 | String get name;
165 | @override
166 | _$SourceCopyWith<_Source> get copyWith;
167 | }
168 |
--------------------------------------------------------------------------------
/lib/data/model/source.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'source.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | _$_Source _$_$_SourceFromJson(Map json) {
10 | return _$_Source(
11 | id: json['id'] as String,
12 | name: json['name'] as String,
13 | );
14 | }
15 |
16 | Map _$_$_SourceToJson(_$_Source instance) => {
17 | 'id': instance.id,
18 | 'name': instance.name,
19 | };
20 |
--------------------------------------------------------------------------------
/lib/data/provider/app_shared_preferences_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 |
3 | import '../local/app_shared_preferences.dart';
4 |
5 | final prefsProvider =
6 | Provider((ref) => AppSharedPreferences());
7 |
--------------------------------------------------------------------------------
/lib/data/provider/auth_data_source_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 |
3 | import '../remote/auth_data_source.dart';
4 | import '../remote/auth_data_source_impl.dart';
5 | import 'firebase_auth_provider.dart';
6 |
7 | final authDataSourceProvider = Provider(
8 | (ref) => AuthDataSourceImpl(ref.read(firebaseAuthProvider)));
9 |
--------------------------------------------------------------------------------
/lib/data/provider/auth_repository_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 |
3 | import '../repository/auth_repository.dart';
4 | import '../repository/auth_repository_impl.dart';
5 | import 'auth_data_source_provider.dart';
6 |
7 | final authRepositoryProvider = Provider(
8 | (ref) => AuthRepositoryImpl(ref.read(authDataSourceProvider)));
9 |
--------------------------------------------------------------------------------
/lib/data/provider/dio_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:hooks_riverpod/hooks_riverpod.dart';
3 |
4 | import '../remote/app_dio.dart';
5 |
6 | final dioProvider = Provider((_) => AppDio.getInstance());
7 |
--------------------------------------------------------------------------------
/lib/data/provider/firebase_auth_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:firebase_auth/firebase_auth.dart';
2 | import 'package:hooks_riverpod/hooks_riverpod.dart';
3 |
4 | final firebaseAuthProvider =
5 | Provider((_) => FirebaseAuth.instance);
6 |
--------------------------------------------------------------------------------
/lib/data/provider/news_data_source_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 |
3 | import '../remote/news_data_source.dart';
4 | import '../remote/news_data_source_impl.dart';
5 | import 'dio_provider.dart';
6 |
7 | final newsDataSourceProvider = Provider(
8 | (ref) => NewsDataSourceImpl(dio: ref.read(dioProvider)));
9 |
--------------------------------------------------------------------------------
/lib/data/provider/news_repository_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 |
3 | import '../repository/news_repository.dart';
4 | import '../repository/news_repository_impl.dart';
5 | import 'news_data_source_provider.dart';
6 |
7 | final newsRepositoryProvider = Provider(
8 | (ref) => NewsRepositoryImpl(dataSource: ref.read(newsDataSourceProvider)));
9 |
--------------------------------------------------------------------------------
/lib/data/provider/theme_data_source_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 |
3 | import '../local/theme_data_source_impl.dart';
4 | import 'app_shared_preferences_provider.dart';
5 |
6 | final themeDataSourceProvider =
7 | Provider((ref) => ThemeDataSourceImpl(ref.read(prefsProvider)));
8 |
--------------------------------------------------------------------------------
/lib/data/provider/theme_repository_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 |
3 | import '../repository/theme_repository.dart';
4 | import '../repository/theme_repository_impl.dart';
5 | import 'theme_data_source_provider.dart';
6 |
7 | final themeRepositoryProvider = Provider((ref) =>
8 | ThemeRepositoryImpl(dataSource: ref.read(themeDataSourceProvider)));
9 |
--------------------------------------------------------------------------------
/lib/data/remote/app_dio.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/adapter.dart';
2 | import 'package:dio/dio.dart';
3 | import 'package:dio_firebase_performance/dio_firebase_performance.dart';
4 | import 'package:dio_http_cache/dio_http_cache.dart';
5 | import 'package:flutter/foundation.dart';
6 | import 'package:ua_client_hints/ua_client_hints.dart';
7 |
8 | import '../../constants.dart';
9 |
10 | // ignore: prefer_mixin
11 | class AppDio with DioMixin implements Dio {
12 | AppDio._([BaseOptions options]) {
13 | options = BaseOptions(
14 | baseUrl: Constants.of().endpoint,
15 | contentType: 'application/json',
16 | connectTimeout: 30000,
17 | sendTimeout: 30000,
18 | receiveTimeout: 30000,
19 | );
20 |
21 | this.options = options;
22 | interceptors.add(InterceptorsWrapper(onRequest: (options) async {
23 | options.headers.addAll(await userAgentClientHintsHeader());
24 | }));
25 |
26 | // API Cache
27 | interceptors.add(DioCacheManager(
28 | CacheConfig(
29 | baseUrl: Constants.of().endpoint,
30 | ),
31 | ).interceptor);
32 |
33 | // Firebase Performance
34 | interceptors.add(DioFirebasePerformanceInterceptor());
35 |
36 | if (kDebugMode) {
37 | // Local Log
38 | interceptors.add(LogInterceptor(responseBody: true, requestBody: true));
39 | }
40 |
41 | httpClientAdapter = DefaultHttpClientAdapter();
42 | }
43 |
44 | static Dio getInstance() => AppDio._();
45 | }
46 |
--------------------------------------------------------------------------------
/lib/data/remote/auth_data_source.dart:
--------------------------------------------------------------------------------
1 | import 'package:firebase_auth/firebase_auth.dart';
2 |
3 | abstract class AuthDataSource {
4 | Future signIn();
5 |
6 | Future signOut();
7 | }
8 |
--------------------------------------------------------------------------------
/lib/data/remote/auth_data_source_impl.dart:
--------------------------------------------------------------------------------
1 | import 'package:firebase_auth/firebase_auth.dart' as firebase;
2 | import 'package:flutter/foundation.dart';
3 | import 'package:google_sign_in/google_sign_in.dart';
4 |
5 | import 'auth_data_source.dart';
6 |
7 | class AuthDataSourceImpl implements AuthDataSource {
8 | AuthDataSourceImpl(this._firebaseAuth);
9 |
10 | final firebase.FirebaseAuth _firebaseAuth;
11 |
12 | @override
13 | Future signIn() async {
14 | final account = await GoogleSignIn().signIn();
15 | if (account == null) {
16 | return throw StateError('Maybe user canceled.');
17 | }
18 | final auth = await account.authentication;
19 | final firebase.AuthCredential authCredential =
20 | firebase.GoogleAuthProvider.credential(
21 | idToken: auth.idToken,
22 | accessToken: auth.accessToken,
23 | );
24 |
25 | final credential = await _firebaseAuth.signInWithCredential(authCredential);
26 | final currentUser = await firebase.FirebaseAuth.instance.currentUser;
27 | assert(credential.user.uid == currentUser.uid);
28 | return credential.user;
29 | }
30 |
31 | @override
32 | Future signOut() {
33 | return GoogleSignIn()
34 | .signOut()
35 | .then((_) => _firebaseAuth.signOut())
36 | .catchError((error) {
37 | debugPrint(error.toString());
38 | throw error;
39 | });
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/data/remote/news_data_source.dart:
--------------------------------------------------------------------------------
1 | import '../model/news.dart';
2 |
3 | // ignore: one_member_abstracts
4 | abstract class NewsDataSource {
5 | Future getNews();
6 | }
7 |
--------------------------------------------------------------------------------
/lib/data/remote/news_data_source_impl.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:dio/dio.dart';
4 | import 'package:dio_http_cache/dio_http_cache.dart';
5 | import 'package:flutter/foundation.dart';
6 |
7 | import '../../constants.dart';
8 | import '../../util/ext/date_time.dart';
9 | import '../model/news.dart';
10 | import 'news_data_source.dart';
11 |
12 | class NewsDataSourceImpl implements NewsDataSource {
13 | NewsDataSourceImpl({@required Dio dio}) : _dio = dio;
14 |
15 | final Dio _dio;
16 |
17 | @override
18 | Future getNews() {
19 | return _dio
20 | .get