⚠️ 制限事項
- 現在 Web 版がビルドできません。Isar 3.0.2 が Web をサポートしなくなったためです。詳細は Issue をご参照ください。
- 現在テストが通りません。ディレクトリ構造を変更したことにテストが追従できていません。対応中です。
GitHub API を利用して GitHub のリポジトリを検索するアプリです。株式会社ゆめみのFlutterエンジニアコードチェックの要件を満たすよう実装しています。
本アプリを通して自分なりの最適なアーキテクチャを確立し、リファレンスコードにすることを目的にしています。
⚠️ 注意
このアプリはGitHub API
を利用するために GitHub のアクセストークン
をアプリの内部でハードコーディングして保持する構成になっています。このアプリを公開すると悪意のある者にアクセストークン
を抜き取られ悪用される恐れがありますのでお控え下さい。もちろん、手元でビルドして動かすことは問題ありません。
一覧(Light) | 一覧(Dark) |
---|---|
デスクトップ | タブレット |
---|---|
詳細 | 0件 | エラー |
---|---|---|
git clone https://github.com/susatthi/github-search.git
本アプリで使用する GitHub の個人アクセストークンを取得して、カレントディレクトリで次のコマンドを実行してください。
# 引数で与えられた環境変数を基にビルドに必要な `lib/util/env/env.dart` を作成してくれます。
# 作成された `lib/util/env/env.dart` を直接編集しても大丈夫です。
bin/flutter_env -g [GitHub 個人アクセストークン] -s [検索文字列の初期値]
パラメータ | 説明 | |
---|---|---|
-g |
Must |
値には GitHub 個人アクセストークン を設定してください。 |
-s |
Optional |
値には好きな文字列を設定してください。指定しない場合は空文字が設定されます。 |
-h |
ヘルプを表示します。 |
Configurations を選択してビルドしてください。
Configurations 名 | 説明 |
---|---|
app-debug |
アプリ向けデバッグビルド |
app-release |
アプリ向けリリースビルド |
web-debug |
Web 向けデバッグビルド |
web-release |
Web 向けリリースビルド |
- アプリの機能
- go_router と go_router_builder を使ったルーティング
- http を使った REST API の実装
- fast_i18n を使った多言語対応(日本語/英語)
- カスタムフォント対応
- mocktail を使った Unit / Widget テスト
- flutter_launcher_icons を使ったアプリアイコン
- flutter_native_splash を使ったスプラッシュ画面
- responsive_framework を使ったレスポンシブ対応
- GitHub Actions によるCI(自動テストと自動ビルド)
- ダークモード対応
- サポートするプラットフォーム
- iOS / Android / Web / macOS / Windows
- Integration テスト
- Riverpod 2 対応
- Firebase 連携
- Flavor 対応(develop / staging / production などの環境分け)
- flutter_riverpod + go_router
- CODE WITH ANDREA と DDD のアーキテクチャを参考にして、本アプリは下記の3層アーキテクチャで実装しています。
ユーザーとの I/F を担う層。Application 層と Domain 層に依存する。Infrastructure 層に依存してはいけない。
ページや UI 部品の Widget クラス群。State を監視( watch / listen )して UI に表現する。ユーザーイベントを検知して Service のメソッドを呼び出す。キャッシュが効かなくなるので直接 Repository Interface を呼び出してはいけない。画面遷移の実装は Widget のイベントハンドラー内で行ってよい。
アプリケーションのロジックや状態を定義する層。Domain 層に依存する。Presentation 層と Infrastructure 層に依存してはいけない。
アプリのあらゆる状態。Domain 層の Entity そのものでもよいし、複数の Repository をまたいだ Entity を統合するクラスでもよい。State は StateProvider
等でラップされ Widget や他の State から参照される。
ユーザーイベントを受け付けて、複数の Repository Interface を呼び出して Entity を受け取って State を更新するサービスクラス。Widget からのメソッド呼び出しや、依存する State の更新を契機に発火する。
ドメインロジックやドメインオブジェクト(エンティティ)を定義する層。どの層にも依存してはいけない。
Repository Interface で扱うドメインオブジェクト(データの構造体)。入力値のバリデーションは Entity のコンストラクタで実装する。Infrastructure 層が投げる例外はドメイン層で定義する。
データの永続化や外部サービス連携を担う Repository のインターフェース。集約毎に定義する。
データの永続化や外部サービス連携を担う層。Domain 層に依存する。Presentation 層と Application 層に依存してはいけない。
Repository Interface の実装。Data Source を利用してデータの永続化を行う。
様々なデータソース。Firebase だったり、API だったり、Hive だったり、SharedPreferences だったり、Isar だったりする。
├── application アプリケーション層
│ └── <関心事>
│ ├── <state> 状態クラス群
│ └── <関心事>_service.dart サービスクラス
├── domain ドメイン層
│ ├── exceptions.dart 例外クラス
│ └── repository
│ └── <集約>
│ ├── <集約>_repository.dart リポジトリのインターフェースクラス
│ └── entity 集約単位のエンティティ
├── infrastructure インフラストラクチャ層
│ └── <データソース>
│ └── <集約>
│ └── <集約>_repository.dart リポジトリの実装
├── presentation
│ ├── app.dart アプリケーション
│ ├── router.dart ルーティング
│ ├── theme.dart テーマ
│ ├── component プレゼンテーション層で共通の Widget
│ └── page
│ └── <関心事>
│ ├── component 画面単位の Widget
│ └── <関心事>_<CURD>page.dart 画面Widget
└── util どの層からもアクセス可能な便利クラス(ロガー、拡張メソッドなど)
基本的に 関心事 毎にファイルを分割しています。例えば、Controller と State を別々のファイルに分けることはしません。ファイル名は 関心事.dart とします。ファイル名 = クラス名とはしません。
Version | |
---|---|
Flutter | 3.3.10 |
Dart | 2.18.6 |
util/localization/*.json
ファイルを変更した場合やfreezed
を使ったdart
ファイルを変更した場合は次のコマンドを実行してください。
make build-runner
- ローカルで単体テストを行うためには事前に次のライブラリをインストールしてください。
# lcov のインストール
brew install lcov
# dart_dot_reporter のインストール
flutter pub global activate dart_dot_reporter
- 次のコマンドで単体テスト(静的解析 => テスト => カバレッジの結果を表示 )を実行します。
# 言語設定が英語のテスト
make test-en
# 言語設定が日本語のテスト
make test-ja
-
API ドキュメント で公開しています。
-
生成する場合は次のコマンドを実行してください。
make dartdoc
- GitHub Actions を利用して CI を構築しています。
- プルリクエストが作成や更新された時、もしくは
main
またはdevelop
ブランチにpush
されたときに CI が発火します。
- プルリクエストが作成や更新された時、もしくは
%%{init:{'theme':'base','themeVariables':{'primaryColor':'#f0f0f0','primaryTextColor':'#2f2f2f', 'lineColor':'#2f2f2f','textColor':'#2f2f2f','fontSize':'16px','nodeBorder':'0px'}}}%%
flowchart LR
Start((開始)) --> AnalyzeUbuntu(Ubuntu静的解析)
Start --> AnalyzeMacosEn(macOS英語静的解析)
Start --> AnalyzeMacosJp(macOS日本語静的解析)
Start --> AnalyzeWindows(Windows静的解析)
Start --> BuildAndroid(Androidビルド)
Start --> BuildiOS(iOSビルド)
Start --> BuildWeb(Webビルド)
Start --> BuildMacOS(macOSビルド)
Start --> BuildWindows(Windowsビルド)
AnalyzeUbuntu ---> TestUbuntu(Ubuntu単体テスト)
AnalyzeMacosEn ---> TestMacosEn(macOS英語単体テスト)
AnalyzeMacosJp --> TestMacosJp(macOS日本語単体テスト)
TestMacosJp --> UploadCoverageMacosJp(Codecovに結果を送信)
AnalyzeWindows ---> TestWindows(Windows単体テスト)
UploadCoverageMacosJp --> NotifySlack(Slackに結果を送信)
TestUbuntu --> NotifySlack
TestMacosEn --> NotifySlack
TestWindows --> NotifySlack
BuildAndroid ----> NotifySlack
BuildiOS ----> NotifySlack
BuildWeb ----> NotifySlack
BuildMacOS ----> NotifySlack
BuildWindows ----> NotifySlack
NotifySlack --> End((終了))
classDef anchor fill:#4063DD, color:#ffffff;
classDef testJob fill:#4063DD, color:#ffffff;
classDef buildJob fill:#d32f2f, color:#ffffff;
classDef reportJob fill:#437C40, color:#ffffff;
%% class Start,End anchor;
class AnalyzeUbuntu,TestUbuntu,UploadCoverageMacosJp,AnalyzeMacosEn,AnalyzeMacosJp,TestMacosEn,TestMacosJp,AnalyzeWindows,TestWindows testJob;
class BuildAndroid,BuildiOS,BuildWeb,BuildMacOS,BuildWindows,CreateApiDoc,DeployGitHubPages buildJob;
class NotifySlack reportJob;
MIT