GitHub 搜索
利用 GitHub API 搜索 GitHub 仓库的应用。实现了株式会社 yumemi 的 Flutter 工程师代码检查的要求。
通过这款应用,旨在确立自己最合适的架构,并将其作为参考代码。
⚠️ 注意 此应用为了使用 `GitHub API`,其配置是将 GitHub 的 `访问令牌` 硬编码在应用内部。如果公开此应用,可能会导致恶意者窃取 `访问令牌` 并滥用,请避免公开。当然,在本地构建和运行是没有问题的。
应用功能
- 简洁的 UI / UX
- GitHub 仓库搜索及详情显示
- 支持无限滚动
- 使用 go_router 进行新的路由管理
- 使用 http 实现 REST API
- 多语言支持(日语/英语)
- 支持自定义字体
- 使用 mockito 进行单元/组件测试
- 使用 flutter_launcher_icons 设置应用图标
- 使用 flutter_native_splash 设置启动画面
- 通过 GitHub Actions 进行自动化测试和构建
- 支持的平台
- iOS / Android / Web / macOS / Windows
未来支持计划
- 使用 hive 或 shared_preferences
- 集成测试
- 主题支持
- 暗黑模式支持
- 更佳的 UI / UX
不支持的功能
- Firebase 集成
- Flavor 支持(开发/预生产/生产等环境划分)
架构 / 软件包
- flutter_riverpod + state_notifier + freezed + go_router
- 参考了 CODE WITH ANDREA 的以下架构。在此应用中,省略了 Application Layer。
- 这是本应用依赖关系图。
%%{init:{'theme':'base','themeVariables':{'primaryColor':'#f0f0f0','primaryTextColor':'#2f2f2f', 'lineColor':'#2f2f2f','textColor':'#2f2f2f','fontSize':'16px','nodeBorder':'0px'}}}%%
graph TD
subgraph プレゼンテーション層
IndexPage(一覧ページ<br>StatelessWidget) --> SearchTextField(検索テキストフィールド<br>ConsumerWidget)
IndexPage --> ListView(一覧 View<br>ConsumerWidget)
SearchTextField --> SearchText([検索文字列<br>String])
ListView --> ListViewState([一覧 View 状態<br>State])
ListViewState --> ListViewController(一覧 View コントローラ<br>StateNotifier)
ListViewController --> SearchText
ViewPage(詳細ページ<br>StatelessWidget) --> DetailView(詳細 View<br>ConsumerWidget)
DetailView --> DetailViewState([詳細 View 状態<br>State])
DetailViewState --> DetailViewController(詳細 View コントローラ<br>StateNotifier)
DetailViewController --> ViewParameter([オーナー名とリポジトリ名<br>Equatable])
end
subgraph データ層
ListViewController --> RepoRepository(リポジトリ用リポジトリ)
DetailViewController ---> RepoRepository
RepoRepository --> GitHubRepoRepository(GitHub 向けリポジトリ用リポジトリ)
subgraph DTO
GitHubRepoRepository --> GitHubHttpClient(GitHub 向け HTTP クライアント)
GitHubRepoRepository --> GitHubApiDef(GitHub API 定義)
end
subgraph データソース
GitHubHttpClient --> GitHubApi(GitHub API)
end
end
subgraph 環境変数
SearchText --> EnvSearchText{{検索文字列初期値<br>String}}
GitHubHttpClient ---> EnvAccessToken{{アクセストークン<br>String}}
end
classDef widget fill:#4063DD, color:#ffffff;
classDef controller fill:#4063DD, color:#ffffff;
classDef state fill:#BDB5F4, color:#ffffff;
classDef repository fill:#437C40, color:#ffffff;
classDef env fill:#7c7d7c, color:#ffffff;
class IndexPage,ViewPage,ListView,SearchTextField,DetailView widget;
class ListViewController,DetailViewController controller;
class SearchText,ListViewState,DetailViewState,ViewParameter state;
class RepoRepository,GitHubRepoRepository,GitHubHttpClient,GitHubApiDef,GitHubApi repository;
class EnvSearchText,EnvAccessToken env;
列表视图更新示例列表视图的依赖关系为:列表视图→列表视图状态→列表视图控制器→搜索字符串。当用户更改搜索字符串并执行搜索时,会更新搜索字符串。然后,依赖于搜索字符串的列表视图控制器会更新,将搜索字符串提供给仓库仓库执行仓库搜索,并根据结果更新列表视图状态。然后,依赖于列表视图状态的列表视图会重新构建并重绘。
- 导航到
详情视图的示例- 当点击
列表视图的ListTile时,会更新要显示的所有者名称和仓库名称并导航到详情页面。当详情页面打开时,会构建详情视图并创建详情视图控制器。详情视图控制器将所有者名称和仓库名称提供给仓库仓库执行仓库获取,并根据结果更新详情视图状态。然后,依赖于详情视图状态的详情视图会重新构建并重绘。
- 当点击
文件夹结构
| 文件夹名 | 说明 |
|---|---|
/ assets |
访问assets的自动生成工具类 |
/ config |
应用程序、定义值、环境变量 |
/ entities |
模型层的文件,用作仓库的返回值实体,演示层使用的实体(带有 `_data` 后缀) |
/ localizations |
语言文件(`arb` 文件),由 `flutter gen-l10n` 生成的类 |
/ presentation / pages |
演示层的文件,屏幕 Widget |
/ presentation / widgets |
演示层的文件,组件 Widget、控制器、状态 |
/ repositories |
数据层的文件,仓库、数据源,数据源在子目录中管理 |
/ utils |
扩展功能、日志等实用类 |
环境
| 版本 | |
|---|---|
| Xcode | 13.3 |
| Android Studio | Bumblebee 2021.1.1 Patch 2 |
| Flutter | 2.10.3 |
| Swift | 5.6 |
| Kotlin | 1.6.10 |
| Chrome | 99 |
目标 OS 版本
| OS 版本 | |
|---|---|
| iOS | 9.0 ~ 15.4 |
| Android | 8.0 ~ 13 |
构建方法
- 请在当前目录执行以下命令。
bin/flutter_env会根据传入的参数创建构建所需的lib/config/env.dart文件。- 直接编辑创建的
lib/config/env.dart文件也是可以的。
bin/flutter_env -g [アクセストークン] -s [検索文字列の初期値]
| 参数名 | 说明 | |
|---|---|---|
-g [访问令牌] |
必须 |
请将 GitHub 个人访问令牌 设置为值。 |
-s [搜索字符串的初始值] |
可选 |
请设置您喜欢的字符串。如果不指定,则设置为空字符串。 |
-h |
显示帮助。 |
- 请选择 Configurations 进行构建
| Configurations 名 | 说明 |
|---|---|
app |
用于应用(iOS / Android) |
Web |
用于 Web |
代码自动生成
- 如果修改了 `arb` 文件或使用了 `freezed` 的 `dart` 文件,请执行以下命令。
bin/flutter_gen
测试
- 要进行本地测试,请先安装以下库。
# lcov のインストール
brew install lcov
# dart_dot_reporter のインストール
flutter pub global activate dart_dot_reporter
- 进行本地测试时,请执行以下命令。
- 执行静态分析 => 测试 => 并显示覆盖率结果。
bin/flutter_test
API 文档
-
已在 API 文档 中公开。
-
要本地生成,请执行以下命令。
bin/dartdoc
CI
- 我们使用 GitHub Actions 构建 CI。
- 当创建或更新 Pull Request 时,或者当 `main` 或 `develop` 分支被 `push` 时,CI 会被触发。
%%{init:{'theme':'base','themeVariables':{'primaryColor':'#f0f0f0','primaryTextColor':'#2f2f2f', 'lineColor':'#2f2f2f','textColor':'#2f2f2f','fontSize':'16px','nodeBorder':'0px'}}}%%
flowchart LR
Start((開始)) --> Analyze(静的解析)
subgraph テスト
Analyze --> Test(単体テスト)
Test --> UploadCoverage(Codecovに結果を送信)
end
subgraph ビルド
UploadCoverage --> BuildAndroid(Androidビルド)
UploadCoverage --> BuildiOS(iOSビルド)
UploadCoverage --> BuildWeb(Webビルド)
UploadCoverage --> BuildMacOS(macOSビルド)
UploadCoverage --> BuildWindows(Windowsビルド)
UploadCoverage --> CreateApiDoc(APIドキュメント作成)
CreateApiDoc --> DeployGitHubPages(GitHubPagesにデプロイ)
end
subgraph レポート
BuildAndroid ---> NotifySlack(Slackに結果を送信)
BuildiOS ---> NotifySlack
BuildWeb ---> NotifySlack
BuildMacOS ---> NotifySlack
BuildWindows ---> NotifySlack
DeployGitHubPages --> NotifySlack
end
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 Analyze,Test,UploadCoverage testJob;
class BuildAndroid,BuildiOS,BuildWeb,BuildMacOS,BuildWindows,CreateApiDoc,DeployGitHubPages buildJob;
class NotifySlack reportJob;
许可证
MIT

