├── .gitignore ├── .metadata ├── LICENSE ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── fluttergithub │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── icon_launcher.png │ │ │ └── icon_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── icon_launcher.png │ │ │ └── icon_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── icon_launcher.png │ │ │ ├── icon_launcher_round.png │ │ │ └── splash.jpg │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── icon_launcher.png │ │ │ └── icon_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── icon_launcher.png │ │ │ └── icon_launcher_round.png │ │ │ ├── values │ │ │ └── styles.xml │ │ │ └── xml │ │ │ └── network_security_config.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── apk └── flutterGithub.apk ├── demo ├── code-structure.png ├── demo1.jpg ├── demo10.jpg ├── demo11.jpg ├── demo12.jpg ├── demo2.jpg ├── demo3.jpg ├── demo4.jpg ├── demo5.jpg ├── demo6.jpg ├── demo7.jpg ├── demo8.jpg ├── demo9.jpg ├── gif-code.gif ├── gif-login.gif ├── gif-person.gif ├── gif-readme.gif ├── gif-repo.gif ├── gif-search.gif ├── gif-theme.gif ├── github-tip.jpeg ├── logo.png └── qr_code.png ├── fonts ├── fileiconfont.ttf └── iconfont.ttf ├── imgs ├── avatar_default.png ├── default_img.png ├── github_login_ic.png ├── login_back.jpg ├── repo_back0.gif ├── repo_back1.jpeg ├── repo_back2.jpeg ├── repo_back3.jpeg ├── repo_back4.jpg └── repo_back5.jpeg ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ └── contents.xcworkspacedata └── 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 │ └── Runner-Bridging-Header.h ├── jsons ├── RepoDaoBean.json ├── branchBean.json ├── cacheConfigBean.json ├── commitContentBean.json ├── commitDetailBean.json ├── commitDetailFileBean.json ├── commitDetailStatsBean.json ├── commitItemBean.json ├── commiterBean.json ├── eventBean.json ├── eventCommitBean.json ├── eventPayloadBean.json ├── fileBean.json ├── profileBean.json ├── readmeBean.json ├── repoBean.json ├── repoDetailBean.json ├── repoOwnerBean.json ├── trendDevSubBean.json ├── trendDeveloperBean.json ├── trendRepoBean.json └── userBean.json ├── l10n-arb ├── intl_messages.arb └── intl_zh_CN.arb ├── lib ├── common │ ├── CacheObject.dart │ ├── Global.dart │ ├── constant │ │ ├── constant.dart │ │ └── ignore.dart │ ├── delegate │ │ ├── index.dart │ │ └── sliver_delegate.dart │ ├── event │ │ └── event_bus.dart │ ├── myAvatar.dart │ ├── net │ │ ├── NetApi.dart │ │ └── api.dart │ └── util │ │ ├── CommonUtil.dart │ │ ├── ListViewUtil.dart │ │ ├── RelativeDateUtil.dart │ │ ├── ReposEventUtil.dart │ │ └── html_utils.dart ├── db │ ├── dao │ │ └── repo_history_dao.dart │ ├── db_manager.dart │ └── db_provider.dart ├── l10n │ ├── localization_intl.dart │ ├── messages_all.dart │ ├── messages_messages.dart │ └── messages_zh_CN.dart ├── main.dart ├── models │ ├── RepoDaoBean.dart │ ├── RepoDaoBean.g.dart │ ├── branchBean.dart │ ├── branchBean.g.dart │ ├── cacheConfigBean.dart │ ├── cacheConfigBean.g.dart │ ├── commitContentBean.dart │ ├── commitContentBean.g.dart │ ├── commitDetailBean.dart │ ├── commitDetailBean.g.dart │ ├── commitDetailFileBean.dart │ ├── commitDetailFileBean.g.dart │ ├── commitDetailStatsBean.dart │ ├── commitDetailStatsBean.g.dart │ ├── commitItemBean.dart │ ├── commitItemBean.g.dart │ ├── commiterBean.dart │ ├── commiterBean.g.dart │ ├── eventBean.dart │ ├── eventBean.g.dart │ ├── eventCommitBean.dart │ ├── eventCommitBean.g.dart │ ├── eventPayloadBean.dart │ ├── eventPayloadBean.g.dart │ ├── fileBean.dart │ ├── fileBean.g.dart │ ├── index.dart │ ├── profileBean.dart │ ├── profileBean.g.dart │ ├── readmeBean.dart │ ├── readmeBean.g.dart │ ├── repoBean.dart │ ├── repoBean.g.dart │ ├── repoDetailBean.dart │ ├── repoDetailBean.g.dart │ ├── repoOwnerBean.dart │ ├── repoOwnerBean.g.dart │ ├── trendDevSubBean.dart │ ├── trendDevSubBean.g.dart │ ├── trendDeveloperBean.dart │ ├── trendDeveloperBean.g.dart │ ├── trendRepoBean.dart │ ├── trendRepoBean.g.dart │ ├── userBean.dart │ └── userBean.g.dart ├── res │ ├── back_image.dart │ ├── icons.dart │ └── styles.dart ├── routes │ ├── CommitDetail │ │ ├── commit_detail_page.dart │ │ └── repo_event_push_list.dart │ ├── FileView │ │ ├── code_detail_fullscreen.dart │ │ ├── code_detail_web.dart │ │ └── photo_view_page.dart │ ├── SearchPage │ │ ├── search_page_repos.dart │ │ └── search_page_users.dart │ ├── drawer │ │ ├── follow_list_page.dart │ │ ├── index.dart │ │ ├── language_page.dart │ │ ├── repos_history_page.dart │ │ ├── test_page.dart │ │ ├── theme_change_page.dart │ │ └── trend │ │ │ ├── trend_page.dart │ │ │ ├── trend_page_developers.dart │ │ │ └── trend_page_repos.dart │ ├── home_page.dart │ ├── login_page.dart │ ├── person_detail_page.dart │ ├── repo_detail_page.dart │ ├── repo_list_page.dart │ └── search_page.dart ├── states │ ├── LocaleModel.dart │ ├── ProfileChangeNotifier.dart │ ├── ThemeModel.dart │ ├── UserModel.dart │ └── index.dart └── widgets │ ├── MyDrawer.dart │ ├── PersonItem.dart │ ├── RepoDetail │ ├── index.dart │ ├── repo_detail_commits.dart │ ├── repo_detail_events.dart │ ├── repo_detail_files.dart │ ├── repo_detail_info.dart │ └── repo_stargazer_or_watcher.dart │ ├── RepoItem.dart │ ├── TrendDevelopersItem.dart │ ├── TrendReposItem.dart │ ├── markdown │ ├── my_markdown_widget.dart │ └── syntax_high_lighter.dart │ ├── myWidgets │ ├── index.dart │ ├── myCard.dart │ ├── mySimpleWidget.dart │ ├── mySpinKit.dart │ └── no_data_or_no_net.dart │ └── personDetail │ ├── follow_person_list.dart │ ├── person_event_list.dart │ └── repo_list.dart ├── pubspec.lock ├── pubspec.yaml └── test └── widget_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Exceptions to above rules. 37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 38 | /token.txt 39 | -------------------------------------------------------------------------------- /.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: f139b11009aeb8ed2a3a3aa8b0066e482709dde3 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 MrHGJ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## FlutterGithub 2 | 3 | ![](./demo/logo.png) 4 | 5 | 6 | ### 用Flutter实现的一款界面精美、功能较全的Github客户端。支持多语言、换肤等功能。代码有充分注释、简单易懂,很适用于学习Flutter。 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 | 点击链接下载[https://github.com/MrHGJ/FlutterGithub/raw/master/apk/flutterGithub.apk] 33 | 34 | 或扫码下载apk进行体验: 35 |
36 | ![](./demo/qr_code.png) 37 |
38 | 39 | ## 功能特性 40 | - **登陆页和首页:** 41 |
42 | ![](./demo/gif-login.gif) 43 |
44 | - **换肤功能:** 45 |
46 | ![](./demo/gif-theme.gif) 47 |
48 | - **搜索功能:** 49 |
50 | ![](./demo/gif-search.gif) 51 |
52 | - **浏览源码:** 53 |
54 | ![](./demo/gif-code.gif) 55 |
56 | - **项目详情:** 57 |
58 | ![](./demo/gif-repo.gif) 59 |
60 | - **个人详情:** 61 |
62 | ![](./demo/gif-person.gif) 63 |
64 | ## 开始使用 65 | 1. 配置好flutter环境; 66 | 2. clone本项目: 67 | ``` 68 | $ git clone https://github.com/MrHGJ/FlutterGithub.git 69 | ``` 70 | 3. **注意点:**需要注册一个Github的OAuth application,替换项目中的`clientId`和`clientSecret`(位置:**./lib/common/constant/ignore.dart**); 71 | 申请地址:[https://github.com/settings/applications/new](https://github.com/settings/applications/new)信息可以随便填写,没有什么具体要求。例如下图所示,填完后提交即可得到client_id和client_secret; 72 | ![](./demo/github-tip.jpeg) 73 | 4. 大功告成,直接运行即可; 74 | 5. 登录用github用户名和密码(暂不支持邮箱登陆)。 75 | 76 | ## 代码结构 77 | ![](./demo/code-structure.png) 78 | - **fonts** 自定义的图标文件资源,.ttf格式; 79 | 80 | - **imgs** 图片资源; 81 | 82 | - **jsons** 存放生成Model类的json数据格式; 83 | 84 | - **l10n-arb** 多语言相关资源; 85 | 86 | - **lib** 87 | 88 | -- **common** 存放通用的类。例如全局变量、eventbus、网络请求、常用工具类等。 89 | 90 | -- **db** SQLite数据库相关类。 91 | 92 | -- **l10n** 多语言。 93 | 94 | -- **models** jsons文件夹对应的Dart Model实例类。 95 | 96 | -- **res** 资源文件。例如颜色、图片、自定义Icon图标、字体样式等。 97 | 98 | -- **routes** 存放所有页面路由类。 99 | 100 | -- **states** 保存APP中需要跨组件共享的状态类。 101 | 102 | -- **widges** 可复用的、常用的、封装的widget类。 103 | 104 | -- **main.dart** 程序入口。 105 | 106 | ## 相关文章 107 | - [**Flutter InfiniteListView学习与扩充**](https://blog.csdn.net/qq_34484722/article/details/106551197) 108 | - [**Github API (flutter调用)**](https://blog.csdn.net/qq_34484722/article/details/106540418) 109 | - [**Flutter App显示Github Readme文档**](https://blog.csdn.net/qq_34484722/article/details/106541277) 110 | - [**webview_flutter插件使用时报错**](https://blog.csdn.net/qq_34484722/article/details/106543039) 111 | - [**Flutter调试和打包**](https://blog.csdn.net/qq_34484722/article/details/106543282) 112 | - [**Flutter页面切换状态维持**](https://blog.csdn.net/qq_34484722/article/details/106543453) 113 | - [**Flutter图片蒙层背景的实现**](https://blog.csdn.net/qq_34484722/article/details/106550071) 114 | 115 | ## 第三方框架 116 | 117 | 库|功能 118 | :--:|:--: 119 | flutter_localizations和intl|国际化 120 | shared_preferences|SharedPreference本地缓存 121 | dio|网络请求 122 | cached_network_image| 加载网络图片并使用缓存 123 | provider|状态管理 124 | fluttertoast|toast显示 125 | flutter_markdown|显示markdown格式 126 | flukit|工具类,项目中主要使用了上拉加载更多列表InfiniteListView 127 | flutter_spinkit|炫酷的loading样式 128 | webview_flutter|提供webview支持 129 | event_bus|事件总线 130 | sqflite|sqlite 数据库 131 | photo_view|使图像能够通过用户手势(例如捏,旋转和拖动)进行缩放和平移 132 | ## 感谢 133 | ❤️ 学习flutter主要参考了[《Flutter实战》](https://book.flutterchina.club/) 134 | ❤️ 项目部分参考并借鉴 [GSYGithubAppFlutter](https://github.com/CarGuo/GSYGithubAppFlutter) 135 | 136 | ## License 137 | ``` 138 | MrHGJ/FlutterGithub is licensed under the 139 | MIT License 140 | 141 | Copyright (c) 2020 MrHGJ 142 | 143 | Permission is hereby granted, free of charge, to any person obtaining a copy 144 | of this software and associated documentation files (the "Software"), to deal 145 | in the Software without restriction, including without limitation the rights 146 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 147 | copies of the Software, and to permit persons to whom the Software is 148 | furnished to do so, subject to the following conditions: 149 | 150 | The above copyright notice and this permission notice shall be included in all 151 | copies or substantial portions of the Software. 152 | ``` -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /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 | 28 | android { 29 | compileSdkVersion 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | checkReleaseBuilds false 37 | disable 'InvalidPackage' 38 | } 39 | 40 | defaultConfig { 41 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 42 | applicationId "com.example.fluttergithub" 43 | minSdkVersion 16 44 | targetSdkVersion 28 45 | versionCode flutterVersionCode.toInteger() 46 | versionName flutterVersionName 47 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 48 | } 49 | 50 | buildTypes { 51 | release { 52 | // TODO: Add your own signing config for the release build. 53 | // Signing with the debug keys for now, so `flutter run --release` works. 54 | signingConfig signingConfigs.debug 55 | } 56 | } 57 | } 58 | 59 | flutter { 60 | source '../..' 61 | } 62 | 63 | dependencies { 64 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 65 | testImplementation 'junit:junit:4.12' 66 | androidTestImplementation 'androidx.test:runner:1.1.1' 67 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 68 | } 69 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 15 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/fluttergithub/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.fluttergithub 2 | 3 | import androidx.annotation.NonNull; 4 | import io.flutter.embedding.android.FlutterActivity 5 | import io.flutter.embedding.engine.FlutterEngine 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 10 | GeneratedPluginRegistrant.registerWith(flutterEngine); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/icon_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-hdpi/icon_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/icon_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-hdpi/icon_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/icon_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-mdpi/icon_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/icon_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-mdpi/icon_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/icon_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-xhdpi/icon_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/icon_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-xhdpi/icon_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/splash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-xhdpi/splash.jpg -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/icon_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-xxhdpi/icon_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/icon_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-xxhdpi/icon_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/icon_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-xxxhdpi/icon_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/icon_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/android/app/src/main/res/mipmap-xxxhdpi/icon_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /apk/flutterGithub.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/apk/flutterGithub.apk -------------------------------------------------------------------------------- /demo/code-structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/code-structure.png -------------------------------------------------------------------------------- /demo/demo1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/demo1.jpg -------------------------------------------------------------------------------- /demo/demo10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/demo10.jpg -------------------------------------------------------------------------------- /demo/demo11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/demo11.jpg -------------------------------------------------------------------------------- /demo/demo12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/demo12.jpg -------------------------------------------------------------------------------- /demo/demo2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/demo2.jpg -------------------------------------------------------------------------------- /demo/demo3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/demo3.jpg -------------------------------------------------------------------------------- /demo/demo4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/demo4.jpg -------------------------------------------------------------------------------- /demo/demo5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/demo5.jpg -------------------------------------------------------------------------------- /demo/demo6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/demo6.jpg -------------------------------------------------------------------------------- /demo/demo7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/demo7.jpg -------------------------------------------------------------------------------- /demo/demo8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/demo8.jpg -------------------------------------------------------------------------------- /demo/demo9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/demo9.jpg -------------------------------------------------------------------------------- /demo/gif-code.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/gif-code.gif -------------------------------------------------------------------------------- /demo/gif-login.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/gif-login.gif -------------------------------------------------------------------------------- /demo/gif-person.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/gif-person.gif -------------------------------------------------------------------------------- /demo/gif-readme.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/gif-readme.gif -------------------------------------------------------------------------------- /demo/gif-repo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/gif-repo.gif -------------------------------------------------------------------------------- /demo/gif-search.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/gif-search.gif -------------------------------------------------------------------------------- /demo/gif-theme.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/gif-theme.gif -------------------------------------------------------------------------------- /demo/github-tip.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/github-tip.jpeg -------------------------------------------------------------------------------- /demo/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/logo.png -------------------------------------------------------------------------------- /demo/qr_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/demo/qr_code.png -------------------------------------------------------------------------------- /fonts/fileiconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/fonts/fileiconfont.ttf -------------------------------------------------------------------------------- /fonts/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/fonts/iconfont.ttf -------------------------------------------------------------------------------- /imgs/avatar_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/imgs/avatar_default.png -------------------------------------------------------------------------------- /imgs/default_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/imgs/default_img.png -------------------------------------------------------------------------------- /imgs/github_login_ic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/imgs/github_login_ic.png -------------------------------------------------------------------------------- /imgs/login_back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/imgs/login_back.jpg -------------------------------------------------------------------------------- /imgs/repo_back0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/imgs/repo_back0.gif -------------------------------------------------------------------------------- /imgs/repo_back1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/imgs/repo_back1.jpeg -------------------------------------------------------------------------------- /imgs/repo_back2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/imgs/repo_back2.jpeg -------------------------------------------------------------------------------- /imgs/repo_back3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/imgs/repo_back3.jpeg -------------------------------------------------------------------------------- /imgs/repo_back4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/imgs/repo_back4.jpg -------------------------------------------------------------------------------- /imgs/repo_back5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/imgs/repo_back5.jpeg -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /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/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrHGJ/FlutterGithub/72e9876f843ff9bbd4b044e0caf3bac22f5dbf47/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 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | fluttergithub 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /jsons/RepoDaoBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hello-World", 3 | "full_name": "MrHGJ/FlutterGithub", 4 | "description": "This your first repo!", 5 | "language": "JavaScript", 6 | "forks_count": 9, 7 | "stargazers_count": 80, 8 | "open_issues_count": 2, 9 | "login": "octocat", 10 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 11 | "look_time": "" 12 | } -------------------------------------------------------------------------------- /jsons/branchBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dev/hgj", 3 | "protected": false 4 | } -------------------------------------------------------------------------------- /jsons/cacheConfigBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "enable": true, 3 | "maxAge": 1000, 4 | "maxCount": 100 5 | } -------------------------------------------------------------------------------- /jsons/commitContentBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "committer":"$commiterBean", 3 | "message":"Update README.md", 4 | "comment_count":0 5 | } -------------------------------------------------------------------------------- /jsons/commitDetailBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "sha": "d24e000336ae41d7f38b359c18703b65daefe449", 3 | "node_id": "MDY6Q29tbWl0MjYyMzQ2MzU0OmQyNGUwMDAzMzZhZTQxZDdmMzhiMzU5YzE4NzAzYjY1ZGFlZmU0NDk=", 4 | "commit": "$commitContentBean", 5 | "committer": "$userBean", 6 | "stats": "$commitDetailStatsBean", 7 | "files": "$[]commitDetailFileBean" 8 | } -------------------------------------------------------------------------------- /jsons/commitDetailFileBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "sha": "feec31812f476de5c8e2f765cbd7f99e738575bb", 3 | "filename": "jsons/repoBean.json", 4 | "status": "modified", 5 | "additions": 1, 6 | "deletions": 8, 7 | "changes": 9, 8 | "blob_url": "https://github.com/MrHGJ/FlutterGithub/blob/d24e000336ae41d7f38b359c18703b65daefe449/jsons/repoBean.json", 9 | "raw_url": "https://github.com/MrHGJ/FlutterGithub/raw/d24e000336ae41d7f38b359c18703b65daefe449/jsons/repoBean.json", 10 | "contents_url": "https://api.github.com/repos/MrHGJ/FlutterGithub/contents/jsons/repoBean.json?ref=d24e000336ae41d7f38b359c18703b65daefe449", 11 | "patch": "" 12 | } -------------------------------------------------------------------------------- /jsons/commitDetailStatsBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "total":919, 3 | "additions":789, 4 | "deletions":130 5 | } -------------------------------------------------------------------------------- /jsons/commitItemBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "sha":"34be3c87120650c72de7b109ea5af3b957c64a48", 3 | "commit":"$commitContentBean", 4 | "committer": "$userBean" 5 | } -------------------------------------------------------------------------------- /jsons/commiterBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"GitHub", 3 | "email":"noreply@github.com", 4 | "date":"2020-05-11T07:51:12Z" 5 | } -------------------------------------------------------------------------------- /jsons/eventBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "id":"12301745966", 3 | "type":"PushEvent", 4 | "actor":"$userBean", 5 | "repo":"$repoBean", 6 | "payload":"$eventPayloadBean", 7 | "public":true, 8 | "created_at":"2020-05-11T15:52:03Z" 9 | } -------------------------------------------------------------------------------- /jsons/eventCommitBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "sha":"e5ca8bf4c1b4efa0fe095455b2525f4865308e1e", 3 | "author":"$userBean", 4 | "message":"fix: 修复repos详情页滑动冲突问题", 5 | "distinct":true, 6 | "url":"https://api.github.com/repos/MrHGJ/FlutterGithub/commits/e5ca8bf4c1b4efa0fe095455b2525f4865308e1e" 7 | } -------------------------------------------------------------------------------- /jsons/eventPayloadBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "push_id": 5054242182, 3 | "size": 1, 4 | "distinct_size": 1, 5 | "ref": "refs/heads/dev/hgj", 6 | "head": "e5ca8bf4c1b4efa0fe095455b2525f4865308e1e", 7 | "before": "48a2664b1d8c7ff1ee2683ed6ecc63ad2809b365", 8 | "commits": "$[]eventCommitBean", 9 | "ref_type": "branch", 10 | "action": "started" 11 | } -------------------------------------------------------------------------------- /jsons/fileBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": ".gitignore", 3 | "path": ".gitignore", 4 | "sha": "ae1f1838ee7e87b1fa976268adc723e1020af38e", 5 | "size": 615, 6 | "url": "https://api.github.com/repos/MrHGJ/FlutterGithub/contents/.gitignore?ref=master", 7 | "html_url": "https://github.com/MrHGJ/FlutterGithub/blob/master/.gitignore", 8 | "git_url": "https://api.github.com/repos/MrHGJ/FlutterGithub/git/blobs/ae1f1838ee7e87b1fa976268adc723e1020af38e", 9 | "download_url": "https://raw.githubusercontent.com/MrHGJ/FlutterGithub/master/.gitignore", 10 | "type": "file" 11 | } -------------------------------------------------------------------------------- /jsons/profileBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": "$userBean", 3 | "token": "", 4 | "theme": 5678, 5 | "cache": "$cacheConfigBean", 6 | "lastLogin": "", 7 | "locale": "" 8 | } -------------------------------------------------------------------------------- /jsons/readmeBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "README.md", 3 | "path": "README.md", 4 | "sha": "c9d37206693b24a6389e5b525378dbfb87beba0e", 5 | "size": 255, 6 | "url": "https://api.github.com/repos/MrHGJ/FlutterGithub/contents/README.md?ref=master", 7 | "download_url": "https://raw.githubusercontent.com/MrHGJ/FlutterGithub/master/README.md", 8 | "type": "file", 9 | "content": "IyBGbHV0dGVyR2l0aHViCueUqGZsdXR0ZXLmhaLmhaLlrozmiJDkuIDkuKpn\naXRodWLlrqLmiLfnq6/vvIzku4XnlKjkuo7lrabkuaBmbHV0dGVy77yM5Yqf\n6IO96YCQ5q2l5re75Yqg5a6M5ZaE44CCCiMj6L+H56iL5LiACjEu5a6M5oiQ\n55m75b2V6aG16Z2i5ZKM5Yqf6IO9CjIu5a6M5oiQ5oiR55qE6aG555uu5YiX\n6KGoCiMj6L+H56iL5LqMCjEu5a6M5oiQdHJlbmTmjpLooYzmppwKIyPov4fn\nqIvkuIkKMS7lrozmiJDpobnnm67or6bmg4XpobUK\n", 10 | "encoding": "base64" 11 | } -------------------------------------------------------------------------------- /jsons/repoBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1296269, 3 | "name": "Hello-World", 4 | "full_name": "octocat/Hello-World", 5 | "owner": "$userBean", 6 | "parent": "$repoBean", 7 | "private": false, 8 | "description": "This your first repo!", 9 | "fork": false, 10 | "language": "JavaScript", 11 | "forks_count": 9, 12 | "stargazers_count": 80, 13 | "size": 108, 14 | "default_branch": "master", 15 | "open_issues_count": 2, 16 | "pushed_at": "2011-01-26T19:06:43Z", 17 | "created_at": "2011-01-26T19:01:12Z", 18 | "updated_at": "2011-01-26T19:14:43Z", 19 | "subscribers_count": 42 20 | } -------------------------------------------------------------------------------- /jsons/repoDetailBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 262346354, 3 | "node_id": "MDEwOlJlcG9zaXRvcnkyNjIzNDYzNTQ=", 4 | "name": "FlutterGithub", 5 | "full_name": "MrHGJ/FlutterGithub", 6 | "private": false, 7 | "owner": "$repoOwnerBean", 8 | "html_url": "https://github.com/MrHGJ/FlutterGithub", 9 | "description": "用flutter慢慢完成一个github客户端,仅用于学习flutter,功能逐步添加完善。", 10 | "fork": false, 11 | "created_at": "2020-05-08T14:34:19Z", 12 | "updated_at": "2020-05-10T04:15:12Z", 13 | "pushed_at": "2020-05-10T13:07:22Z", 14 | "homepage": "", 15 | "size": 104, 16 | "stargazers_count": 1, 17 | "watchers_count": 1, 18 | "language": "Dart", 19 | "has_issues": true, 20 | "has_projects": true, 21 | "has_downloads": true, 22 | "has_wiki": true, 23 | "has_pages": false, 24 | "forks_count": 0, 25 | "archived": false, 26 | "disabled": false, 27 | "open_issues_count": 0, 28 | "forks": 0, 29 | "open_issues": 0, 30 | "watchers": 1, 31 | "default_branch": "master", 32 | "network_count": 0, 33 | "subscribers_count": 0 34 | } -------------------------------------------------------------------------------- /jsons/repoOwnerBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "login": "MrHGJ", 3 | "id": 33540797, 4 | "node_id": "MDQ6VXNlcjMzNTQwNzk3", 5 | "avatar_url": "https://avatars3.githubusercontent.com/u/33540797?v=4", 6 | "gravatar_id": "", 7 | "type": "User", 8 | "site_admin": false 9 | } -------------------------------------------------------------------------------- /jsons/trendDevSubBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ink", 3 | "description": "🌈 React for interactive command-line apps", 4 | "url": "https://github.com/vadimdemedes/ink" 5 | } -------------------------------------------------------------------------------- /jsons/trendDeveloperBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "username": "philipwalton", 3 | "name": "Philip Walton", 4 | "url": "https://github.com/philipwalton", 5 | "avatar": "https://avatars0.githubusercontent.com/u/326742", 6 | "repo": "$trendDevSubBean" 7 | } -------------------------------------------------------------------------------- /jsons/trendRepoBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "nhsx", 3 | "name": "COVID-19-app-iOS-BETA", 4 | "avatar": "https://github.com/nhsx.png", 5 | "url": "https://github.com/nhsx/COVID-19-app-iOS-BETA", 6 | "description": "Source code of the Beta of the NHS COVID-19 iOS app", 7 | "language": "Objective-C", 8 | "languageColor": "#438eff", 9 | "stars": 541, 10 | "forks": 98, 11 | "currentPeriodStars": 312, 12 | "builtBy": [ 13 | { 14 | "username": "edent", 15 | "href": "https://github.com/edent", 16 | "avatar": "https://avatars2.githubusercontent.com/u/837136" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /jsons/userBean.json: -------------------------------------------------------------------------------- 1 | { 2 | "login": "octocat", 3 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 4 | "type": "User", 5 | "name": "monalisa octocat", 6 | "company": "GitHub", 7 | "blog": "https://github.com/blog", 8 | "location": "San Francisco", 9 | "email": "octocat@github.com", 10 | "hireable": false, 11 | "bio": "There once was...", 12 | "public_repos": 2, 13 | "followers": 20, 14 | "following": 0, 15 | "created_at": "2008-01-14T04:33:35Z", 16 | "updated_at": "2008-01-14T04:33:35Z", 17 | "total_private_repos": 100, 18 | "owned_private_repos": 100 19 | } -------------------------------------------------------------------------------- /l10n-arb/intl_messages.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@last_modified": "2020-05-21T11:14:01.431070", 3 | "title": "Flutter APP", 4 | "@title": { 5 | "description": "Title for the Demo application", 6 | "type": "text", 7 | "placeholders": {} 8 | }, 9 | "home": "Github", 10 | "@home": { 11 | "type": "text", 12 | "placeholders": {} 13 | }, 14 | "language": "Language", 15 | "@language": { 16 | "type": "text", 17 | "placeholders": {} 18 | }, 19 | "login": "Login", 20 | "@login": { 21 | "type": "text", 22 | "placeholders": {} 23 | }, 24 | "auto": "Auto", 25 | "@auto": { 26 | "type": "text", 27 | "placeholders": {} 28 | }, 29 | "setting": "Setting", 30 | "@setting": { 31 | "type": "text", 32 | "placeholders": {} 33 | }, 34 | "theme": "Theme", 35 | "@theme": { 36 | "type": "text", 37 | "placeholders": {} 38 | }, 39 | "noDescription": "No description yet !", 40 | "@noDescription": { 41 | "type": "text", 42 | "placeholders": {} 43 | }, 44 | "userName": "User Name", 45 | "@userName": { 46 | "type": "text", 47 | "placeholders": {} 48 | }, 49 | "userNameRequired": "User name required!", 50 | "@userNameRequired": { 51 | "type": "text", 52 | "placeholders": {} 53 | }, 54 | "password": "Password", 55 | "@password": { 56 | "type": "text", 57 | "placeholders": {} 58 | }, 59 | "passwordRequired": "Password required!", 60 | "@passwordRequired": { 61 | "type": "text", 62 | "placeholders": {} 63 | }, 64 | "userNameOrPasswordWrong": "User name or password is not correct!", 65 | "@userNameOrPasswordWrong": { 66 | "type": "text", 67 | "placeholders": {} 68 | }, 69 | "logout": "Logout", 70 | "@logout": { 71 | "type": "text", 72 | "placeholders": {} 73 | }, 74 | "logoutTip": "Are you sure you want to quit your current account?", 75 | "@logoutTip": { 76 | "type": "text", 77 | "placeholders": {} 78 | }, 79 | "yes": "yes", 80 | "@yes": { 81 | "type": "text", 82 | "placeholders": {} 83 | }, 84 | "cancel": "cancel", 85 | "@cancel": { 86 | "type": "text", 87 | "placeholders": {} 88 | }, 89 | "test": "test", 90 | "@test": { 91 | "type": "text", 92 | "placeholders": {} 93 | }, 94 | "trend": "trend", 95 | "@trend": { 96 | "type": "text", 97 | "placeholders": {} 98 | }, 99 | "repos": "repos", 100 | "@repos": { 101 | "type": "text", 102 | "placeholders": {} 103 | }, 104 | "developers": "developers", 105 | "@developers": { 106 | "type": "text", 107 | "placeholders": {} 108 | }, 109 | "info": "info", 110 | "@info": { 111 | "type": "text", 112 | "placeholders": {} 113 | }, 114 | "file": "file", 115 | "@file": { 116 | "type": "text", 117 | "placeholders": {} 118 | }, 119 | "commit": "commit", 120 | "@commit": { 121 | "type": "text", 122 | "placeholders": {} 123 | }, 124 | "activity": "activity", 125 | "@activity": { 126 | "type": "text", 127 | "placeholders": {} 128 | }, 129 | "size": "size", 130 | "@size": { 131 | "type": "text", 132 | "placeholders": {} 133 | }, 134 | "myStarRepos": "My Star", 135 | "@myStarRepos": { 136 | "type": "text", 137 | "placeholders": {} 138 | }, 139 | "myFollow": "My Follow", 140 | "@myFollow": { 141 | "type": "text", 142 | "placeholders": {} 143 | }, 144 | "thisProject": "This Project", 145 | "@thisProject": { 146 | "type": "text", 147 | "placeholders": {} 148 | }, 149 | "repositories": "repositories", 150 | "@repositories": { 151 | "type": "text", 152 | "placeholders": {} 153 | }, 154 | "footprint": "footprint", 155 | "@footprint": { 156 | "type": "text", 157 | "placeholders": {} 158 | }, 159 | "me": "me", 160 | "@me": { 161 | "type": "text", 162 | "placeholders": {} 163 | } 164 | } -------------------------------------------------------------------------------- /l10n-arb/intl_zh_CN.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@last_modified": "2019-04-30T15:02:44.753296", 3 | "title": "Github客户端", 4 | "@title": { 5 | "description": "Title for the Demo application", 6 | "type": "text", 7 | "placeholders": {} 8 | }, 9 | "home": "Github客户端", 10 | "@home": { 11 | "type": "text", 12 | "placeholders": {} 13 | }, 14 | "language": "语言", 15 | "@language": { 16 | "type": "text", 17 | "placeholders": {} 18 | }, 19 | "login": "登录", 20 | "@login": { 21 | "type": "text", 22 | "placeholders": {} 23 | }, 24 | "auto": "跟随系统", 25 | "@auto": { 26 | "type": "text", 27 | "placeholders": {} 28 | }, 29 | "setting": "设置", 30 | "@setting": { 31 | "type": "text", 32 | "placeholders": {} 33 | }, 34 | "theme": "换肤", 35 | "@theme": { 36 | "type": "text", 37 | "placeholders": {} 38 | }, 39 | "noDescription": "暂无描述!", 40 | "@noDescription": { 41 | "type": "text", 42 | "placeholders": {} 43 | }, 44 | "userName": "用户名", 45 | "@userName": { 46 | "type": "text", 47 | "placeholders": {} 48 | }, 49 | "userNameRequired": "用户名不能为空", 50 | "@userNameRequired": { 51 | "type": "text", 52 | "placeholders": {} 53 | }, 54 | "password": "密码", 55 | "@password": { 56 | "type": "text", 57 | "placeholders": {} 58 | }, 59 | "passwordRequired": "密码不能为空", 60 | "@passwordRequired": { 61 | "type": "text", 62 | "placeholders": {} 63 | }, 64 | "userNameOrPasswordWrong": "用户名或密码不正确", 65 | "@userNameOrPasswordWrong": { 66 | "type": "text", 67 | "placeholders": {} 68 | }, 69 | "logout": "注销", 70 | "@logout": { 71 | "type": "text", 72 | "placeholders": {} 73 | }, 74 | "logoutTip": "确定要退出当前账号吗?", 75 | "@logoutTip": { 76 | "type": "text", 77 | "placeholders": {} 78 | }, 79 | "yes": "确定", 80 | "@yes": { 81 | "type": "text", 82 | "placeholders": {} 83 | }, 84 | "cancel": "取消", 85 | "@cancel": { 86 | "type": "text", 87 | "placeholders": {} 88 | }, 89 | "test": "测试", 90 | "@test": { 91 | "type": "text", 92 | "placeholders": {} 93 | }, 94 | "trend": "排行榜", 95 | "@trend": { 96 | "type": "text", 97 | "placeholders": {} 98 | }, 99 | "repos": "项目", 100 | "@repos": { 101 | "type": "text", 102 | "placeholders": {} 103 | }, 104 | "developers": "开发者", 105 | "@developers": { 106 | "type": "text", 107 | "placeholders": {} 108 | }, 109 | "info": "简介", 110 | "@info": { 111 | "type": "text", 112 | "placeholders": {} 113 | }, 114 | "file": "文件", 115 | "@file": { 116 | "type": "text", 117 | "placeholders": {} 118 | }, 119 | "commit": "提交记录", 120 | "@commit": { 121 | "type": "text", 122 | "placeholders": {} 123 | }, 124 | "activity": "动态", 125 | "@activity": { 126 | "type": "text", 127 | "placeholders": {} 128 | }, 129 | "size": "大小", 130 | "@size": { 131 | "type": "text", 132 | "placeholders": {} 133 | }, 134 | "myStarRepos": "我star的项目", 135 | "@myStarRepos": { 136 | "type": "text", 137 | "placeholders": {} 138 | }, 139 | "myFollow": "我关注的人", 140 | "@myFollow": { 141 | "type": "text", 142 | "placeholders": {} 143 | }, 144 | "thisProject": "浏览本项目", 145 | "@thisProject": { 146 | "type": "text", 147 | "placeholders": {} 148 | }, 149 | "repositories": "仓库", 150 | "@repositories": { 151 | "type": "text", 152 | "placeholders": {} 153 | }, 154 | "footprint": "足迹", 155 | "@footprint": { 156 | "type": "text", 157 | "placeholders": {} 158 | }, 159 | "me": "我的", 160 | "@me": { 161 | "type": "text", 162 | "placeholders": {} 163 | } 164 | } -------------------------------------------------------------------------------- /lib/common/CacheObject.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:fluttergithub/common/Global.dart'; 5 | 6 | class CacheObject { 7 | CacheObject(this.response) 8 | : timeStamp = DateTime.now().millisecondsSinceEpoch; 9 | Response response; 10 | int timeStamp; //缓存创建时间 11 | @override 12 | bool operator ==(other) { 13 | return response.hashCode == other.hashCode; 14 | } 15 | 16 | //将请求uri作为缓存的key 17 | @override 18 | int get hashCode => response.realUri.hashCode; 19 | } 20 | 21 | class NetCache extends Interceptor { 22 | //为确保迭代器顺序和对象插入时间一致,我们使用LinkedHashMap 23 | var cache = LinkedHashMap(); 24 | 25 | @override 26 | Future onRequest(RequestOptions options) async { 27 | if (!Global.profile.cache.enable) return options; 28 | //refresh标记是否是"下拉刷新" 29 | bool refresh = options.extra["refresh"] == true; 30 | //如果是下拉刷新,先删除相关缓存 31 | if (refresh) { 32 | if (options.extra["list"] == true) { 33 | //若是列表,则只要url中包含当前path的缓存全部删除(简单实现,并不精准) 34 | cache.removeWhere((key, v) => key.contains(options.path)); 35 | } else { 36 | // 如果不是列表,则只删除uri相同的缓存 37 | cache.remove(options.uri.toString()); 38 | } 39 | return options; 40 | } 41 | if (options.extra["noCache"] != true && 42 | options.method.toLowerCase() == 'get') { 43 | String key = options.extra["cacheKey"] ?? options.uri.toString(); 44 | var ob = cache[key]; 45 | if (ob != null) { 46 | //若缓存未过期,则返回缓存内容 47 | if ((DateTime.now().millisecondsSinceEpoch - ob.timeStamp) / 1000 < 48 | Global.profile.cache.maxAge) { 49 | return cache[key].response; 50 | } else { 51 | //若已过期则删除缓存,继续向服务器请求 52 | cache.remove(key); 53 | } 54 | } 55 | } 56 | } 57 | 58 | @override 59 | Future onError(DioError err) { 60 | // 错误状态不缓存 61 | } 62 | 63 | @override 64 | Future onResponse(Response response) { 65 | //如果启用缓存,将返回结果保存到缓存中 66 | if (Global.profile.cache.enable) { 67 | _saveCache(response); 68 | } 69 | } 70 | 71 | _saveCache(Response object) { 72 | RequestOptions options = object.request; 73 | if (options.extra["noCache"] != true && 74 | options.method.toLowerCase() == "get") { 75 | // 如果缓存数量超过最大数量限制,则先移除最早的一条记录 76 | if (cache.length == Global.profile.cache.maxCount) { 77 | cache.remove(cache[cache.keys.first]); 78 | } 79 | String key = options.extra["cacheKey"] ?? options.uri.toString(); 80 | cache[key] = CacheObject(object); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/common/Global.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:fluttergithub/models/index.dart'; 5 | import 'package:fluttergithub/res/styles.dart'; 6 | import 'package:shared_preferences/shared_preferences.dart'; 7 | 8 | import 'CacheObject.dart'; 9 | import 'net/NetApi.dart'; 10 | 11 | class Global { 12 | static SharedPreferences prefs; 13 | static ProfileBean profile = ProfileBean(); 14 | 15 | //网络缓存对象 16 | static NetCache netCache = NetCache(); 17 | 18 | //可选主题列表 19 | static List get themes => MyColors.themesSwatch; 20 | 21 | //是否为release版本 22 | static bool get isRelease => bool.fromEnvironment("dart.vm.product"); 23 | 24 | //初始化全局信息,会在App启动时执行 25 | static Future init() async { 26 | WidgetsFlutterBinding.ensureInitialized(); 27 | prefs = await SharedPreferences.getInstance(); 28 | var _profile = prefs.getString("profile"); 29 | if (_profile != null) { 30 | try { 31 | profile = ProfileBean.fromJson(jsonDecode(_profile)); 32 | } catch (e) { 33 | print(e); 34 | } 35 | } 36 | //如果没有缓存策略,设置默认缓存策略 37 | profile.cache = profile.cache ?? CacheConfigBean() 38 | ..enable = true 39 | ..maxAge = 3600 40 | ..maxCount = 100; 41 | //初始化网络请求相关配置 42 | NetApi.init(); 43 | } 44 | 45 | //持久化Profile信息 46 | static saveProfile() => 47 | prefs.setString("profile", jsonEncode(profile.toJson())); 48 | } 49 | -------------------------------------------------------------------------------- /lib/common/constant/constant.dart: -------------------------------------------------------------------------------- 1 | class Constant{ 2 | /// //////////////////////////////////////常量////////////////////////////////////// /// 3 | static const BASE_URL = 'https://api.github.com'; 4 | 5 | /// //////////////////////////////////////SharedPreference////////////////////////////////////// /// 6 | static const USER_LOGIN_KEY = 'userLogin'; //这个是用户登录时输入框中填入的用户名 7 | static const PASSWORD_KEY = 'password'; 8 | static const USER_NAME_KEY = 'username'; //这个是用户登录成功后从后台获取的真正用户名 9 | static const BASIC_KEY = 'basic'; 10 | static const IS_LOGIN_KEY = 'isLogin'; 11 | static const SEARCH_HISTORY_KEY = 'search_history'; 12 | } -------------------------------------------------------------------------------- /lib/common/constant/ignore.dart: -------------------------------------------------------------------------------- 1 | class Ignore { 2 | //注册自己的OAuth Application,得到clientId和clientSecret,进行替换 3 | //注册地址: https://github.com/settings/applications/new 4 | static const String clientId = 'xxxxxxxxxxxxxxx'; 5 | static const String clientSecret ='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; 6 | } -------------------------------------------------------------------------------- /lib/common/delegate/index.dart: -------------------------------------------------------------------------------- 1 | export 'sliver_delegate.dart'; -------------------------------------------------------------------------------- /lib/common/delegate/sliver_delegate.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class MySliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate { 5 | MySliverPersistentHeaderDelegate( 6 | {@required this.minHeight, 7 | @required this.maxHeight, 8 | @required this.child}); 9 | 10 | final double minHeight; 11 | final double maxHeight; 12 | final Widget child; 13 | 14 | @override 15 | double get minExtent => minHeight; 16 | 17 | @override 18 | double get maxExtent => max(maxHeight, minHeight); 19 | 20 | @override 21 | Widget build( 22 | BuildContext context, double shrinkOffset, bool overlapsContent) { 23 | return new SizedBox.expand( 24 | child: child, 25 | ); 26 | } 27 | 28 | @override 29 | bool shouldRebuild(MySliverPersistentHeaderDelegate oldDelegate) { 30 | return maxHeight != oldDelegate.maxExtent || 31 | minHeight != oldDelegate.minExtent||child!=oldDelegate.child; 32 | } 33 | } -------------------------------------------------------------------------------- /lib/common/event/event_bus.dart: -------------------------------------------------------------------------------- 1 | //创建EventBus 2 | import 'package:event_bus/event_bus.dart'; 3 | 4 | EventBus eventBus = EventBus(); 5 | 6 | //切换分支事件 7 | class BranchSwitchEvent { 8 | String curBranch; 9 | 10 | BranchSwitchEvent(this.curBranch); 11 | } 12 | 13 | //搜索事件 14 | class SearchEvent { 15 | String searchWords; 16 | SearchEvent({this.searchWords}); 17 | } 18 | -------------------------------------------------------------------------------- /lib/common/myAvatar.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | Widget myAvatar(String url,{ 5 | double width = 30, 6 | double height, 7 | BoxFit fit, 8 | BorderRadius borderRadius, 9 | }){ 10 | var placeholder = Image.asset( 11 | "imgs/avatar_default.png", //头像占位图,加载过程中显示 12 | width: width, 13 | height: height 14 | ); 15 | return ClipRRect( 16 | borderRadius: borderRadius??BorderRadius.circular(2), 17 | child: CachedNetworkImage( 18 | imageUrl: url, 19 | width: width, 20 | height: height, 21 | fit: fit, 22 | placeholder: (context, url) =>placeholder, 23 | errorWidget: (context, url, error) =>placeholder, 24 | ), 25 | ); 26 | } -------------------------------------------------------------------------------- /lib/common/net/api.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluttergithub/common/constant/constant.dart'; 2 | 3 | class Api { 4 | //GitHub API OAuth认证 5 | static getAuthorizations() { 6 | return Constant.BASE_URL + "/authorizations"; 7 | } 8 | 9 | //用户登录获取用户信息 10 | static getUser(String username) { 11 | return Constant.BASE_URL + "/users/$username"; 12 | } 13 | 14 | //获取用户项目列表 15 | static getRepos(String userName) { 16 | return Constant.BASE_URL + "/users/$userName/repos"; 17 | } 18 | 19 | //获取项目详情 20 | static getRepoDetail(String repoOwner, String repoName) { 21 | return Constant.BASE_URL + "/repos/$repoOwner/$repoName"; 22 | } 23 | 24 | //Star仓库的人 get 25 | static getRepoStargazers(reposOwner, reposName) { 26 | return "${Constant.BASE_URL}/repos/$reposOwner/$reposName/stargazers"; 27 | } 28 | 29 | //Watch仓库的人 get 30 | static getRepoWatchers(reposOwner, reposName) { 31 | return "${Constant.BASE_URL}/repos/$reposOwner/$reposName/subscribers"; 32 | } 33 | 34 | //获取当前项目分支 35 | static getBranch(String repoOwner, String repoName) { 36 | return '${Constant.BASE_URL}/repos/$repoOwner/$repoName/branches'; 37 | } 38 | 39 | //获取Readme.md内容 40 | static getReadme(String repoOwner, String repoName) { 41 | return "${Constant.BASE_URL}/repos/$repoOwner/$repoName/readme"; 42 | } 43 | 44 | //获取commits列表 45 | static getRepoCommits(String repoOwner, String repoName) { 46 | return "${Constant.BASE_URL}/repos/$repoOwner/$repoName/commits"; 47 | } 48 | 49 | //获取commits详情列表 50 | static getRepoCommitsDetail(String repoOwner, String repoName, String sha) { 51 | return "${Constant.BASE_URL}/repos/$repoOwner/$repoName/commits/$sha"; 52 | } 53 | 54 | //获取项目动态列表 55 | static getRepoEvents(String repoOwner, String repoName) { 56 | return "${Constant.BASE_URL}/repos/$repoOwner/$repoName/events"; 57 | } 58 | 59 | //获取仓库下路径的内容 60 | static getRepoContent(String repoOwner, String repoName, String path) { 61 | return "${Constant.BASE_URL}/repos/$repoOwner/$repoName/contents/$path"; 62 | } 63 | 64 | //获取用户starred项目列表 65 | static getStarredRepos(String userName) { 66 | return "${Constant.BASE_URL}/users/$userName/starred"; 67 | } 68 | 69 | //获取用户动态列表 70 | static getUserEvents(String userName) { 71 | return "${Constant.BASE_URL}/users/$userName/events"; 72 | } 73 | 74 | //userName关注的人 75 | static getUserFollowing(userName) { 76 | return "${Constant.BASE_URL}/users/$userName/following?"; 77 | } 78 | 79 | //关注userName的人(粉丝) 80 | static getUserFollower(userName) { 81 | return "${Constant.BASE_URL}/users/$userName/followers?"; 82 | } 83 | 84 | ///搜索 85 | ///type: repositories(搜索仓库),users(搜索用户) 86 | ///searchWords: 搜索的关键词 87 | ///sort: 排序的方式,例如Best Match, Most Stars... 88 | ///order : desc(降序), asc(升序) 89 | static search(type, searchWords, sort, order) { 90 | return "${Constant.BASE_URL}/search/$type?q=$searchWords&sort=$sort&order=$order"; 91 | } 92 | 93 | //趋势项目 94 | static getTrendingRepos(String since, String language) { 95 | return "https://github-trending-api.now.sh/repositories?language=$language&since=$since"; 96 | } 97 | 98 | //趋势用户 99 | static getTrendDevelopers(String since, String language) { 100 | return 'https://github-trending-api.now.sh/developers?language=$language&since=$since'; 101 | } 102 | 103 | //判断当前项目是否star 104 | static isStarred(String repoOwner, String repoName) { 105 | return "${Constant.BASE_URL}/user/starred/$repoOwner/$repoName"; 106 | } 107 | 108 | //判断当前developer是否已follow 109 | static isFollowing(String developerName) { 110 | return "${Constant.BASE_URL}/user/following/$developerName"; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /lib/common/util/CommonUtil.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:fluttertoast/fluttertoast.dart'; 5 | 6 | void showToast(String msg) { 7 | Fluttertoast.showToast( 8 | msg: msg, 9 | toastLength: Toast.LENGTH_SHORT, 10 | gravity: ToastGravity.CENTER, 11 | timeInSecForIos: 1, 12 | backgroundColor: Colors.black.withAlpha(158), 13 | textColor: Colors.white, 14 | fontSize: 16.0); 15 | } 16 | 17 | void showLongToast(String msg) { 18 | Fluttertoast.showToast( 19 | msg: msg, 20 | toastLength: Toast.LENGTH_LONG, 21 | gravity: ToastGravity.CENTER, 22 | timeInSecForIos: 1, 23 | backgroundColor: Colors.black.withAlpha(158), 24 | textColor: Colors.white, 25 | fontSize: 16.0); 26 | } 27 | 28 | void showLoading(context, [String text]) { 29 | text = text ?? "Loading..."; 30 | showDialog( 31 | barrierDismissible: false, 32 | context: context, 33 | builder: (context) { 34 | return Center( 35 | child: Container( 36 | decoration: BoxDecoration( 37 | color: Colors.white, 38 | borderRadius: BorderRadius.circular(3.0), 39 | boxShadow: [ 40 | //阴影 41 | BoxShadow( 42 | color: Colors.black12, 43 | //offset: Offset(2.0,2.0), 44 | blurRadius: 10.0, 45 | ) 46 | ]), 47 | padding: EdgeInsets.all(16), 48 | margin: EdgeInsets.all(16), 49 | constraints: BoxConstraints(minHeight: 120, minWidth: 180), 50 | child: Column( 51 | mainAxisSize: MainAxisSize.min, 52 | mainAxisAlignment: MainAxisAlignment.center, 53 | children: [ 54 | SizedBox( 55 | height: 30, 56 | width: 30, 57 | child: CircularProgressIndicator( 58 | strokeWidth: 3, 59 | ), 60 | ), 61 | Padding( 62 | padding: const EdgeInsets.only(top: 20.0), 63 | child: Text( 64 | text, 65 | style: Theme.of(context).textTheme.body2, 66 | ), 67 | ), 68 | ], 69 | ), 70 | ), 71 | ); 72 | }); 73 | } 74 | 75 | //获取屏幕宽 76 | double getScreenWidth(BuildContext context) { 77 | return MediaQuery.of(context).size.width; 78 | } 79 | 80 | //获取屏幕高 81 | double getScreenHeight(BuildContext context) { 82 | return MediaQuery.of(context).size.height; 83 | } 84 | 85 | //Base64加密 86 | String encodeBase64(String data) { 87 | var content = utf8.encode(data); 88 | return base64Encode(content); 89 | } 90 | 91 | //Base64解密 92 | String decodeBase64(String data) { 93 | return utf8.decode(base64Decode(data)); 94 | } 95 | 96 | ///判断文件是否是Image类型 97 | const IMAGE_END = [".png", ".jpg", ".jpeg", ".gif", ".svg"]; 98 | 99 | isImageEnd(String path) { 100 | bool image = false; 101 | for (String item in IMAGE_END) { 102 | if (path.indexOf(item) + item.length == path.length) { 103 | image = true; 104 | } 105 | } 106 | return image; 107 | } 108 | 109 | //计算文件大小 110 | calculateFileSize(int fileByte) { 111 | if (fileByte < 1024) { 112 | return fileByte.toString() + " B"; 113 | } else if (fileByte < 1024 * 1024) { 114 | return keepDecimal(fileByte / 1024) + " KB"; 115 | } else if (fileByte < 1024 * 1024 * 1024) { 116 | return keepDecimal(fileByte / 1024 / 1024) + " M"; 117 | } else { 118 | return keepDecimal(fileByte / 1024 / 1024 / 1024) + " G"; 119 | } 120 | } 121 | 122 | //保留两位小数 123 | keepDecimal(double data) { 124 | String str = data.toString(); 125 | String decimal; 126 | if (str.contains('.')) { 127 | var arry = str.split('.'); 128 | decimal = arry[1].toString(); 129 | if (decimal.length > 2) { 130 | decimal = decimal.substring(0, 2); 131 | } 132 | return arry[0].toString() + '.' + decimal; 133 | } else { 134 | return str; 135 | } 136 | } 137 | 138 | ///跳转页面 139 | goToPage({@required BuildContext context, @required Widget page}) { 140 | Navigator.push( 141 | context, 142 | MaterialPageRoute( 143 | builder: (context) => page, 144 | ), 145 | ); 146 | } 147 | -------------------------------------------------------------------------------- /lib/common/util/RelativeDateUtil.dart: -------------------------------------------------------------------------------- 1 | class RelativeDateFormat { 2 | static final num ONE_MINUTE = 60000; 3 | static final num ONE_HOUR = 3600000; 4 | static final num ONE_DAY = 86400000; 5 | static final num ONE_WEEK = 604800000; 6 | 7 | static final String ONE_SECOND_AGO = " 秒前"; 8 | static final String ONE_MINUTE_AGO = " 分钟前"; 9 | static final String ONE_HOUR_AGO = " 小时前"; 10 | static final String ONE_DAY_AGO = " 天前"; 11 | static final String ONE_MONTH_AGO = " 月前"; 12 | static final String ONE_YEAR_AGO = " 年前"; 13 | 14 | //时间转换 15 | static String format(DateTime date) { 16 | num delta = 17 | DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch; 18 | if (delta < 1 * ONE_MINUTE) { 19 | num seconds = toSeconds(delta); 20 | return (seconds <= 0 ? 1 : seconds).toInt().toString() + ONE_SECOND_AGO; 21 | } 22 | if (delta < 45 * ONE_MINUTE) { 23 | num minutes = toMinutes(delta); 24 | return (minutes <= 0 ? 1 : minutes).toInt().toString() + ONE_MINUTE_AGO; 25 | } 26 | if (delta < 24 * ONE_HOUR) { 27 | num hours = toHours(delta); 28 | return (hours <= 0 ? 1 : hours).toInt().toString() + ONE_HOUR_AGO; 29 | } 30 | if (delta < 48 * ONE_HOUR) { 31 | return "昨天"; 32 | } 33 | if (delta < 30 * ONE_DAY) { 34 | num days = toDays(delta); 35 | return (days <= 0 ? 1 : days).toInt().toString() + ONE_DAY_AGO; 36 | } 37 | if (delta < 12 * 4 * ONE_WEEK) { 38 | num months = toMonths(delta); 39 | return (months <= 0 ? 1 : months).toInt().toString() + ONE_MONTH_AGO; 40 | } else { 41 | num years = toYears(delta); 42 | return (years <= 0 ? 1 : years).toInt().toString() + ONE_YEAR_AGO; 43 | } 44 | } 45 | 46 | static num toSeconds(num date) { 47 | return date / 1000; 48 | } 49 | 50 | static num toMinutes(num date) { 51 | return toSeconds(date) / 60; 52 | } 53 | 54 | static num toHours(num date) { 55 | return toMinutes(date) / 60; 56 | } 57 | 58 | static num toDays(num date) { 59 | return toHours(date) / 24; 60 | } 61 | 62 | static num toMonths(num date) { 63 | return toDays(date) / 30; 64 | } 65 | 66 | static num toYears(num date) { 67 | return toMonths(date) / 365; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/db/dao/repo_history_dao.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluttergithub/db/db_provider.dart'; 2 | import 'package:fluttergithub/models/index.dart'; 3 | import 'package:sqflite/sqflite.dart'; 4 | 5 | class RepoHistoryDao extends BaseDBProvider { 6 | ///表名 7 | final String name = "ReposHistory"; 8 | 9 | ///表主键字段 10 | final String columnId = "_id"; 11 | 12 | @override 13 | tableName() { 14 | return name; 15 | } 16 | 17 | @override 18 | tableSqlString() { 19 | return tableBaseString(name, columnId) + 20 | ''' 21 | name text, 22 | full_name text, 23 | description text, 24 | language text, 25 | forks_count integer, 26 | stargazers_count integer, 27 | open_issues_count integer, 28 | login text, 29 | avatar_url text, 30 | look_time text) 31 | '''; 32 | } 33 | 34 | /// 35 | /// 插入数据 36 | /// 37 | Future insert(RepoDaoBean repoData) async { 38 | Database db = await getDB(); 39 | bool repoIsExist = await getRepoIsExistByFullName(repoData.full_name); 40 | //如果repo已经存在,先删除 41 | if (repoIsExist) { 42 | await db.delete(name, 43 | where: "full_name = ?", whereArgs: [repoData.full_name]); 44 | } 45 | return await db.insert(name, repoData.toJson()); 46 | } 47 | 48 | /// 49 | /// 获取当前浏览的Repo是否存在 50 | /// 51 | Future getRepoIsExistByFullName(String fullName) async { 52 | Database db = await getDB(); 53 | List> maps = 54 | await db.query(name, where: "full_name = ?", whereArgs: [fullName]); 55 | if (maps.length > 0) { 56 | return true; 57 | } 58 | return false; 59 | } 60 | 61 | /// 62 | /// 获取所有的repo历史数据 63 | /// 64 | Future> getRepoHistoryList() async { 65 | Database db = await getDB(); 66 | List> maps = 67 | await db.query(name, orderBy: "look_time DESC"); 68 | if (maps.length > 0) { 69 | return maps.map((item) => RepoDaoBean.fromJson(item)).toList(); 70 | } 71 | return null; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/db/db_manager.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:sqflite/sqflite.dart'; 4 | 5 | ///数据库创建与关闭管理 6 | class DBManager { 7 | static const int _DB_VERSION = 1; //数据库版本 8 | static const String _DB_NAME = 'hgj_flutter_github.db'; //数据库名 9 | ///数据库实例 10 | static Database _database; 11 | 12 | ///初始化,打开数据库 13 | static init() async { 14 | var dbPath = await getDatabasesPath(); 15 | String path = dbPath + _DB_NAME; 16 | if (Platform.isIOS) { 17 | path = dbPath + '/' + _DB_NAME; 18 | } 19 | //打开数据库 20 | _database = await openDatabase(path, version: _DB_VERSION, 21 | onCreate: (Database db, int version) async { 22 | //TODO 可以在这里创建表 23 | }); 24 | } 25 | 26 | ///判断表是否存在 27 | static isTableExist(String tableName) async { 28 | await getCurrentDatabase(); 29 | String sql = 30 | "select * from Sqlite_master where type = 'table' and name = '$tableName'"; 31 | var res = await _database.rawQuery(sql); 32 | return res != null && res.length > 0; 33 | } 34 | 35 | ///获取当前数据库实例 36 | static Future getCurrentDatabase() async { 37 | if (_database == null) { 38 | await init(); 39 | } 40 | return _database; 41 | } 42 | 43 | ///关闭数据库 44 | static close() { 45 | _database?.close(); 46 | _database = null; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/db/db_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:sqflite/sqflite.dart'; 3 | 4 | import 'db_manager.dart'; 5 | 6 | /// 7 | /// 数据库表操作基类 8 | /// 9 | abstract class BaseDBProvider { 10 | bool isTableExist = false; 11 | 12 | //返回建表sql 13 | tableSqlString(); 14 | 15 | //返回建表的表名 16 | tableName(); 17 | 18 | tableBaseString(String name, String columnId) { 19 | return ''' 20 | create table $name ( 21 | $columnId integer primary key autoincrement, 22 | '''; 23 | } 24 | 25 | Future getDB() async { 26 | return await open(); 27 | } 28 | 29 | @mustCallSuper 30 | prepare(name, String createSql) async { 31 | isTableExist = await DBManager.isTableExist(name); 32 | if (!isTableExist) { 33 | Database db = await DBManager.getCurrentDatabase(); 34 | return await db.execute(createSql); 35 | } 36 | } 37 | 38 | open() async { 39 | if (!isTableExist) { 40 | await prepare(tableName(), tableSqlString()); 41 | } 42 | return await DBManager.getCurrentDatabase(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/l10n/localization_intl.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:intl/intl.dart'; 3 | import 'messages_all.dart'; //1 4 | 5 | class GmLocalizations { 6 | static Future load(Locale locale) { 7 | final String name = 8 | locale.countryCode.isEmpty ? locale.languageCode : locale.toString(); 9 | final String localeName = Intl.canonicalizedLocale(name); 10 | //2 11 | return initializeMessages(localeName).then((b) { 12 | Intl.defaultLocale = localeName; 13 | return new GmLocalizations(); 14 | }); 15 | } 16 | 17 | static GmLocalizations of(BuildContext context) { 18 | return Localizations.of(context, GmLocalizations); 19 | } 20 | 21 | String get title { 22 | return Intl.message( 23 | 'Flutter APP', 24 | name: 'title', 25 | desc: 'Title for the Demo application', 26 | ); 27 | } 28 | 29 | String get home => Intl.message('Github', name: 'home'); 30 | 31 | String get language => Intl.message('Language', name: 'language'); 32 | 33 | String get login => Intl.message('Login', name: 'login'); 34 | 35 | String get auto => Intl.message('Auto', name: 'auto'); 36 | 37 | String get setting => Intl.message('Setting', name: 'setting'); 38 | 39 | String get theme => Intl.message('Theme', name: 'theme'); 40 | 41 | String get noDescription => 42 | Intl.message('No description yet !', name: 'noDescription'); 43 | 44 | String get userName => Intl.message('User Name', name: 'userName'); 45 | String get userNameRequired => Intl.message("User name required!" , name: 'userNameRequired'); 46 | String get password => Intl.message('Password', name: 'password'); 47 | String get passwordRequired => Intl.message('Password required!', name: 'passwordRequired'); 48 | String get userNameOrPasswordWrong=>Intl.message('User name or password is not correct!', name: 'userNameOrPasswordWrong'); 49 | String get logout => Intl.message('Logout', name: 'logout'); 50 | String get logoutTip => Intl.message('Are you sure you want to quit your current account?', name: 'logoutTip'); 51 | String get yes => Intl.message('yes', name: 'yes'); 52 | String get cancel => Intl.message('cancel', name: 'cancel'); 53 | String get test => Intl.message('test', name: 'test'); 54 | String get trend => Intl.message('trend', name: 'trend'); 55 | String get repos => Intl.message('repos', name: 'repos'); 56 | String get developers => Intl.message('developers', name: 'developers'); 57 | String get info => Intl.message('info', name: 'info'); 58 | String get file => Intl.message('file', name: 'file'); 59 | String get commit => Intl.message('commit', name: 'commit'); 60 | String get activity => Intl.message('activity', name: 'activity'); 61 | String get size => Intl.message('size', name: 'size'); 62 | String get myStarRepos => Intl.message('My Star',name: 'myStarRepos'); 63 | String get myFollow => Intl.message('My Follow',name: 'myFollow'); 64 | String get thisProject =>Intl.message('This Project',name: 'thisProject'); 65 | String get repositories => Intl.message('repositories',name: 'repositories'); 66 | String get footprint => Intl.message('footprint',name: 'footprint'); 67 | String get me=>Intl.message('me',name: 'me'); 68 | 69 | } 70 | 71 | //Locale代理类 72 | class GmLocalizationsDelegate extends LocalizationsDelegate { 73 | const GmLocalizationsDelegate(); 74 | 75 | //是否支持某个Local 76 | @override 77 | bool isSupported(Locale locale) => ['en', 'zh'].contains(locale.languageCode); 78 | 79 | // Flutter会调用此类加载相应的Locale资源类 80 | @override 81 | Future load(Locale locale) { 82 | //3 83 | return GmLocalizations.load(locale); 84 | } 85 | 86 | // 当Localizations Widget重新build时,是否调用load重新加载Locale资源. 87 | @override 88 | bool shouldReload(GmLocalizationsDelegate old) => false; 89 | } 90 | -------------------------------------------------------------------------------- /lib/l10n/messages_all.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that looks up messages for specific locales by 3 | // delegating to the appropriate library. 4 | 5 | // Ignore issues from commonly used lints in this file. 6 | // ignore_for_file:implementation_imports, file_names, unnecessary_new 7 | // ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering 8 | // ignore_for_file:argument_type_not_assignable, invalid_assignment 9 | // ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases 10 | // ignore_for_file:comment_references 11 | 12 | import 'dart:async'; 13 | 14 | import 'package:intl/intl.dart'; 15 | import 'package:intl/message_lookup_by_library.dart'; 16 | import 'package:intl/src/intl_helpers.dart'; 17 | 18 | import 'messages_messages.dart' as messages_messages; 19 | import 'messages_zh_CN.dart' as messages_zh_cn; 20 | 21 | typedef Future LibraryLoader(); 22 | Map _deferredLibraries = { 23 | 'messages': () => new Future.value(null), 24 | 'zh_CN': () => new Future.value(null), 25 | }; 26 | 27 | MessageLookupByLibrary _findExact(String localeName) { 28 | switch (localeName) { 29 | case 'messages': 30 | return messages_messages.messages; 31 | case 'zh_CN': 32 | return messages_zh_cn.messages; 33 | default: 34 | return null; 35 | } 36 | } 37 | 38 | /// User programs should call this before using [localeName] for messages. 39 | Future initializeMessages(String localeName) async { 40 | var availableLocale = Intl.verifiedLocale( 41 | localeName, 42 | (locale) => _deferredLibraries[locale] != null, 43 | onFailure: (_) => null); 44 | if (availableLocale == null) { 45 | return new Future.value(false); 46 | } 47 | var lib = _deferredLibraries[availableLocale]; 48 | await (lib == null ? new Future.value(false) : lib()); 49 | initializeInternalMessageLookup(() => new CompositeMessageLookup()); 50 | messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); 51 | return new Future.value(true); 52 | } 53 | 54 | bool _messagesExistFor(String locale) { 55 | try { 56 | return _findExact(locale) != null; 57 | } catch (e) { 58 | return false; 59 | } 60 | } 61 | 62 | MessageLookupByLibrary _findGeneratedMessagesFor(String locale) { 63 | var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, 64 | onFailure: (_) => null); 65 | if (actualLocale == null) return null; 66 | return _findExact(actualLocale); 67 | } 68 | -------------------------------------------------------------------------------- /lib/l10n/messages_messages.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that provides messages for a messages locale. All the 3 | // messages from the main program should be duplicated here with the same 4 | // function name. 5 | 6 | // Ignore issues from commonly used lints in this file. 7 | // ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new 8 | // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering 9 | // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases 10 | // ignore_for_file:unused_import, file_names 11 | 12 | import 'package:intl/intl.dart'; 13 | import 'package:intl/message_lookup_by_library.dart'; 14 | 15 | final messages = new MessageLookup(); 16 | 17 | typedef String MessageIfAbsent(String messageStr, List args); 18 | 19 | class MessageLookup extends MessageLookupByLibrary { 20 | String get localeName => 'messages'; 21 | 22 | final messages = _notInlinedMessages(_notInlinedMessages); 23 | static _notInlinedMessages(_) => { 24 | "activity" : MessageLookupByLibrary.simpleMessage("activity"), 25 | "auto" : MessageLookupByLibrary.simpleMessage("Auto"), 26 | "cancel" : MessageLookupByLibrary.simpleMessage("cancel"), 27 | "commit" : MessageLookupByLibrary.simpleMessage("commit"), 28 | "developers" : MessageLookupByLibrary.simpleMessage("developers"), 29 | "file" : MessageLookupByLibrary.simpleMessage("file"), 30 | "footprint" : MessageLookupByLibrary.simpleMessage("footprint"), 31 | "home" : MessageLookupByLibrary.simpleMessage("Github"), 32 | "info" : MessageLookupByLibrary.simpleMessage("info"), 33 | "language" : MessageLookupByLibrary.simpleMessage("Language"), 34 | "login" : MessageLookupByLibrary.simpleMessage("Login"), 35 | "logout" : MessageLookupByLibrary.simpleMessage("Logout"), 36 | "logoutTip" : MessageLookupByLibrary.simpleMessage("Are you sure you want to quit your current account?"), 37 | "me" : MessageLookupByLibrary.simpleMessage("me"), 38 | "myFollow" : MessageLookupByLibrary.simpleMessage("My Follow"), 39 | "myStarRepos" : MessageLookupByLibrary.simpleMessage("My Star"), 40 | "noDescription" : MessageLookupByLibrary.simpleMessage("No description yet !"), 41 | "password" : MessageLookupByLibrary.simpleMessage("Password"), 42 | "passwordRequired" : MessageLookupByLibrary.simpleMessage("Password required!"), 43 | "repos" : MessageLookupByLibrary.simpleMessage("repos"), 44 | "repositories" : MessageLookupByLibrary.simpleMessage("repositories"), 45 | "setting" : MessageLookupByLibrary.simpleMessage("Setting"), 46 | "size" : MessageLookupByLibrary.simpleMessage("size"), 47 | "test" : MessageLookupByLibrary.simpleMessage("test"), 48 | "theme" : MessageLookupByLibrary.simpleMessage("Theme"), 49 | "thisProject" : MessageLookupByLibrary.simpleMessage("This Project"), 50 | "title" : MessageLookupByLibrary.simpleMessage("Flutter APP"), 51 | "trend" : MessageLookupByLibrary.simpleMessage("trend"), 52 | "userName" : MessageLookupByLibrary.simpleMessage("User Name"), 53 | "userNameOrPasswordWrong" : MessageLookupByLibrary.simpleMessage("User name or password is not correct!"), 54 | "userNameRequired" : MessageLookupByLibrary.simpleMessage("User name required!"), 55 | "yes" : MessageLookupByLibrary.simpleMessage("yes") 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /lib/l10n/messages_zh_CN.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that provides messages for a zh_CN locale. All the 3 | // messages from the main program should be duplicated here with the same 4 | // function name. 5 | 6 | // Ignore issues from commonly used lints in this file. 7 | // ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new 8 | // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering 9 | // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases 10 | // ignore_for_file:unused_import, file_names 11 | 12 | import 'package:intl/intl.dart'; 13 | import 'package:intl/message_lookup_by_library.dart'; 14 | 15 | final messages = new MessageLookup(); 16 | 17 | typedef String MessageIfAbsent(String messageStr, List args); 18 | 19 | class MessageLookup extends MessageLookupByLibrary { 20 | String get localeName => 'zh_CN'; 21 | 22 | final messages = _notInlinedMessages(_notInlinedMessages); 23 | static _notInlinedMessages(_) => { 24 | "activity" : MessageLookupByLibrary.simpleMessage("动态"), 25 | "auto" : MessageLookupByLibrary.simpleMessage("跟随系统"), 26 | "cancel" : MessageLookupByLibrary.simpleMessage("取消"), 27 | "commit" : MessageLookupByLibrary.simpleMessage("提交记录"), 28 | "developers" : MessageLookupByLibrary.simpleMessage("开发者"), 29 | "file" : MessageLookupByLibrary.simpleMessage("文件"), 30 | "footprint" : MessageLookupByLibrary.simpleMessage("足迹"), 31 | "home" : MessageLookupByLibrary.simpleMessage("Github客户端"), 32 | "info" : MessageLookupByLibrary.simpleMessage("简介"), 33 | "language" : MessageLookupByLibrary.simpleMessage("语言"), 34 | "login" : MessageLookupByLibrary.simpleMessage("登录"), 35 | "logout" : MessageLookupByLibrary.simpleMessage("注销"), 36 | "logoutTip" : MessageLookupByLibrary.simpleMessage("确定要退出当前账号吗?"), 37 | "me" : MessageLookupByLibrary.simpleMessage("我的"), 38 | "myFollow" : MessageLookupByLibrary.simpleMessage("我关注的人"), 39 | "myStarRepos" : MessageLookupByLibrary.simpleMessage("我star的项目"), 40 | "noDescription" : MessageLookupByLibrary.simpleMessage("暂无描述!"), 41 | "password" : MessageLookupByLibrary.simpleMessage("密码"), 42 | "passwordRequired" : MessageLookupByLibrary.simpleMessage("密码不能为空"), 43 | "repos" : MessageLookupByLibrary.simpleMessage("项目"), 44 | "repositories" : MessageLookupByLibrary.simpleMessage("仓库"), 45 | "setting" : MessageLookupByLibrary.simpleMessage("设置"), 46 | "size" : MessageLookupByLibrary.simpleMessage("大小"), 47 | "test" : MessageLookupByLibrary.simpleMessage("测试"), 48 | "theme" : MessageLookupByLibrary.simpleMessage("换肤"), 49 | "thisProject" : MessageLookupByLibrary.simpleMessage("浏览本项目"), 50 | "title" : MessageLookupByLibrary.simpleMessage("Github客户端"), 51 | "trend" : MessageLookupByLibrary.simpleMessage("排行榜"), 52 | "userName" : MessageLookupByLibrary.simpleMessage("用户名"), 53 | "userNameOrPasswordWrong" : MessageLookupByLibrary.simpleMessage("用户名或密码不正确"), 54 | "userNameRequired" : MessageLookupByLibrary.simpleMessage("用户名不能为空"), 55 | "yes" : MessageLookupByLibrary.simpleMessage("确定") 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_localizations/flutter_localizations.dart'; 3 | import 'routes/login_page.dart'; 4 | import 'package:provider/provider.dart'; 5 | import 'common/Global.dart'; 6 | import 'l10n/localization_intl.dart'; 7 | import 'routes/home_page.dart'; 8 | import 'routes/drawer/index.dart'; 9 | import 'states/index.dart'; 10 | 11 | void main() => Global.init().then((e) => runApp(MyApp())); 12 | 13 | class MyApp extends StatelessWidget { 14 | @override 15 | Widget build(BuildContext context) { 16 | return MultiProvider( 17 | providers: [ 18 | ChangeNotifierProvider.value(notifier: ThemeModel()), 19 | ChangeNotifierProvider.value(notifier: UserModel()), 20 | ChangeNotifierProvider.value(notifier: LocaleModel()), 21 | ], 22 | child: Consumer2(builder: 23 | (BuildContext context, themeModel, localeModel, Widget child) { 24 | return MaterialApp( 25 | theme: ThemeData( 26 | primaryColor: themeModel.theme, 27 | primaryColorDark: themeModel.theme), 28 | onGenerateTitle: (context) { 29 | return GmLocalizations.of(context).title; 30 | }, 31 | home: Provider.of(context).isLogin 32 | ? HomeRoute() 33 | : LoginRoute(), 34 | //应用主页 35 | locale: localeModel.getLocale(), 36 | //我们只支持美国英语和中文简体 37 | supportedLocales: [ 38 | const Locale('en', 'US'), // 美国英语 39 | const Locale('zh', 'CN'), // 中文简体 40 | //其它Locales 41 | ], 42 | localizationsDelegates: [ 43 | // 本地化的代理类 44 | GlobalMaterialLocalizations.delegate, 45 | GlobalWidgetsLocalizations.delegate, 46 | GmLocalizationsDelegate() 47 | ], 48 | localeResolutionCallback: 49 | (Locale _locale, Iterable supportedLocales) { 50 | if (localeModel.getLocale() != null) { 51 | //如果已经选定语言,则不跟随系统 52 | return localeModel.getLocale(); 53 | } else { 54 | Locale locale; 55 | //APP语言跟随系统语言,如果系统语言不是中文简体或美国英语, 56 | //则默认使用美国英语 57 | if (supportedLocales.contains(_locale)) { 58 | locale = _locale; 59 | } else { 60 | locale = Locale('en', 'US'); 61 | } 62 | return locale; 63 | } 64 | }, 65 | // 注册命名路由表 66 | routes: { 67 | "login": (context) => LoginRoute(), 68 | "themes": (context) => ThemeChangeRoute(), 69 | "language": (context) => LanguageRoute(), 70 | "test": (context) => TestRoute(), 71 | "trend": (context) => TrendRoute(), 72 | }, 73 | ); 74 | }), 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/models/RepoDaoBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluttergithub/models/index.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'RepoDaoBean.g.dart'; 5 | 6 | @JsonSerializable() 7 | class RepoDaoBean { 8 | RepoDaoBean(); 9 | 10 | String name; 11 | String full_name; 12 | String description; 13 | String language; 14 | num forks_count; 15 | num stargazers_count; 16 | num open_issues_count; 17 | String login; 18 | String avatar_url; 19 | String look_time; 20 | 21 | factory RepoDaoBean.fromJson(Map json) => 22 | _$RepoDaoBeanFromJson(json); 23 | 24 | Map toJson() => _$RepoDaoBeanToJson(this); 25 | 26 | fromRepoDetailBean(RepoDetailBean repoDetail) { 27 | RepoDaoBean repoDao = new RepoDaoBean(); 28 | repoDao.name = repoDetail.name; 29 | repoDao.full_name = repoDetail.full_name; 30 | repoDao.description = repoDetail.description; 31 | repoDao.language = repoDetail.language; 32 | repoDao.forks_count = repoDetail.forks_count; 33 | repoDao.stargazers_count = repoDetail.stargazers_count; 34 | repoDao.open_issues_count = repoDetail.open_issues_count; 35 | repoDao.login = repoDetail.owner.login; 36 | repoDao.avatar_url = repoDetail.owner.avatar_url; 37 | repoDao.look_time = DateTime.now().toString(); 38 | return repoDao; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/models/RepoDaoBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'RepoDaoBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | RepoDaoBean _$RepoDaoBeanFromJson(Map json) { 10 | return RepoDaoBean() 11 | ..name = json['name'] as String 12 | ..full_name = json['full_name'] as String 13 | ..description = json['description'] as String 14 | ..language = json['language'] as String 15 | ..forks_count = json['forks_count'] as num 16 | ..stargazers_count = json['stargazers_count'] as num 17 | ..open_issues_count = json['open_issues_count'] as num 18 | ..login = json['login'] as String 19 | ..avatar_url = json['avatar_url'] as String 20 | ..look_time = json['look_time'] as String; 21 | } 22 | 23 | Map _$RepoDaoBeanToJson(RepoDaoBean instance) => 24 | { 25 | 'name': instance.name, 26 | 'full_name': instance.full_name, 27 | 'description': instance.description, 28 | 'language': instance.language, 29 | 'forks_count': instance.forks_count, 30 | 'stargazers_count': instance.stargazers_count, 31 | 'open_issues_count': instance.open_issues_count, 32 | 'login': instance.login, 33 | 'avatar_url': instance.avatar_url, 34 | 'look_time': instance.look_time, 35 | }; 36 | -------------------------------------------------------------------------------- /lib/models/branchBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'branchBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class BranchBean { 7 | BranchBean(); 8 | 9 | String name; 10 | bool protected; 11 | 12 | factory BranchBean.fromJson(Map json) => _$BranchBeanFromJson(json); 13 | Map toJson() => _$BranchBeanToJson(this); 14 | } 15 | -------------------------------------------------------------------------------- /lib/models/branchBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'branchBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | BranchBean _$BranchBeanFromJson(Map json) { 10 | return BranchBean() 11 | ..name = json['name'] as String 12 | ..protected = json['protected'] as bool; 13 | } 14 | 15 | Map _$BranchBeanToJson(BranchBean instance) => 16 | { 17 | 'name': instance.name, 18 | 'protected': instance.protected, 19 | }; 20 | -------------------------------------------------------------------------------- /lib/models/cacheConfigBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'cacheConfigBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class CacheConfigBean { 7 | CacheConfigBean(); 8 | 9 | bool enable; 10 | num maxAge; 11 | num maxCount; 12 | 13 | factory CacheConfigBean.fromJson(Map json) => _$CacheConfigBeanFromJson(json); 14 | Map toJson() => _$CacheConfigBeanToJson(this); 15 | } 16 | -------------------------------------------------------------------------------- /lib/models/cacheConfigBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'cacheConfigBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CacheConfigBean _$CacheConfigBeanFromJson(Map json) { 10 | return CacheConfigBean() 11 | ..enable = json['enable'] as bool 12 | ..maxAge = json['maxAge'] as num 13 | ..maxCount = json['maxCount'] as num; 14 | } 15 | 16 | Map _$CacheConfigBeanToJson(CacheConfigBean instance) => 17 | { 18 | 'enable': instance.enable, 19 | 'maxAge': instance.maxAge, 20 | 'maxCount': instance.maxCount, 21 | }; 22 | -------------------------------------------------------------------------------- /lib/models/commitContentBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import "commiterBean.dart"; 3 | part 'commitContentBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class CommitContentBean { 7 | CommitContentBean(); 8 | 9 | CommiterBean committer; 10 | String message; 11 | num comment_count; 12 | 13 | factory CommitContentBean.fromJson(Map json) => _$CommitContentBeanFromJson(json); 14 | Map toJson() => _$CommitContentBeanToJson(this); 15 | } 16 | -------------------------------------------------------------------------------- /lib/models/commitContentBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'commitContentBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CommitContentBean _$CommitContentBeanFromJson(Map json) { 10 | return CommitContentBean() 11 | ..committer = json['committer'] == null 12 | ? null 13 | : CommiterBean.fromJson(json['committer'] as Map) 14 | ..message = json['message'] as String 15 | ..comment_count = json['comment_count'] as num; 16 | } 17 | 18 | Map _$CommitContentBeanToJson(CommitContentBean instance) => 19 | { 20 | 'committer': instance.committer, 21 | 'message': instance.message, 22 | 'comment_count': instance.comment_count, 23 | }; 24 | -------------------------------------------------------------------------------- /lib/models/commitDetailBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import "commitContentBean.dart"; 3 | import "userBean.dart"; 4 | import "commitDetailStatsBean.dart"; 5 | import "commitDetailFileBean.dart"; 6 | part 'commitDetailBean.g.dart'; 7 | 8 | @JsonSerializable() 9 | class CommitDetailBean { 10 | CommitDetailBean(); 11 | 12 | String sha; 13 | String node_id; 14 | CommitContentBean commit; 15 | UserBean committer; 16 | CommitDetailStatsBean stats; 17 | List files; 18 | 19 | factory CommitDetailBean.fromJson(Map json) => _$CommitDetailBeanFromJson(json); 20 | Map toJson() => _$CommitDetailBeanToJson(this); 21 | } 22 | -------------------------------------------------------------------------------- /lib/models/commitDetailBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'commitDetailBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CommitDetailBean _$CommitDetailBeanFromJson(Map json) { 10 | return CommitDetailBean() 11 | ..sha = json['sha'] as String 12 | ..node_id = json['node_id'] as String 13 | ..commit = json['commit'] == null 14 | ? null 15 | : CommitContentBean.fromJson(json['commit'] as Map) 16 | ..committer = json['committer'] == null 17 | ? null 18 | : UserBean.fromJson(json['committer'] as Map) 19 | ..stats = json['stats'] == null 20 | ? null 21 | : CommitDetailStatsBean.fromJson(json['stats'] as Map) 22 | ..files = (json['files'] as List) 23 | ?.map((e) => e == null 24 | ? null 25 | : CommitDetailFileBean.fromJson(e as Map)) 26 | ?.toList(); 27 | } 28 | 29 | Map _$CommitDetailBeanToJson(CommitDetailBean instance) => 30 | { 31 | 'sha': instance.sha, 32 | 'node_id': instance.node_id, 33 | 'commit': instance.commit, 34 | 'committer': instance.committer, 35 | 'stats': instance.stats, 36 | 'files': instance.files, 37 | }; 38 | -------------------------------------------------------------------------------- /lib/models/commitDetailFileBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'commitDetailFileBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class CommitDetailFileBean { 7 | CommitDetailFileBean(); 8 | 9 | String sha; 10 | String filename; 11 | String status; 12 | num additions; 13 | num deletions; 14 | num changes; 15 | String blob_url; 16 | String raw_url; 17 | String contents_url; 18 | String patch; 19 | 20 | factory CommitDetailFileBean.fromJson(Map json) => _$CommitDetailFileBeanFromJson(json); 21 | Map toJson() => _$CommitDetailFileBeanToJson(this); 22 | } 23 | -------------------------------------------------------------------------------- /lib/models/commitDetailFileBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'commitDetailFileBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CommitDetailFileBean _$CommitDetailFileBeanFromJson(Map json) { 10 | return CommitDetailFileBean() 11 | ..sha = json['sha'] as String 12 | ..filename = json['filename'] as String 13 | ..status = json['status'] as String 14 | ..additions = json['additions'] as num 15 | ..deletions = json['deletions'] as num 16 | ..changes = json['changes'] as num 17 | ..blob_url = json['blob_url'] as String 18 | ..raw_url = json['raw_url'] as String 19 | ..contents_url = json['contents_url'] as String 20 | ..patch = json['patch'] as String; 21 | } 22 | 23 | Map _$CommitDetailFileBeanToJson( 24 | CommitDetailFileBean instance) => 25 | { 26 | 'sha': instance.sha, 27 | 'filename': instance.filename, 28 | 'status': instance.status, 29 | 'additions': instance.additions, 30 | 'deletions': instance.deletions, 31 | 'changes': instance.changes, 32 | 'blob_url': instance.blob_url, 33 | 'raw_url': instance.raw_url, 34 | 'contents_url': instance.contents_url, 35 | 'patch': instance.patch, 36 | }; 37 | -------------------------------------------------------------------------------- /lib/models/commitDetailStatsBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'commitDetailStatsBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class CommitDetailStatsBean { 7 | CommitDetailStatsBean(); 8 | 9 | num total; 10 | num additions; 11 | num deletions; 12 | 13 | factory CommitDetailStatsBean.fromJson(Map json) => _$CommitDetailStatsBeanFromJson(json); 14 | Map toJson() => _$CommitDetailStatsBeanToJson(this); 15 | } 16 | -------------------------------------------------------------------------------- /lib/models/commitDetailStatsBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'commitDetailStatsBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CommitDetailStatsBean _$CommitDetailStatsBeanFromJson( 10 | Map json) { 11 | return CommitDetailStatsBean() 12 | ..total = json['total'] as num 13 | ..additions = json['additions'] as num 14 | ..deletions = json['deletions'] as num; 15 | } 16 | 17 | Map _$CommitDetailStatsBeanToJson( 18 | CommitDetailStatsBean instance) => 19 | { 20 | 'total': instance.total, 21 | 'additions': instance.additions, 22 | 'deletions': instance.deletions, 23 | }; 24 | -------------------------------------------------------------------------------- /lib/models/commitItemBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import "commitContentBean.dart"; 3 | import "userBean.dart"; 4 | part 'commitItemBean.g.dart'; 5 | 6 | @JsonSerializable() 7 | class CommitItemBean { 8 | CommitItemBean(); 9 | 10 | String sha; 11 | CommitContentBean commit; 12 | UserBean committer; 13 | 14 | factory CommitItemBean.fromJson(Map json) => _$CommitItemBeanFromJson(json); 15 | Map toJson() => _$CommitItemBeanToJson(this); 16 | } 17 | -------------------------------------------------------------------------------- /lib/models/commitItemBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'commitItemBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CommitItemBean _$CommitItemBeanFromJson(Map json) { 10 | return CommitItemBean() 11 | ..sha = json['sha'] as String 12 | ..commit = json['commit'] == null 13 | ? null 14 | : CommitContentBean.fromJson(json['commit'] as Map) 15 | ..committer = json['committer'] == null 16 | ? null 17 | : UserBean.fromJson(json['committer'] as Map); 18 | } 19 | 20 | Map _$CommitItemBeanToJson(CommitItemBean instance) => 21 | { 22 | 'sha': instance.sha, 23 | 'commit': instance.commit, 24 | 'committer': instance.committer, 25 | }; 26 | -------------------------------------------------------------------------------- /lib/models/commiterBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'commiterBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class CommiterBean { 7 | CommiterBean(); 8 | 9 | String name; 10 | String email; 11 | String date; 12 | 13 | factory CommiterBean.fromJson(Map json) => _$CommiterBeanFromJson(json); 14 | Map toJson() => _$CommiterBeanToJson(this); 15 | } 16 | -------------------------------------------------------------------------------- /lib/models/commiterBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'commiterBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CommiterBean _$CommiterBeanFromJson(Map json) { 10 | return CommiterBean() 11 | ..name = json['name'] as String 12 | ..email = json['email'] as String 13 | ..date = json['date'] as String; 14 | } 15 | 16 | Map _$CommiterBeanToJson(CommiterBean instance) => 17 | { 18 | 'name': instance.name, 19 | 'email': instance.email, 20 | 'date': instance.date, 21 | }; 22 | -------------------------------------------------------------------------------- /lib/models/eventBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import "userBean.dart"; 3 | import "repoBean.dart"; 4 | import "eventPayloadBean.dart"; 5 | part 'eventBean.g.dart'; 6 | 7 | @JsonSerializable() 8 | class EventBean { 9 | EventBean(); 10 | 11 | String id; 12 | String type; 13 | UserBean actor; 14 | RepoBean repo; 15 | EventPayloadBean payload; 16 | bool public; 17 | String created_at; 18 | 19 | factory EventBean.fromJson(Map json) => _$EventBeanFromJson(json); 20 | Map toJson() => _$EventBeanToJson(this); 21 | } 22 | -------------------------------------------------------------------------------- /lib/models/eventBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'eventBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | EventBean _$EventBeanFromJson(Map json) { 10 | return EventBean() 11 | ..id = json['id'] as String 12 | ..type = json['type'] as String 13 | ..actor = json['actor'] == null 14 | ? null 15 | : UserBean.fromJson(json['actor'] as Map) 16 | ..repo = json['repo'] == null 17 | ? null 18 | : RepoBean.fromJson(json['repo'] as Map) 19 | ..payload = json['payload'] == null 20 | ? null 21 | : EventPayloadBean.fromJson(json['payload'] as Map) 22 | ..public = json['public'] as bool 23 | ..created_at = json['created_at'] as String; 24 | } 25 | 26 | Map _$EventBeanToJson(EventBean instance) => { 27 | 'id': instance.id, 28 | 'type': instance.type, 29 | 'actor': instance.actor, 30 | 'repo': instance.repo, 31 | 'payload': instance.payload, 32 | 'public': instance.public, 33 | 'created_at': instance.created_at, 34 | }; 35 | -------------------------------------------------------------------------------- /lib/models/eventCommitBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import "userBean.dart"; 3 | part 'eventCommitBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class EventCommitBean { 7 | EventCommitBean(); 8 | 9 | String sha; 10 | UserBean author; 11 | String message; 12 | bool distinct; 13 | String url; 14 | 15 | factory EventCommitBean.fromJson(Map json) => _$EventCommitBeanFromJson(json); 16 | Map toJson() => _$EventCommitBeanToJson(this); 17 | } 18 | -------------------------------------------------------------------------------- /lib/models/eventCommitBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'eventCommitBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | EventCommitBean _$EventCommitBeanFromJson(Map json) { 10 | return EventCommitBean() 11 | ..sha = json['sha'] as String 12 | ..author = json['author'] == null 13 | ? null 14 | : UserBean.fromJson(json['author'] as Map) 15 | ..message = json['message'] as String 16 | ..distinct = json['distinct'] as bool 17 | ..url = json['url'] as String; 18 | } 19 | 20 | Map _$EventCommitBeanToJson(EventCommitBean instance) => 21 | { 22 | 'sha': instance.sha, 23 | 'author': instance.author, 24 | 'message': instance.message, 25 | 'distinct': instance.distinct, 26 | 'url': instance.url, 27 | }; 28 | -------------------------------------------------------------------------------- /lib/models/eventPayloadBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import "eventCommitBean.dart"; 3 | part 'eventPayloadBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class EventPayloadBean { 7 | EventPayloadBean(); 8 | 9 | num push_id; 10 | num size; 11 | num distinct_size; 12 | String ref; 13 | String head; 14 | String before; 15 | List commits; 16 | String ref_type; 17 | String action; 18 | 19 | factory EventPayloadBean.fromJson(Map json) => _$EventPayloadBeanFromJson(json); 20 | Map toJson() => _$EventPayloadBeanToJson(this); 21 | } 22 | -------------------------------------------------------------------------------- /lib/models/eventPayloadBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'eventPayloadBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | EventPayloadBean _$EventPayloadBeanFromJson(Map json) { 10 | return EventPayloadBean() 11 | ..push_id = json['push_id'] as num 12 | ..size = json['size'] as num 13 | ..distinct_size = json['distinct_size'] as num 14 | ..ref = json['ref'] as String 15 | ..head = json['head'] as String 16 | ..before = json['before'] as String 17 | ..commits = (json['commits'] as List) 18 | ?.map((e) => e == null 19 | ? null 20 | : EventCommitBean.fromJson(e as Map)) 21 | ?.toList() 22 | ..ref_type = json['ref_type'] as String 23 | ..action = json['action'] as String; 24 | } 25 | 26 | Map _$EventPayloadBeanToJson(EventPayloadBean instance) => 27 | { 28 | 'push_id': instance.push_id, 29 | 'size': instance.size, 30 | 'distinct_size': instance.distinct_size, 31 | 'ref': instance.ref, 32 | 'head': instance.head, 33 | 'before': instance.before, 34 | 'commits': instance.commits, 35 | 'ref_type': instance.ref_type, 36 | 'action': instance.action, 37 | }; 38 | -------------------------------------------------------------------------------- /lib/models/fileBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'fileBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class FileBean { 7 | FileBean(); 8 | 9 | String name; 10 | String path; 11 | String sha; 12 | num size; 13 | String url; 14 | String html_url; 15 | String git_url; 16 | String download_url; 17 | String type; 18 | 19 | factory FileBean.fromJson(Map json) => _$FileBeanFromJson(json); 20 | Map toJson() => _$FileBeanToJson(this); 21 | } 22 | -------------------------------------------------------------------------------- /lib/models/fileBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'fileBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | FileBean _$FileBeanFromJson(Map json) { 10 | return FileBean() 11 | ..name = json['name'] as String 12 | ..path = json['path'] as String 13 | ..sha = json['sha'] as String 14 | ..size = json['size'] as num 15 | ..url = json['url'] as String 16 | ..html_url = json['html_url'] as String 17 | ..git_url = json['git_url'] as String 18 | ..download_url = json['download_url'] as String 19 | ..type = json['type'] as String; 20 | } 21 | 22 | Map _$FileBeanToJson(FileBean instance) => { 23 | 'name': instance.name, 24 | 'path': instance.path, 25 | 'sha': instance.sha, 26 | 'size': instance.size, 27 | 'url': instance.url, 28 | 'html_url': instance.html_url, 29 | 'git_url': instance.git_url, 30 | 'download_url': instance.download_url, 31 | 'type': instance.type, 32 | }; 33 | -------------------------------------------------------------------------------- /lib/models/index.dart: -------------------------------------------------------------------------------- 1 | export 'fileBean.dart' ; 2 | export 'commitItemBean.dart' ; 3 | export 'profileBean.dart' ; 4 | export 'commitDetailBean.dart' ; 5 | export 'repoDetailBean.dart' ; 6 | export 'readmeBean.dart' ; 7 | export 'eventPayloadBean.dart' ; 8 | export 'commitDetailStatsBean.dart' ; 9 | export 'cacheConfigBean.dart' ; 10 | export 'trendDevSubBean.dart' ; 11 | export 'eventCommitBean.dart' ; 12 | export 'commitDetailFileBean.dart' ; 13 | export 'commiterBean.dart' ; 14 | export 'branchBean.dart' ; 15 | export 'trendDeveloperBean.dart' ; 16 | export 'userBean.dart' ; 17 | export 'trendRepoBean.dart' ; 18 | export 'eventBean.dart' ; 19 | export 'RepoDaoBean.dart' ; 20 | export 'repoOwnerBean.dart' ; 21 | export 'repoBean.dart' ; 22 | export 'commitContentBean.dart' ; 23 | -------------------------------------------------------------------------------- /lib/models/profileBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import "userBean.dart"; 3 | import "cacheConfigBean.dart"; 4 | part 'profileBean.g.dart'; 5 | 6 | @JsonSerializable() 7 | class ProfileBean { 8 | ProfileBean(); 9 | 10 | UserBean user; 11 | String token; 12 | num theme; 13 | CacheConfigBean cache; 14 | String lastLogin; 15 | String locale; 16 | 17 | factory ProfileBean.fromJson(Map json) => _$ProfileBeanFromJson(json); 18 | Map toJson() => _$ProfileBeanToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /lib/models/profileBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'profileBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ProfileBean _$ProfileBeanFromJson(Map json) { 10 | return ProfileBean() 11 | ..user = json['user'] == null 12 | ? null 13 | : UserBean.fromJson(json['user'] as Map) 14 | ..token = json['token'] as String 15 | ..theme = json['theme'] as num 16 | ..cache = json['cache'] == null 17 | ? null 18 | : CacheConfigBean.fromJson(json['cache'] as Map) 19 | ..lastLogin = json['lastLogin'] as String 20 | ..locale = json['locale'] as String; 21 | } 22 | 23 | Map _$ProfileBeanToJson(ProfileBean instance) => 24 | { 25 | 'user': instance.user, 26 | 'token': instance.token, 27 | 'theme': instance.theme, 28 | 'cache': instance.cache, 29 | 'lastLogin': instance.lastLogin, 30 | 'locale': instance.locale, 31 | }; 32 | -------------------------------------------------------------------------------- /lib/models/readmeBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'readmeBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class ReadmeBean { 7 | ReadmeBean(); 8 | 9 | String name; 10 | String path; 11 | String sha; 12 | num size; 13 | String url; 14 | String download_url; 15 | String type; 16 | String content; 17 | String encoding; 18 | 19 | factory ReadmeBean.fromJson(Map json) => _$ReadmeBeanFromJson(json); 20 | Map toJson() => _$ReadmeBeanToJson(this); 21 | } 22 | -------------------------------------------------------------------------------- /lib/models/readmeBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'readmeBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ReadmeBean _$ReadmeBeanFromJson(Map json) { 10 | return ReadmeBean() 11 | ..name = json['name'] as String 12 | ..path = json['path'] as String 13 | ..sha = json['sha'] as String 14 | ..size = json['size'] as num 15 | ..url = json['url'] as String 16 | ..download_url = json['download_url'] as String 17 | ..type = json['type'] as String 18 | ..content = json['content'] as String 19 | ..encoding = json['encoding'] as String; 20 | } 21 | 22 | Map _$ReadmeBeanToJson(ReadmeBean instance) => 23 | { 24 | 'name': instance.name, 25 | 'path': instance.path, 26 | 'sha': instance.sha, 27 | 'size': instance.size, 28 | 'url': instance.url, 29 | 'download_url': instance.download_url, 30 | 'type': instance.type, 31 | 'content': instance.content, 32 | 'encoding': instance.encoding, 33 | }; 34 | -------------------------------------------------------------------------------- /lib/models/repoBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import "userBean.dart"; 3 | part 'repoBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class RepoBean { 7 | RepoBean(); 8 | 9 | num id; 10 | String name; 11 | String full_name; 12 | UserBean owner; 13 | RepoBean parent; 14 | bool private; 15 | String description; 16 | bool fork; 17 | String language; 18 | num forks_count; 19 | num stargazers_count; 20 | num size; 21 | String default_branch; 22 | num open_issues_count; 23 | String pushed_at; 24 | String created_at; 25 | String updated_at; 26 | num subscribers_count; 27 | 28 | factory RepoBean.fromJson(Map json) => _$RepoBeanFromJson(json); 29 | Map toJson() => _$RepoBeanToJson(this); 30 | } 31 | -------------------------------------------------------------------------------- /lib/models/repoBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'repoBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | RepoBean _$RepoBeanFromJson(Map json) { 10 | return RepoBean() 11 | ..id = json['id'] as num 12 | ..name = json['name'] as String 13 | ..full_name = json['full_name'] as String 14 | ..owner = json['owner'] == null 15 | ? null 16 | : UserBean.fromJson(json['owner'] as Map) 17 | ..parent = json['parent'] == null 18 | ? null 19 | : RepoBean.fromJson(json['parent'] as Map) 20 | ..private = json['private'] as bool 21 | ..description = json['description'] as String 22 | ..fork = json['fork'] as bool 23 | ..language = json['language'] as String 24 | ..forks_count = json['forks_count'] as num 25 | ..stargazers_count = json['stargazers_count'] as num 26 | ..size = json['size'] as num 27 | ..default_branch = json['default_branch'] as String 28 | ..open_issues_count = json['open_issues_count'] as num 29 | ..pushed_at = json['pushed_at'] as String 30 | ..created_at = json['created_at'] as String 31 | ..updated_at = json['updated_at'] as String 32 | ..subscribers_count = json['subscribers_count'] as num; 33 | } 34 | 35 | Map _$RepoBeanToJson(RepoBean instance) => { 36 | 'id': instance.id, 37 | 'name': instance.name, 38 | 'full_name': instance.full_name, 39 | 'owner': instance.owner, 40 | 'parent': instance.parent, 41 | 'private': instance.private, 42 | 'description': instance.description, 43 | 'fork': instance.fork, 44 | 'language': instance.language, 45 | 'forks_count': instance.forks_count, 46 | 'stargazers_count': instance.stargazers_count, 47 | 'size': instance.size, 48 | 'default_branch': instance.default_branch, 49 | 'open_issues_count': instance.open_issues_count, 50 | 'pushed_at': instance.pushed_at, 51 | 'created_at': instance.created_at, 52 | 'updated_at': instance.updated_at, 53 | 'subscribers_count': instance.subscribers_count, 54 | }; 55 | -------------------------------------------------------------------------------- /lib/models/repoDetailBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import "repoOwnerBean.dart"; 3 | part 'repoDetailBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class RepoDetailBean { 7 | RepoDetailBean(); 8 | 9 | num id; 10 | String node_id; 11 | String name; 12 | String full_name; 13 | bool private; 14 | RepoOwnerBean owner; 15 | String html_url; 16 | String description; 17 | bool fork; 18 | String created_at; 19 | String updated_at; 20 | String pushed_at; 21 | String homepage; 22 | num size; 23 | num stargazers_count; 24 | num watchers_count; 25 | String language; 26 | bool has_issues; 27 | bool has_projects; 28 | bool has_downloads; 29 | bool has_wiki; 30 | bool has_pages; 31 | num forks_count; 32 | bool archived; 33 | bool disabled; 34 | num open_issues_count; 35 | num forks; 36 | num open_issues; 37 | num watchers; 38 | String default_branch; 39 | num network_count; 40 | num subscribers_count; 41 | 42 | factory RepoDetailBean.fromJson(Map json) => _$RepoDetailBeanFromJson(json); 43 | Map toJson() => _$RepoDetailBeanToJson(this); 44 | } 45 | -------------------------------------------------------------------------------- /lib/models/repoDetailBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'repoDetailBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | RepoDetailBean _$RepoDetailBeanFromJson(Map json) { 10 | return RepoDetailBean() 11 | ..id = json['id'] as num 12 | ..node_id = json['node_id'] as String 13 | ..name = json['name'] as String 14 | ..full_name = json['full_name'] as String 15 | ..private = json['private'] as bool 16 | ..owner = json['owner'] == null 17 | ? null 18 | : RepoOwnerBean.fromJson(json['owner'] as Map) 19 | ..html_url = json['html_url'] as String 20 | ..description = json['description'] as String 21 | ..fork = json['fork'] as bool 22 | ..created_at = json['created_at'] as String 23 | ..updated_at = json['updated_at'] as String 24 | ..pushed_at = json['pushed_at'] as String 25 | ..homepage = json['homepage'] as String 26 | ..size = json['size'] as num 27 | ..stargazers_count = json['stargazers_count'] as num 28 | ..watchers_count = json['watchers_count'] as num 29 | ..language = json['language'] as String 30 | ..has_issues = json['has_issues'] as bool 31 | ..has_projects = json['has_projects'] as bool 32 | ..has_downloads = json['has_downloads'] as bool 33 | ..has_wiki = json['has_wiki'] as bool 34 | ..has_pages = json['has_pages'] as bool 35 | ..forks_count = json['forks_count'] as num 36 | ..archived = json['archived'] as bool 37 | ..disabled = json['disabled'] as bool 38 | ..open_issues_count = json['open_issues_count'] as num 39 | ..forks = json['forks'] as num 40 | ..open_issues = json['open_issues'] as num 41 | ..watchers = json['watchers'] as num 42 | ..default_branch = json['default_branch'] as String 43 | ..network_count = json['network_count'] as num 44 | ..subscribers_count = json['subscribers_count'] as num; 45 | } 46 | 47 | Map _$RepoDetailBeanToJson(RepoDetailBean instance) => 48 | { 49 | 'id': instance.id, 50 | 'node_id': instance.node_id, 51 | 'name': instance.name, 52 | 'full_name': instance.full_name, 53 | 'private': instance.private, 54 | 'owner': instance.owner, 55 | 'html_url': instance.html_url, 56 | 'description': instance.description, 57 | 'fork': instance.fork, 58 | 'created_at': instance.created_at, 59 | 'updated_at': instance.updated_at, 60 | 'pushed_at': instance.pushed_at, 61 | 'homepage': instance.homepage, 62 | 'size': instance.size, 63 | 'stargazers_count': instance.stargazers_count, 64 | 'watchers_count': instance.watchers_count, 65 | 'language': instance.language, 66 | 'has_issues': instance.has_issues, 67 | 'has_projects': instance.has_projects, 68 | 'has_downloads': instance.has_downloads, 69 | 'has_wiki': instance.has_wiki, 70 | 'has_pages': instance.has_pages, 71 | 'forks_count': instance.forks_count, 72 | 'archived': instance.archived, 73 | 'disabled': instance.disabled, 74 | 'open_issues_count': instance.open_issues_count, 75 | 'forks': instance.forks, 76 | 'open_issues': instance.open_issues, 77 | 'watchers': instance.watchers, 78 | 'default_branch': instance.default_branch, 79 | 'network_count': instance.network_count, 80 | 'subscribers_count': instance.subscribers_count, 81 | }; 82 | -------------------------------------------------------------------------------- /lib/models/repoOwnerBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'repoOwnerBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class RepoOwnerBean { 7 | RepoOwnerBean(); 8 | 9 | String login; 10 | num id; 11 | String node_id; 12 | String avatar_url; 13 | String gravatar_id; 14 | String type; 15 | bool site_admin; 16 | 17 | factory RepoOwnerBean.fromJson(Map json) => _$RepoOwnerBeanFromJson(json); 18 | Map toJson() => _$RepoOwnerBeanToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /lib/models/repoOwnerBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'repoOwnerBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | RepoOwnerBean _$RepoOwnerBeanFromJson(Map json) { 10 | return RepoOwnerBean() 11 | ..login = json['login'] as String 12 | ..id = json['id'] as num 13 | ..node_id = json['node_id'] as String 14 | ..avatar_url = json['avatar_url'] as String 15 | ..gravatar_id = json['gravatar_id'] as String 16 | ..type = json['type'] as String 17 | ..site_admin = json['site_admin'] as bool; 18 | } 19 | 20 | Map _$RepoOwnerBeanToJson(RepoOwnerBean instance) => 21 | { 22 | 'login': instance.login, 23 | 'id': instance.id, 24 | 'node_id': instance.node_id, 25 | 'avatar_url': instance.avatar_url, 26 | 'gravatar_id': instance.gravatar_id, 27 | 'type': instance.type, 28 | 'site_admin': instance.site_admin, 29 | }; 30 | -------------------------------------------------------------------------------- /lib/models/trendDevSubBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'trendDevSubBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class TrendDevSubBean { 7 | TrendDevSubBean(); 8 | 9 | String name; 10 | String description; 11 | String url; 12 | 13 | factory TrendDevSubBean.fromJson(Map json) => _$TrendDevSubBeanFromJson(json); 14 | Map toJson() => _$TrendDevSubBeanToJson(this); 15 | } 16 | -------------------------------------------------------------------------------- /lib/models/trendDevSubBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'trendDevSubBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | TrendDevSubBean _$TrendDevSubBeanFromJson(Map json) { 10 | return TrendDevSubBean() 11 | ..name = json['name'] as String 12 | ..description = json['description'] as String 13 | ..url = json['url'] as String; 14 | } 15 | 16 | Map _$TrendDevSubBeanToJson(TrendDevSubBean instance) => 17 | { 18 | 'name': instance.name, 19 | 'description': instance.description, 20 | 'url': instance.url, 21 | }; 22 | -------------------------------------------------------------------------------- /lib/models/trendDeveloperBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import "trendDevSubBean.dart"; 3 | part 'trendDeveloperBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class TrendDeveloperBean { 7 | TrendDeveloperBean(); 8 | 9 | String username; 10 | String name; 11 | String url; 12 | String avatar; 13 | TrendDevSubBean repo; 14 | 15 | factory TrendDeveloperBean.fromJson(Map json) => _$TrendDeveloperBeanFromJson(json); 16 | Map toJson() => _$TrendDeveloperBeanToJson(this); 17 | } 18 | -------------------------------------------------------------------------------- /lib/models/trendDeveloperBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'trendDeveloperBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | TrendDeveloperBean _$TrendDeveloperBeanFromJson(Map json) { 10 | return TrendDeveloperBean() 11 | ..username = json['username'] as String 12 | ..name = json['name'] as String 13 | ..url = json['url'] as String 14 | ..avatar = json['avatar'] as String 15 | ..repo = json['repo'] == null 16 | ? null 17 | : TrendDevSubBean.fromJson(json['repo'] as Map); 18 | } 19 | 20 | Map _$TrendDeveloperBeanToJson(TrendDeveloperBean instance) => 21 | { 22 | 'username': instance.username, 23 | 'name': instance.name, 24 | 'url': instance.url, 25 | 'avatar': instance.avatar, 26 | 'repo': instance.repo, 27 | }; 28 | -------------------------------------------------------------------------------- /lib/models/trendRepoBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'trendRepoBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class TrendRepoBean { 7 | TrendRepoBean(); 8 | 9 | String author; 10 | String name; 11 | String avatar; 12 | String url; 13 | String description; 14 | String language; 15 | String languageColor; 16 | num stars; 17 | num forks; 18 | num currentPeriodStars; 19 | List builtBy; 20 | 21 | factory TrendRepoBean.fromJson(Map json) => _$TrendRepoBeanFromJson(json); 22 | Map toJson() => _$TrendRepoBeanToJson(this); 23 | } 24 | -------------------------------------------------------------------------------- /lib/models/trendRepoBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'trendRepoBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | TrendRepoBean _$TrendRepoBeanFromJson(Map json) { 10 | return TrendRepoBean() 11 | ..author = json['author'] as String 12 | ..name = json['name'] as String 13 | ..avatar = json['avatar'] as String 14 | ..url = json['url'] as String 15 | ..description = json['description'] as String 16 | ..language = json['language'] as String 17 | ..languageColor = json['languageColor'] as String 18 | ..stars = json['stars'] as num 19 | ..forks = json['forks'] as num 20 | ..currentPeriodStars = json['currentPeriodStars'] as num 21 | ..builtBy = json['builtBy'] as List; 22 | } 23 | 24 | Map _$TrendRepoBeanToJson(TrendRepoBean instance) => 25 | { 26 | 'author': instance.author, 27 | 'name': instance.name, 28 | 'avatar': instance.avatar, 29 | 'url': instance.url, 30 | 'description': instance.description, 31 | 'language': instance.language, 32 | 'languageColor': instance.languageColor, 33 | 'stars': instance.stars, 34 | 'forks': instance.forks, 35 | 'currentPeriodStars': instance.currentPeriodStars, 36 | 'builtBy': instance.builtBy, 37 | }; 38 | -------------------------------------------------------------------------------- /lib/models/userBean.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'userBean.g.dart'; 4 | 5 | @JsonSerializable() 6 | class UserBean { 7 | UserBean(); 8 | 9 | String login; 10 | String avatar_url; 11 | String type; 12 | String name; 13 | String company; 14 | String blog; 15 | String location; 16 | String email; 17 | bool hireable; 18 | String bio; 19 | num public_repos; 20 | num followers; 21 | num following; 22 | String created_at; 23 | String updated_at; 24 | num total_private_repos; 25 | num owned_private_repos; 26 | 27 | factory UserBean.fromJson(Map json) => _$UserBeanFromJson(json); 28 | Map toJson() => _$UserBeanToJson(this); 29 | } 30 | -------------------------------------------------------------------------------- /lib/models/userBean.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'userBean.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | UserBean _$UserBeanFromJson(Map json) { 10 | return UserBean() 11 | ..login = json['login'] as String 12 | ..avatar_url = json['avatar_url'] as String 13 | ..type = json['type'] as String 14 | ..name = json['name'] as String 15 | ..company = json['company'] as String 16 | ..blog = json['blog'] as String 17 | ..location = json['location'] as String 18 | ..email = json['email'] as String 19 | ..hireable = json['hireable'] as bool 20 | ..bio = json['bio'] as String 21 | ..public_repos = json['public_repos'] as num 22 | ..followers = json['followers'] as num 23 | ..following = json['following'] as num 24 | ..created_at = json['created_at'] as String 25 | ..updated_at = json['updated_at'] as String 26 | ..total_private_repos = json['total_private_repos'] as num 27 | ..owned_private_repos = json['owned_private_repos'] as num; 28 | } 29 | 30 | Map _$UserBeanToJson(UserBean instance) => { 31 | 'login': instance.login, 32 | 'avatar_url': instance.avatar_url, 33 | 'type': instance.type, 34 | 'name': instance.name, 35 | 'company': instance.company, 36 | 'blog': instance.blog, 37 | 'location': instance.location, 38 | 'email': instance.email, 39 | 'hireable': instance.hireable, 40 | 'bio': instance.bio, 41 | 'public_repos': instance.public_repos, 42 | 'followers': instance.followers, 43 | 'following': instance.following, 44 | 'created_at': instance.created_at, 45 | 'updated_at': instance.updated_at, 46 | 'total_private_repos': instance.total_private_repos, 47 | 'owned_private_repos': instance.owned_private_repos, 48 | }; 49 | -------------------------------------------------------------------------------- /lib/res/back_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttergithub/res/styles.dart'; 4 | 5 | ///项目详情页头部背景图片,为了适应主题色 6 | Widget getBackImage(BuildContext context){ 7 | Color primaryColor= Theme.of(context).primaryColor; 8 | int index=0; 9 | List imgPath = [ 10 | 'imgs/repo_back0.gif', 11 | 'imgs/repo_back1.jpeg', 12 | 'imgs/repo_back2.jpeg', 13 | 'imgs/repo_back3.jpeg', 14 | 'imgs/repo_back4.jpg', 15 | 'imgs/repo_back5.jpeg', 16 | ]; 17 | if(primaryColor==MyColors.themesSwatch[0]){ 18 | 19 | } 20 | for(int i =0;i createState() { 17 | return _EventPushListPageState(); 18 | } 19 | } 20 | 21 | class _EventPushListPageState extends State { 22 | @override 23 | Widget build(BuildContext context) { 24 | var branch = widget.payload.ref.substring(11); 25 | return Scaffold( 26 | appBar: AppBar( 27 | title: Text('PushEvent List'), 28 | ), 29 | body: ListView.builder( 30 | itemCount: widget.payload.commits.length, 31 | itemBuilder: (BuildContext context, int index) { 32 | return GestureDetector( 33 | child: MyCard( 34 | child: Column( 35 | crossAxisAlignment: CrossAxisAlignment.start, 36 | children: [ 37 | Row( 38 | children: [ 39 | Expanded( 40 | child: Text( 41 | widget.payload.commits[index].author.name, 42 | style: TextStyle( 43 | fontSize: 20, fontWeight: FontWeight.bold), 44 | ), 45 | ), 46 | Padding( 47 | padding: EdgeInsets.only(right: 5.0), 48 | child: Icon( 49 | Icons.bookmark, 50 | color: Theme.of(context).primaryColor, 51 | size: 16, 52 | ), 53 | ), 54 | Text( 55 | widget.payload.commits[index].sha.substring(0, 7), 56 | style: TextStyle(color: Theme.of(context).primaryColor), 57 | ) 58 | ], 59 | ), 60 | Padding( 61 | padding: EdgeInsets.only(top: 5), 62 | child: Text( 63 | widget.payload.commits[index].message, 64 | style: TextStyle(color: Colors.grey), 65 | ), 66 | ) 67 | ], 68 | ), 69 | ), 70 | onTap: () { 71 | goToPage( 72 | context: context, 73 | page: CommitDetailPage(widget.repoOwner, widget.repoName, 74 | widget.payload.commits[index].sha, branch)); 75 | }, 76 | ); 77 | }, 78 | ), 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/routes/FileView/code_detail_fullscreen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:webview_flutter/webview_flutter.dart'; 3 | 4 | class CodeDetailFullScreen extends StatelessWidget{ 5 | CodeDetailFullScreen(this.data); 6 | final String data; 7 | @override 8 | Widget build(BuildContext context) { 9 | return Scaffold(body: WebView( 10 | initialUrl: data, 11 | javascriptMode: JavascriptMode.unrestricted, 12 | ),); 13 | } 14 | } -------------------------------------------------------------------------------- /lib/routes/FileView/code_detail_web.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:common_utils/common_utils.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:fluttergithub/common/net/NetApi.dart'; 7 | import 'package:fluttergithub/common/util/html_utils.dart'; 8 | import 'package:fluttergithub/routes/FileView/code_detail_fullscreen.dart'; 9 | import 'package:webview_flutter/webview_flutter.dart'; 10 | 11 | class CodeDetailWeb extends StatefulWidget { 12 | CodeDetailWeb( 13 | {this.repoOwner, 14 | this.repoName, 15 | @required this.title, 16 | this.filePath, 17 | this.htmlData, 18 | this.branch}); 19 | 20 | final String repoOwner; 21 | final String repoName; 22 | final String title; 23 | final String filePath; 24 | final String branch; 25 | final String htmlData; 26 | 27 | @override 28 | State createState() { 29 | return _CodeDetailWebState(); 30 | } 31 | } 32 | 33 | class _CodeDetailWebState extends State { 34 | String codeData; 35 | 36 | Future _getNetData() async { 37 | if (widget.htmlData != null) { 38 | return widget.htmlData; 39 | } 40 | var response = await NetApi(context).getReposCodeFileContent( 41 | widget.repoOwner, widget.repoName, widget.filePath, 42 | branch: widget.branch); 43 | String data = HtmlUtils.resolveHtmlFile(response, "java"); 44 | String url = new Uri.dataFromString(data, 45 | mimeType: 'text/html', encoding: Encoding.getByName("utf-8")) 46 | .toString(); 47 | return url; 48 | } 49 | 50 | @override 51 | Widget build(BuildContext context) { 52 | return Scaffold( 53 | appBar: AppBar( 54 | title: Text(widget.title), 55 | actions: [ 56 | IconButton( 57 | icon: Icon(Icons.fullscreen), 58 | onPressed: () { 59 | Navigator.push( 60 | context, 61 | MaterialPageRoute( 62 | builder: (context) => CodeDetailFullScreen(codeData))); 63 | }, 64 | ) 65 | ], 66 | ), 67 | body: FutureBuilder( 68 | future: _getNetData(), 69 | builder: (BuildContext context, AsyncSnapshot snapshot) { 70 | // 请求已结束 71 | if (snapshot.connectionState == ConnectionState.done) { 72 | if (snapshot.hasError) { 73 | // 请求失败,显示错误 74 | return Center( 75 | child: Text("Error: ${snapshot.error}"), 76 | ); 77 | } else { 78 | // 请求成功,显示数据 79 | codeData = snapshot.data; 80 | return WebView( 81 | initialUrl: snapshot.data, 82 | javascriptMode: JavascriptMode.unrestricted, 83 | ); 84 | } 85 | } else { 86 | // 请求未结束,显示loading 87 | return Center( 88 | child: CircularProgressIndicator(), 89 | ); 90 | } 91 | }, 92 | ), 93 | ); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/routes/FileView/photo_view_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_spinkit/flutter_spinkit.dart'; 3 | import 'package:photo_view/photo_view.dart'; 4 | 5 | class PhotoViewPage extends StatelessWidget { 6 | PhotoViewPage(this.picUrl); 7 | 8 | final String picUrl; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | appBar: AppBar( 14 | title: Text("照片查看"), 15 | ), 16 | body: Container( 17 | color: Colors.black87, 18 | child: PhotoView( 19 | imageProvider: NetworkImage(picUrl), 20 | loadingChild: Container( 21 | child: new Stack( 22 | children: [ 23 | new Center( 24 | child: new Image.asset('imgs/default_img.png', 25 | height: 180.0, width: 180.0)), 26 | new Center( 27 | child: new SpinKitFoldingCube( 28 | color: Colors.white30, size: 60.0)), 29 | ], 30 | ), 31 | ), 32 | ), 33 | ), 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/routes/SearchPage/search_page_repos.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttergithub/common/event/event_bus.dart'; 4 | import 'package:fluttergithub/common/net/NetApi.dart'; 5 | import 'package:fluttergithub/common/util/ListViewUtil.dart'; 6 | import 'package:fluttergithub/models/index.dart'; 7 | import 'package:fluttergithub/widgets/RepoItem.dart'; 8 | import 'package:fluttergithub/widgets/myWidgets/no_data_or_no_net.dart'; 9 | 10 | class SearchPageRepos extends StatefulWidget { 11 | SearchPageRepos({@required this.searchWords}); 12 | 13 | final String searchWords; 14 | 15 | @override 16 | State createState() { 17 | return _SearchPageReposState(); 18 | } 19 | } 20 | 21 | class _SearchPageReposState extends State 22 | with AutomaticKeepAliveClientMixin { 23 | var curSearchWords; 24 | 25 | //搜索订阅事件 26 | var _searchChangeSubscription; 27 | 28 | //这个key用来在不是手动下拉,而是点击某个button或其它操作时,代码直接触发下拉刷新 29 | final GlobalKey refreshIndicatorKey = 30 | new GlobalKey(); 31 | 32 | @override 33 | bool get wantKeepAlive => true; 34 | 35 | @override 36 | void initState() { 37 | super.initState(); 38 | curSearchWords = widget.searchWords; 39 | //订阅搜索事件 40 | _searchChangeSubscription = eventBus.on().listen((event) { 41 | setState(() { 42 | curSearchWords = event.searchWords; 43 | }); 44 | //refreshIndicatorKey.currentState.show(); //更新文件列表 45 | }); 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return MediaQuery.removePadding( 51 | removeTop: true, 52 | context: context, 53 | child: MyInfiniteListView( 54 | refreshKey: refreshIndicatorKey, 55 | emptyBuilder: (VoidCallback refresh, BuildContext context) { 56 | return listNoDataView(refresh, context); 57 | }, 58 | onRetrieveData: (int page, List items, bool refresh) async { 59 | var data = await NetApi(context).searchRepos( 60 | keyWords: curSearchWords, 61 | queryParameters: { 62 | 'page': page, 63 | 'page_size': 30, 64 | }, 65 | ); 66 | //把请求到的新数据添加到items中 67 | items.addAll(data); 68 | // 如果接口返回的数量等于'page_size',则认为还有数据,反之则认为最后一页 69 | return data.length == 30; 70 | }, 71 | itemBuilder: (List list, int index, BuildContext ctx) { 72 | // 项目信息列表项 73 | return RepoItem(list[index]); 74 | }, 75 | ), 76 | ); 77 | } 78 | 79 | @override 80 | void dispose() { 81 | _searchChangeSubscription.cancel(); 82 | super.dispose(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/routes/SearchPage/search_page_users.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttergithub/common/event/event_bus.dart'; 4 | import 'package:fluttergithub/common/net/NetApi.dart'; 5 | import 'package:fluttergithub/common/util/ListViewUtil.dart'; 6 | import 'package:fluttergithub/models/index.dart'; 7 | import 'package:fluttergithub/widgets/PersonItem.dart'; 8 | import 'package:fluttergithub/widgets/RepoItem.dart'; 9 | import 'package:fluttergithub/widgets/myWidgets/no_data_or_no_net.dart'; 10 | 11 | class SearchPageUsers extends StatefulWidget { 12 | SearchPageUsers({@required this.searchWords}); 13 | final String searchWords; 14 | 15 | @override 16 | State createState() { 17 | return _SearchPageUsersState(); 18 | } 19 | } 20 | 21 | class _SearchPageUsersState extends State 22 | with AutomaticKeepAliveClientMixin { 23 | var curSearchWords; 24 | 25 | //搜索订阅事件 26 | var _searchChangeSubscription; 27 | 28 | //这个key用来在不是手动下拉,而是点击某个button或其它操作时,代码直接触发下拉刷新 29 | final GlobalKey refreshIndicatorKey = 30 | new GlobalKey(); 31 | 32 | @override 33 | bool get wantKeepAlive => true; 34 | 35 | @override 36 | void initState() { 37 | super.initState(); 38 | curSearchWords = widget.searchWords; 39 | //订阅搜索事件 40 | _searchChangeSubscription = eventBus.on().listen((event) { 41 | setState(() { 42 | curSearchWords = event.searchWords; 43 | }); 44 | //refreshIndicatorKey.currentState.show(); //更新文件列表 45 | }); 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return MediaQuery.removePadding( 51 | removeTop: true, 52 | context: context, 53 | child: MyInfiniteListView( 54 | refreshKey: refreshIndicatorKey, 55 | emptyBuilder: (VoidCallback refresh, BuildContext context){ 56 | return listNoDataView(refresh, context); 57 | }, 58 | onRetrieveData: (int page, List items, bool refresh) async { 59 | var data = await NetApi(context).searchUsers( 60 | keyWords: curSearchWords, 61 | queryParameters: { 62 | 'page': page, 63 | 'page_size': 30, 64 | }, 65 | ); 66 | //把请求到的新数据添加到items中 67 | items.addAll(data); 68 | // 如果接口返回的数量等于'page_size',则认为还有数据,反之则认为最后一页 69 | return data.length == 30; 70 | }, 71 | itemBuilder: (List list, int index, BuildContext ctx) { 72 | // 项目信息列表项 73 | return PersonItem(personData:list[index]); 74 | }, 75 | ), 76 | ); 77 | } 78 | 79 | @override 80 | void dispose() { 81 | _searchChangeSubscription.cancel(); 82 | super.dispose(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/routes/drawer/follow_list_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttergithub/widgets/personDetail/follow_person_list.dart'; 4 | 5 | class FollowListPage extends StatefulWidget{ 6 | FollowListPage(this.title,this.userName); 7 | final String userName; 8 | final String title; 9 | @override 10 | State createState() { 11 | return _FollowListPageStat(); 12 | } 13 | } 14 | class _FollowListPageStat extends State{ 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar( 19 | title: Text(widget.title), 20 | ), 21 | body: PersonFollowList(personName: widget.userName,isFollowing: true,), 22 | ); 23 | } 24 | } -------------------------------------------------------------------------------- /lib/routes/drawer/index.dart: -------------------------------------------------------------------------------- 1 | export 'language_page.dart'; 2 | export 'test_page.dart'; 3 | export 'theme_change_page.dart'; 4 | export 'trend/trend_page.dart'; -------------------------------------------------------------------------------- /lib/routes/drawer/language_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttergithub/l10n/localization_intl.dart'; 4 | import 'package:fluttergithub/states/LocaleModel.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class LanguageRoute extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | var color = Theme.of(context).primaryColor; 11 | var localeModel = Provider.of(context); 12 | var gm = GmLocalizations.of(context); 13 | //构建语言选择项 14 | Widget _buildLanguageItem(String lan, value) { 15 | return ListTile( 16 | title: Text( 17 | lan, 18 | // 对APP当前语言进行高亮显示 19 | style: TextStyle(color: localeModel.locale == value ? color : null), 20 | ), 21 | trailing: 22 | localeModel.locale == value ? Icon(Icons.done, color: color) : null, 23 | onTap: () { 24 | // 更新locale后MaterialApp会重新build 25 | localeModel.locale = value; 26 | }, 27 | ); 28 | } 29 | 30 | return Scaffold( 31 | appBar: AppBar( 32 | title: Text(gm.language), 33 | ), 34 | body: ListView( 35 | children: [ 36 | _buildLanguageItem("中文简体", "zh_CN"), 37 | _buildLanguageItem("English", "en_US"), 38 | _buildLanguageItem(gm.auto, null), 39 | ], 40 | ), 41 | ); 42 | } 43 | } -------------------------------------------------------------------------------- /lib/routes/drawer/test_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fluttergithub/common/util/CommonUtil.dart'; 3 | import 'package:fluttergithub/routes/drawer/index.dart'; 4 | import 'package:fluttergithub/routes/drawer/trend/trend_page.dart'; 5 | import 'package:fluttergithub/routes/search_page.dart'; 6 | import 'package:fluttergithub/states/index.dart'; 7 | 8 | import '../person_detail_page.dart'; 9 | import '../repo_list_page.dart'; 10 | import 'repos_history_page.dart'; 11 | 12 | class TestRoute extends StatefulWidget{ 13 | @override 14 | State createState() { 15 | return _TestRouteState(); 16 | } 17 | } 18 | 19 | class _TestRouteState extends State{ 20 | var _position = 0; 21 | final iconsMap = { 22 | "仓库": Icons.mode_comment, 23 | "关注": Icons.star, 24 | "热度": Icons.favorite, 25 | "我的": Icons.person, 26 | }; 27 | List get iconsMapKey => iconsMap.keys.toList(); 28 | var activeColor = Colors.white; 29 | List _pageList = List(); 30 | 31 | 32 | void initState() { 33 | super.initState(); 34 | _pageList.add(RepoListRoute(title: "我的仓库",personName: UserModel().user.login,isStarredRepoList: false,)); 35 | _pageList.add(RepoHistoryPage()); 36 | _pageList.add(TrendRoute()); 37 | _pageList.add(PersonDetailPage(name:UserModel().user.login)); 38 | } 39 | 40 | @override 41 | Widget build(BuildContext context) { 42 | return Scaffold( 43 | floatingActionButton: FloatingActionButton( 44 | onPressed: () => goToPage(context: context, page: SearchPage()), 45 | child: Icon(Icons.search), 46 | backgroundColor: Theme.of(context).primaryColor, 47 | ), 48 | bottomNavigationBar: _buildBottomAppBar(), 49 | floatingActionButtonLocation:FloatingActionButtonLocation.centerDocked, 50 | body: IndexedStack( 51 | index: _position, 52 | children: _pageList, 53 | ), 54 | ); 55 | } 56 | Widget _buildBottomAppBar() { 57 | return BottomAppBar( 58 | elevation: 1, 59 | shape: CircularNotchedRectangle(), 60 | notchMargin: 5, 61 | color: Theme.of(context).primaryColor, 62 | child: Row( 63 | mainAxisAlignment: MainAxisAlignment.spaceAround, 64 | children: iconsMapKey.asMap().keys.map((i) => _buildChild(i)).toList() 65 | ..insertAll( 2, [SizedBox(width: 30)])), 66 | ); 67 | } 68 | 69 | Widget _buildChild(int i) { 70 | var active = i == _position; 71 | return Padding( 72 | padding: const EdgeInsets.all(8.0), 73 | child: GestureDetector( 74 | onTap: () => setState(() => _position = i), 75 | child: Wrap( 76 | direction: Axis.vertical, 77 | alignment: WrapAlignment.center, 78 | children: [ 79 | Icon( 80 | iconsMap[iconsMapKey[i]], 81 | color: active ? activeColor : Colors.white60, 82 | size: 25, 83 | ), 84 | Text(iconsMapKey[i], 85 | style: TextStyle( 86 | color: active ? activeColor : Colors.white60, fontSize: 14)), 87 | ], 88 | ), 89 | ), 90 | ); 91 | } 92 | 93 | } -------------------------------------------------------------------------------- /lib/routes/drawer/theme_change_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fluttergithub/common/Global.dart'; 3 | import 'package:fluttergithub/l10n/localization_intl.dart'; 4 | import 'package:fluttergithub/states/ThemeModel.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class ThemeChangeRoute extends StatelessWidget{ 8 | @override 9 | Widget build(BuildContext context) { 10 | return Scaffold( 11 | appBar: AppBar( 12 | title: Text(GmLocalizations.of(context).theme), 13 | ), 14 | body: ListView( //显示主题色块 15 | children: Global.themes.map((e) { 16 | return GestureDetector( 17 | child: Padding( 18 | padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 16), 19 | child: Container( 20 | color: e, 21 | height: 40, 22 | ), 23 | ), 24 | onTap: () { 25 | //主题更新后,MaterialApp会重新build 26 | Provider.of(context).theme = e; 27 | }, 28 | ); 29 | }).toList(), 30 | ), 31 | ); 32 | } 33 | } -------------------------------------------------------------------------------- /lib/routes/drawer/trend/trend_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttergithub/common/util/CommonUtil.dart'; 4 | import 'package:fluttergithub/l10n/localization_intl.dart'; 5 | import 'package:fluttergithub/routes/drawer/trend/trend_page_developers.dart'; 6 | import 'package:fluttergithub/routes/drawer/trend/trend_page_repos.dart'; 7 | import 'package:fluttergithub/widgets/MyDrawer.dart'; 8 | 9 | class TrendRoute extends StatefulWidget { 10 | @override 11 | State createState() { 12 | return _TrendRouteState(); 13 | } 14 | } 15 | 16 | class _TrendRouteState extends State 17 | with SingleTickerProviderStateMixin { 18 | PageController _pageController = PageController(); 19 | TabController _tabController; 20 | String _language; //选择的开发语言 21 | String _since; //选择的时间段(日、周、月) 22 | int _currentIndex = 0; //当前选择的tab 23 | bool _isChange = false; 24 | 25 | @override 26 | void initState() { 27 | super.initState(); 28 | _since = 'daily'; 29 | _tabController = new TabController(length: 2, vsync: this); 30 | } 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | var gm = GmLocalizations.of(context); 35 | final List choices = List(2); 36 | choices[0] = Choice(title: gm.repos); 37 | choices[1] = Choice(title: gm.developers); 38 | return Scaffold( 39 | appBar: AppBar( 40 | centerTitle: true, 41 | title: TabBar( 42 | controller: _tabController, 43 | labelPadding: EdgeInsets.all(8.0), 44 | labelStyle: TextStyle(fontSize: 20), 45 | unselectedLabelStyle: TextStyle(fontSize: 16), 46 | isScrollable: true, 47 | indicatorColor: Colors.white, 48 | tabs: choices 49 | .map((Choice choice) => Tab( 50 | text: choice.title, 51 | )) 52 | .toList(), 53 | onTap: (index) { 54 | _currentIndex = index; 55 | _pageController.jumpTo(getScreenWidth(context) * index); 56 | if (_isChange) { 57 | _isChange = false; 58 | if (_currentIndex == 0) { 59 | //refreshReposData 60 | } else { 61 | //refreshDevelopersData 62 | } 63 | } 64 | }, 65 | ), 66 | ), 67 | drawer: MyDrawer(), 68 | body: PageView( 69 | controller: _pageController, 70 | children: [ 71 | TrendReposRoute(), 72 | TrendDevelopersRoute(), 73 | ], 74 | onPageChanged: (index){ 75 | _currentIndex = index; 76 | _tabController.animateTo(index); 77 | if(_isChange){ 78 | //refreshData 79 | } 80 | }, 81 | ), 82 | ); 83 | } 84 | } 85 | 86 | class Choice { 87 | const Choice({this.title}); 88 | 89 | final String title; 90 | } 91 | -------------------------------------------------------------------------------- /lib/routes/drawer/trend/trend_page_developers.dart: -------------------------------------------------------------------------------- 1 | import 'package:flukit/flukit.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttergithub/common/net/NetApi.dart'; 4 | import 'package:fluttergithub/models/index.dart'; 5 | import 'package:fluttergithub/widgets/TrendDevelopersItem.dart'; 6 | import 'package:fluttergithub/widgets/myWidgets/no_data_or_no_net.dart'; 7 | 8 | class TrendDevelopersRoute extends StatefulWidget { 9 | @override 10 | State createState() { 11 | return _TrendDevelopersRouteState(); 12 | } 13 | } 14 | 15 | class _TrendDevelopersRouteState extends State 16 | with AutomaticKeepAliveClientMixin { 17 | //导航栏切换时保持原有状态 18 | @override 19 | bool get wantKeepAlive => true; 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return InfiniteListView( 24 | emptyBuilder: (VoidCallback refresh, BuildContext context){ 25 | return listNoDataView(refresh, context); 26 | }, 27 | onRetrieveData: 28 | (int page, List items, bool refresh) async { 29 | var data = await NetApi(context).getTrendingDevelopers("daily", ""); 30 | items.addAll(data); 31 | return data.length == 20; 32 | }, 33 | itemBuilder: (List list, int index, BuildContext ctx) { 34 | return TrendDevelopersItem(list[index]); 35 | }, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/routes/drawer/trend/trend_page_repos.dart: -------------------------------------------------------------------------------- 1 | import 'package:flukit/flukit.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttergithub/common/net/NetApi.dart'; 4 | import 'package:fluttergithub/models/index.dart'; 5 | import 'package:fluttergithub/widgets/TrendReposItem.dart'; 6 | import 'package:fluttergithub/widgets/myWidgets/no_data_or_no_net.dart'; 7 | 8 | class TrendReposRoute extends StatefulWidget { 9 | @override 10 | State createState() { 11 | return _TrendReposRouteState(); 12 | } 13 | } 14 | 15 | class _TrendReposRouteState extends State 16 | with AutomaticKeepAliveClientMixin { 17 | //导航栏切换时保持原有状态 18 | @override 19 | bool get wantKeepAlive => true; 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return InfiniteListView( 24 | emptyBuilder: (VoidCallback refresh, BuildContext context){ 25 | return listNoDataView(refresh, context); 26 | }, 27 | onRetrieveData: 28 | (int page, List items, bool refresh) async { 29 | var data = await NetApi(context).getTrendingRepos("daily", ""); 30 | items.addAll(data); 31 | return data.length == 20; 32 | }, 33 | itemBuilder: (List list, int index, BuildContext ctx) { 34 | return TrendReposItem(list[index]); 35 | }, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/routes/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttergithub/res/icons.dart'; 4 | import 'package:fluttergithub/common/util/CommonUtil.dart'; 5 | import 'package:fluttergithub/l10n/localization_intl.dart'; 6 | import 'package:fluttergithub/routes/search_page.dart'; 7 | import 'package:fluttergithub/states/UserModel.dart'; 8 | 9 | import 'drawer/repos_history_page.dart'; 10 | import 'drawer/trend/trend_page.dart'; 11 | import 'person_detail_page.dart'; 12 | import 'repo_list_page.dart'; 13 | 14 | class HomeRoute extends StatefulWidget { 15 | @override 16 | State createState() { 17 | return _HomeRouteState(); 18 | } 19 | } 20 | 21 | class _HomeRouteState extends State { 22 | var _position = 0; 23 | var iconsMap; 24 | 25 | List iconsMapKey; 26 | var activeColor = Colors.white; 27 | List _pageList = List(); 28 | 29 | void initState() { 30 | super.initState(); 31 | 32 | _pageList.add(RepoListRoute( 33 | title: "我的仓库", 34 | personName: UserModel().user.login, 35 | isStarredRepoList: false, 36 | )); 37 | _pageList.add(RepoHistoryPage()); 38 | _pageList.add(TrendRoute()); 39 | _pageList.add(PersonDetailPage(name: UserModel().user.login)); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | var gm = GmLocalizations.of(context); 45 | iconsMap = { 46 | gm.repositories: MyIcons.repos, 47 | gm.footprint: MyIcons.footprint_fill, 48 | gm.trend: MyIcons.trend, 49 | gm.me: Icons.person, 50 | }; 51 | DateTime _lastPressedAt; //上次点击时间 52 | return Scaffold( 53 | floatingActionButton: FloatingActionButton( 54 | onPressed: () => goToPage(context: context, page: SearchPage()), 55 | child: Icon(Icons.search), 56 | backgroundColor: Theme.of(context).primaryColor, 57 | ), 58 | bottomNavigationBar: _buildBottomAppBar(), 59 | floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, 60 | body: WillPopScope( 61 | child: IndexedStack( 62 | index: _position, 63 | children: _pageList, 64 | ), 65 | onWillPop: () async { 66 | if (_lastPressedAt == null || 67 | DateTime.now().difference(_lastPressedAt) > Duration(seconds: 2)) { 68 | //两次点击间隔超过1s则重新计时 69 | _lastPressedAt = DateTime.now(); 70 | showToast("再返回一次退出应用"); 71 | return false; 72 | } 73 | return true; 74 | }, 75 | ), 76 | ); 77 | } 78 | Widget _buildBottomAppBar() { 79 | iconsMapKey=iconsMap.keys.toList(); 80 | return BottomAppBar( 81 | elevation: 1, 82 | shape: CircularNotchedRectangle(), 83 | notchMargin: 5, 84 | color: Theme.of(context).primaryColor, 85 | child: Row( 86 | mainAxisAlignment: MainAxisAlignment.spaceAround, 87 | children: iconsMapKey.asMap().keys.map((i) => _buildChild(i)).toList() 88 | ..insertAll(2, [SizedBox(width: 30)])), 89 | ); 90 | } 91 | 92 | Widget _buildChild(int i) { 93 | var active = i == _position; 94 | return GestureDetector( 95 | child: Padding( 96 | padding: const EdgeInsets.symmetric(vertical:8.0,horizontal: 8.0), 97 | child: Wrap( 98 | direction: Axis.vertical, 99 | alignment: WrapAlignment.center, 100 | crossAxisAlignment: WrapCrossAlignment.center, 101 | children: [ 102 | Icon( 103 | iconsMap[iconsMapKey[i]], 104 | color: active ? activeColor : Colors.white60, 105 | size: 25, 106 | ), 107 | Text(iconsMapKey[i], 108 | style: TextStyle( 109 | color: active ? activeColor : Colors.white60, 110 | fontSize: 12)), 111 | ], 112 | ), 113 | ), 114 | onTap: () => setState(() => _position = i), 115 | ); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /lib/routes/repo_list_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flukit/flukit.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:fluttergithub/common/net/NetApi.dart'; 5 | import 'package:fluttergithub/models/index.dart'; 6 | import 'package:fluttergithub/widgets/MyDrawer.dart'; 7 | import 'package:fluttergithub/widgets/RepoItem.dart'; 8 | import 'package:fluttergithub/widgets/myWidgets/no_data_or_no_net.dart'; 9 | 10 | //repo列表,包含titleBar, 11 | class RepoListRoute extends StatefulWidget { 12 | RepoListRoute( 13 | {@required this.title, 14 | @required this.personName, 15 | @required this.isStarredRepoList}); 16 | 17 | final String title; 18 | final String personName; 19 | final bool isStarredRepoList; 20 | 21 | @override 22 | State createState() { 23 | return _RepoListRouteState(); 24 | } 25 | } 26 | 27 | class _RepoListRouteState extends State { 28 | @override 29 | Widget build(BuildContext context) { 30 | return Scaffold( 31 | appBar: AppBar( 32 | title: Text(widget.title), 33 | ), 34 | drawer: widget.isStarredRepoList ? null : MyDrawer(), 35 | body: InfiniteListView( 36 | emptyBuilder: (VoidCallback refresh, BuildContext context){ 37 | return listNoDataView(refresh, context); 38 | }, 39 | onRetrieveData: (int page, List items, bool refresh) async { 40 | var data; 41 | if (!widget.isStarredRepoList) { 42 | data = await NetApi(context).getRepos( 43 | repoOwner: widget.personName, 44 | refresh: refresh, 45 | queryParameters: { 46 | 'page': page, 47 | 'page_size': 30, 48 | }, 49 | ); 50 | } else { 51 | data = await NetApi(context).getStarredRepoList( 52 | userName: widget.personName, 53 | queryParameters: { 54 | 'page': page, 55 | 'page_size': 30, 56 | }, 57 | ); 58 | } 59 | //把请求到的新数据添加到items中 60 | items.addAll(data); 61 | // 如果接口返回的数量等于'page_size',则认为还有数据,反之则认为最后一页 62 | return data.length == 30; 63 | }, 64 | itemBuilder: (List list, int index, BuildContext ctx) { 65 | // 项目信息列表项 66 | return RepoItem(list[index]); 67 | }, 68 | ), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/states/LocaleModel.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:fluttergithub/states/ProfileChangeNotifier.dart'; 4 | 5 | class LocaleModel extends ProfileChangeNotifier{ 6 | // 获取当前用户的APP语言配置Locale类,如果为null,则语言跟随系统语言 7 | Locale getLocale() { 8 | if (profile.locale == null) return null; 9 | var t = profile.locale.split("_"); 10 | return Locale(t[0], t[1]); 11 | } 12 | 13 | // 获取当前Locale的字符串表示 14 | String get locale => profile.locale; 15 | 16 | // 用户改变APP语言后,通知依赖项更新,新语言会立即生效 17 | set locale(String locale) { 18 | if (locale != profile.locale) { 19 | profile.locale = locale; 20 | notifyListeners(); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /lib/states/ProfileChangeNotifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:fluttergithub/common/Global.dart'; 3 | import 'package:fluttergithub/models/index.dart'; 4 | 5 | class ProfileChangeNotifier extends ChangeNotifier { 6 | ProfileBean get profile => Global.profile; 7 | 8 | @override 9 | void notifyListeners() { 10 | Global.saveProfile(); //保存Profile变更 11 | super.notifyListeners(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/states/ThemeModel.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttergithub/common/Global.dart'; 4 | import 'package:fluttergithub/states/ProfileChangeNotifier.dart'; 5 | 6 | class ThemeModel extends ProfileChangeNotifier { 7 | // 获取当前主题,如果未设置主题,则默认使用蓝色主题 8 | Color get theme => Global.themes 9 | .firstWhere((e) => e.value == profile.theme, orElse: () => Global.themes[0]); 10 | 11 | // 主题改变后,通知其依赖项,新主题会立即生效 12 | set theme(Color color) { 13 | if (color != theme) { 14 | profile.theme = color.value; 15 | notifyListeners(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/states/UserModel.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluttergithub/models/index.dart'; 2 | import 'package:fluttergithub/states/ProfileChangeNotifier.dart'; 3 | 4 | class UserModel extends ProfileChangeNotifier { 5 | UserBean get user => profile.user; 6 | 7 | //App是否登录(如果有用户信息,则证明登录过) 8 | bool get isLogin => user != null; 9 | 10 | //用户信息发生变化,更新用户信息并通知依赖它的子孙Widgets更新 11 | set user(UserBean user) { 12 | if (user?.login != profile.user?.login) { 13 | profile.lastLogin = profile.user?.login; 14 | profile.user = user; 15 | notifyListeners(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/states/index.dart: -------------------------------------------------------------------------------- 1 | export 'LocaleModel.dart'; 2 | export 'ThemeModel.dart'; 3 | export 'UserModel.dart'; -------------------------------------------------------------------------------- /lib/widgets/PersonItem.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttergithub/common/myAvatar.dart'; 4 | import 'package:fluttergithub/models/index.dart'; 5 | import 'package:fluttergithub/routes/person_detail_page.dart'; 6 | 7 | import 'myWidgets/index.dart'; 8 | 9 | class PersonItem extends StatelessWidget { 10 | PersonItem({@required this.personData}); 11 | 12 | final UserBean personData; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return GestureDetector( 17 | child: MyCard( 18 | child: Row( 19 | children: [ 20 | Padding( 21 | padding: EdgeInsets.only(right: 20.0), 22 | child: myAvatar( 23 | personData.avatar_url, 24 | width: 50.0, 25 | height: 50.0, 26 | borderRadius: BorderRadius.circular(50), 27 | ), 28 | ), 29 | Text( 30 | personData.login, 31 | style: TextStyle( 32 | fontSize: 16, color: Theme.of(context).primaryColor), 33 | ), 34 | ], 35 | ), 36 | ), 37 | onTap: () { 38 | Navigator.push( 39 | context, 40 | MaterialPageRoute( 41 | builder: (context) => PersonDetailPage(name: personData.login), 42 | ), 43 | ); 44 | }, 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/widgets/RepoDetail/index.dart: -------------------------------------------------------------------------------- 1 | export 'repo_detail_info.dart'; 2 | export 'repo_detail_events.dart'; 3 | export 'repo_detail_files.dart'; 4 | export 'repo_detail_commits.dart'; -------------------------------------------------------------------------------- /lib/widgets/RepoDetail/repo_stargazer_or_watcher.dart: -------------------------------------------------------------------------------- 1 | import 'package:flukit/flukit.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:fluttergithub/common/net/NetApi.dart'; 5 | import 'package:fluttergithub/models/index.dart'; 6 | import 'package:fluttergithub/widgets/PersonItem.dart'; 7 | import 'package:fluttergithub/widgets/myWidgets/no_data_or_no_net.dart'; 8 | 9 | class RepoStarOrWatcherList extends StatefulWidget { 10 | RepoStarOrWatcherList(this.repoOwner, this.repoName, 11 | {@required this.isStargazer}); 12 | 13 | final String repoOwner; 14 | final String repoName; 15 | final bool isStargazer; 16 | 17 | @override 18 | State createState() { 19 | return _RepoStarOrWatcherState(); 20 | } 21 | } 22 | 23 | class _RepoStarOrWatcherState extends State 24 | with AutomaticKeepAliveClientMixin { 25 | @override 26 | bool get wantKeepAlive => true; 27 | 28 | @override 29 | Widget build(BuildContext mContext) { 30 | return Scaffold( 31 | appBar: AppBar( 32 | title: Container( 33 | child: Column( 34 | crossAxisAlignment: CrossAxisAlignment.start, 35 | children: [ 36 | Text( 37 | widget.isStargazer ? 'Stargazers' : 'Watchers', 38 | style: TextStyle( 39 | color: Colors.white, 40 | fontSize: 18, 41 | fontWeight: FontWeight.bold), 42 | ), 43 | Text( 44 | widget.repoOwner + '/' + widget.repoName, 45 | style: TextStyle(color: Colors.grey, fontSize: 12.0), 46 | ), 47 | ], 48 | ), 49 | ), 50 | ), 51 | body: InfiniteListView( 52 | emptyBuilder: (VoidCallback refresh, BuildContext context){ 53 | return listNoDataView(refresh, context); 54 | }, 55 | onRetrieveData: (int page, List items, bool refresh) async { 56 | var data = await NetApi(context).getRepoStargazersOrWatcher( 57 | repoOwner: widget.repoOwner, 58 | repoName: widget.repoName, 59 | isStargazers: widget.isStargazer, 60 | queryParameters: { 61 | 'page': page, 62 | 'page_size': 30, 63 | }, 64 | ); 65 | //把请求到的新数据添加到items中 66 | items.addAll(data); 67 | // 如果接口返回的数量等于'page_size',则认为还有数据,反之则认为最后一页 68 | return data.length == 30; 69 | }, 70 | itemBuilder: (List list, int index, BuildContext ctx) { 71 | // 项目信息列表项 72 | return PersonItem( 73 | personData: list[index], 74 | ); 75 | }, 76 | ), 77 | ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/widgets/myWidgets/index.dart: -------------------------------------------------------------------------------- 1 | export 'myCard.dart'; 2 | export 'mySimpleWidget.dart'; -------------------------------------------------------------------------------- /lib/widgets/myWidgets/myCard.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | ///自定义的卡片布局 4 | class MyCard extends StatelessWidget { 5 | MyCard({@required this.child}); 6 | 7 | final Widget child; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | margin: const EdgeInsets.only(top: 12.0, left: 8.0, right: 8.0), 13 | decoration: BoxDecoration( 14 | color: Colors.white, 15 | borderRadius: BorderRadius.circular(5.0), 16 | boxShadow: [ 17 | BoxShadow( 18 | color: Colors.black54, 19 | offset: Offset(1.0, 1.0), //延伸的阴影,向右下偏移的距离 20 | blurRadius: 3.0) //延伸距离,会有模糊效果 21 | ], 22 | ), 23 | child: Padding( 24 | padding: 25 | EdgeInsets.only(top: 12.0, bottom: 12.0, left: 8.0, right: 8.0), 26 | child: child, 27 | ), 28 | ); 29 | } 30 | } 31 | 32 | class MyCardNoMargin extends StatelessWidget { 33 | MyCardNoMargin({@required this.child}); 34 | 35 | final Widget child; 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return Container( 40 | margin: const EdgeInsets.only(left: 8.0, right: 8.0), 41 | decoration: BoxDecoration( 42 | color: Colors.white, 43 | borderRadius: BorderRadius.circular(5.0), 44 | boxShadow: [ 45 | BoxShadow( 46 | color: Colors.black54, 47 | offset: Offset(0.0, 0.0), //延伸的阴影,向右下偏移的距离 48 | blurRadius: 1.0) //延伸距离,会有模糊效果 49 | ], 50 | ), 51 | child: Padding( 52 | padding: 53 | EdgeInsets.only(top: 12.0, bottom: 12.0, left: 8.0, right: 8.0), 54 | child: child, 55 | ), 56 | ); 57 | } 58 | } -------------------------------------------------------------------------------- /lib/widgets/myWidgets/mySimpleWidget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | Widget numberAndText(num count, String text) { 4 | return Column( 5 | mainAxisSize: MainAxisSize.min, 6 | mainAxisAlignment: MainAxisAlignment.center, 7 | children: [ 8 | Text( 9 | count.toString(), 10 | style: TextStyle(fontSize: 18, color: Colors.black54), 11 | ), 12 | Text( 13 | text, 14 | style: TextStyle(fontSize: 12, color: Colors.black38), 15 | ), 16 | ], 17 | ); 18 | } 19 | 20 | Widget languageWithPoint(String language) { 21 | Color pointColor = Colors.orange; 22 | if (language == null || language.length == 0) { 23 | return Container( 24 | width: 0, 25 | height: 0, 26 | ); 27 | } 28 | switch (language) { 29 | case "Java": 30 | pointColor = Colors.green; 31 | break; 32 | case "Dart": 33 | pointColor = Colors.red; 34 | break; 35 | case "JavaScript": 36 | pointColor = Colors.blue; 37 | break; 38 | case "HTML": 39 | pointColor = Colors.yellow; 40 | break; 41 | case "Python": 42 | pointColor = Colors.redAccent; 43 | break; 44 | case "C++": 45 | pointColor = Colors.purple; 46 | break; 47 | case "C#": 48 | pointColor = Colors.pink; 49 | break; 50 | case "PHP": 51 | pointColor = Colors.lightGreen; 52 | break; 53 | case "C": 54 | pointColor = Colors.purpleAccent; 55 | break; 56 | case "Ruby": 57 | pointColor = Colors.blueAccent; 58 | break; 59 | case "Go": 60 | pointColor = Colors.lightBlueAccent; 61 | break; 62 | case "Vue": 63 | pointColor = Colors.teal; 64 | break; 65 | } 66 | return Row( 67 | children: [ 68 | Padding( 69 | padding: EdgeInsets.only(right: 3.0), 70 | child: Icon( 71 | Icons.fiber_manual_record, 72 | color: pointColor, 73 | size: 10, 74 | ), 75 | ), 76 | Text( 77 | language, 78 | style: TextStyle(color: Colors.black45), 79 | ), 80 | ], 81 | ); 82 | } 83 | 84 | Widget infoWithIcon(message, icon, iconSize) { 85 | if (message == null || message.length == 0) { 86 | message = "目前什么都没有"; 87 | } 88 | return Row( 89 | children: [ 90 | Padding( 91 | padding: EdgeInsets.only(right: 5.0), 92 | child: Icon( 93 | icon, 94 | color: Colors.white70, 95 | size: iconSize, 96 | ), 97 | ), 98 | Expanded( 99 | child: Text( 100 | message ?? "目前什么都没有", 101 | maxLines: 1, 102 | overflow: TextOverflow.ellipsis, 103 | style: TextStyle(color: Colors.white70, fontSize: 13), 104 | ) , 105 | ), 106 | 107 | ], 108 | ); 109 | } 110 | 111 | //图标+文字,水平排布 112 | Widget iconWithTextHorizontal( 113 | {icon, text, iconColor, textColor, iconSize, textSize, padding = 5.0}) { 114 | return Row( 115 | crossAxisAlignment: CrossAxisAlignment.center, 116 | children: [ 117 | Padding( 118 | padding: EdgeInsets.only(right: padding), 119 | child: Icon( 120 | icon, 121 | color: iconColor, 122 | size: iconSize, 123 | ), 124 | ), 125 | Text( 126 | text ?? '', 127 | style: TextStyle(color: textColor, fontSize: textSize), 128 | ), 129 | ], 130 | ); 131 | } 132 | -------------------------------------------------------------------------------- /lib/widgets/myWidgets/mySpinKit.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_spinkit/flutter_spinkit.dart'; 5 | ///loading样式 6 | Widget MySpinkitFullScreen(){ 7 | return Center( 8 | child: new Center( 9 | child: new SpinKitCubeGrid( 10 | color: Colors.blue, size: 60.0, 11 | duration: Duration(milliseconds:1000 ),) 12 | ), 13 | ); 14 | } -------------------------------------------------------------------------------- /lib/widgets/myWidgets/no_data_or_no_net.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | Widget listNoDataView(refresh, context) { 5 | return Material( 6 | //color: Colors.transparent, 7 | child: InkWell( 8 | splashColor: Theme.of(context).secondaryHeaderColor, 9 | onTap: refresh, 10 | child: Center( 11 | child: Padding( 12 | padding: EdgeInsets.only(top: 0), 13 | child: Column( 14 | crossAxisAlignment: CrossAxisAlignment.center, 15 | mainAxisAlignment: MainAxisAlignment.center, 16 | children: [ 17 | Icon( 18 | Icons.event_busy, 19 | //color: Colors.deepOrange[300], 20 | color: Theme.of(context).primaryColor, 21 | size: 150, 22 | ), 23 | Padding( 24 | padding: EdgeInsets.only(top: 0), 25 | child: Text( 26 | "没有数据", 27 | style: TextStyle( 28 | color: Theme.of(context).primaryColor, fontSize: 22), 29 | )) 30 | ], 31 | ), 32 | ), 33 | ), 34 | ), 35 | ); 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /lib/widgets/personDetail/follow_person_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flukit/flukit.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:fluttergithub/common/myAvatar.dart'; 5 | import 'package:fluttergithub/common/net/NetApi.dart'; 6 | import 'package:fluttergithub/models/index.dart'; 7 | import 'package:fluttergithub/routes/person_detail_page.dart'; 8 | import 'package:fluttergithub/widgets/PersonItem.dart'; 9 | import 'package:fluttergithub/widgets/myWidgets/index.dart'; 10 | import 'package:fluttergithub/widgets/myWidgets/no_data_or_no_net.dart'; 11 | 12 | class PersonFollowList extends StatefulWidget { 13 | PersonFollowList( 14 | {@required this.personName, @required this.isFollowing}); 15 | 16 | final String personName; 17 | final bool isFollowing; 18 | 19 | @override 20 | State createState() { 21 | return _PersonFollowListState(); 22 | } 23 | } 24 | 25 | class _PersonFollowListState extends State 26 | with AutomaticKeepAliveClientMixin { 27 | @override 28 | bool get wantKeepAlive => true; 29 | 30 | @override 31 | Widget build(BuildContext mContext) { 32 | return MediaQuery.removePadding( 33 | removeTop: true, 34 | context: context, 35 | child: InfiniteListView( 36 | emptyBuilder: (VoidCallback refresh, BuildContext context){ 37 | return listNoDataView(refresh, context); 38 | }, 39 | onRetrieveData: (int page, List items, bool refresh) async { 40 | var data = await NetApi(context).getFollowList( 41 | userName: widget.personName, 42 | isGetFollowing: widget.isFollowing, 43 | queryParameters: { 44 | 'page': page, 45 | 'page_size': 30, 46 | }, 47 | ); 48 | //把请求到的新数据添加到items中 49 | items.addAll(data); 50 | // 如果接口返回的数量等于'page_size',则认为还有数据,反之则认为最后一页 51 | return data.length == 30; 52 | }, 53 | itemBuilder: (List list, int index, BuildContext ctx) { 54 | // 项目信息列表项 55 | return PersonItem(personData: list[index],); 56 | }, 57 | ), 58 | ); 59 | } 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /lib/widgets/personDetail/repo_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flukit/flukit.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttergithub/common/net/NetApi.dart'; 4 | import 'package:fluttergithub/models/index.dart'; 5 | import 'package:fluttergithub/widgets/RepoItem.dart'; 6 | import 'package:fluttergithub/widgets/myWidgets/no_data_or_no_net.dart'; 7 | 8 | class RepoListPage extends StatefulWidget { 9 | RepoListPage({@required this.personName, @required this.isStarredRepoList}); 10 | 11 | final String personName; 12 | final bool isStarredRepoList; 13 | 14 | @override 15 | State createState() { 16 | return _RepoListPageState(); 17 | } 18 | } 19 | 20 | class _RepoListPageState extends State 21 | with AutomaticKeepAliveClientMixin { 22 | @override 23 | bool get wantKeepAlive => true; 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return MediaQuery.removePadding( 28 | removeTop: true, 29 | context: context, 30 | child: InfiniteListView( 31 | emptyBuilder: (VoidCallback refresh, BuildContext context){ 32 | return listNoDataView(refresh, context); 33 | }, 34 | onRetrieveData: (int page, List items, bool refresh) async { 35 | var data; 36 | if (!widget.isStarredRepoList) { 37 | data = await NetApi(context).getRepos( 38 | repoOwner: widget.personName, 39 | refresh: refresh, 40 | queryParameters: { 41 | 'page': page, 42 | 'page_size': 30, 43 | }, 44 | ); 45 | } else { 46 | data = await NetApi(context).getStarredRepoList( 47 | userName: widget.personName, 48 | queryParameters: { 49 | 'page': page, 50 | 'page_size': 30, 51 | }, 52 | ); 53 | } 54 | //把请求到的新数据添加到items中 55 | items.addAll(data); 56 | // 如果接口返回的数量等于'page_size',则认为还有数据,反之则认为最后一页 57 | return data.length == 30; 58 | }, 59 | itemBuilder: (List list, int index, BuildContext ctx) { 60 | // 项目信息列表项 61 | return RepoItem(list[index]); 62 | }, 63 | ), 64 | ); 65 | } 66 | } 67 | 68 | repoListWidget({BuildContext context, String userName}) { 69 | return InfiniteListView( 70 | emptyBuilder: (VoidCallback refresh, BuildContext context){ 71 | return listNoDataView(refresh, context); 72 | }, 73 | onRetrieveData: (int page, List items, bool refresh) async { 74 | var data = await NetApi(context).getRepos( 75 | repoOwner: userName, 76 | refresh: refresh, 77 | queryParameters: { 78 | 'page': page, 79 | 'page_size': 30, 80 | }, 81 | ); 82 | //把请求到的新数据添加到items中 83 | items.addAll(data); 84 | // 如果接口返回的数量等于'page_size',则认为还有数据,反之则认为最后一页 85 | return data.length == 30; 86 | }, 87 | itemBuilder: (List list, int index, BuildContext ctx) { 88 | // 项目信息列表项 89 | return RepoItem(list[index]); 90 | }, 91 | ); 92 | } 93 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: fluttergithub 2 | description: A new Flutter application. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 1.0.0+1 15 | 16 | environment: 17 | sdk: ">=2.1.0 <3.0.0" 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | flutter_localizations: 23 | sdk: flutter 24 | 25 | # The following adds the Cupertino Icons font to your application. 26 | # Use with the CupertinoIcons class for iOS style icons. 27 | cupertino_icons: ^0.1.2 28 | shared_preferences: ^0.5.1+1 29 | dio: ^3.0.9 30 | provider: ^2.0.1 31 | intl: ^0.16.0 32 | cached_network_image: ^2.2.0+1 33 | fluttertoast: ^3.0.3 34 | #一个Flutter UI组件库。 https://github.com/flutterchina/flukit 35 | flukit: ^1.0.2 36 | #https://github.com/Sky24n/common_utils 37 | common_utils: ^1.1.3 38 | #Flutter支持MarkDown模式 https://github.com/flutter/flutter_markdown 39 | flutter_markdown: 0.3.5 40 | #flutter loading样式。 https://github.com/jogboms/flutter_spinkit 41 | flutter_spinkit: "^4.1.2" 42 | #A Flutter plugin that provides a WebView widget. 43 | webview_flutter: ^0.3.19+9 44 | # A simple transparent image. https://pub.dev/packages/transparent_image#-readme-tab- 45 | transparent_image: ^1.0.0 46 | event_bus: ^1.1.0 47 | #sqlite 数据库 48 | sqflite: ^1.1.0 49 | #PhotoView使图像能够通过用户手势(例如捏,旋转和拖动)进行缩放和平移。 50 | photo_view: 51 | git: 52 | url: https://github.com/CarSmallGuo/photo_view.git 53 | ref: master 54 | 55 | 56 | dev_dependencies: 57 | json_model: 58 | git: 59 | url: "https://github.com/wbtvc/json_model.git" 60 | build_runner: ^1.6.0 61 | json_serializable: ^3.0.0 62 | intl_translation: ^0.17.2 63 | flutter_test: 64 | sdk: flutter 65 | 66 | 67 | # For information on the generic Dart part of this file, see the 68 | # following page: https://dart.dev/tools/pub/pubspec 69 | 70 | # The following section is specific to Flutter. 71 | flutter: 72 | 73 | # The following line ensures that the Material Icons font is 74 | # included with your application, so that you can use the icons in 75 | # the material Icons class. 76 | uses-material-design: true 77 | assets: 78 | - imgs/ 79 | 80 | # To add assets to your application, add an assets section, like this: 81 | # assets: 82 | # - images/a_dot_burr.jpeg 83 | # - images/a_dot_ham.jpeg 84 | 85 | # An image asset can refer to one or more resolution-specific "variants", see 86 | # https://flutter.dev/assets-and-images/#resolution-aware. 87 | 88 | # For details regarding adding assets from package dependencies, see 89 | # https://flutter.dev/assets-and-images/#from-packages 90 | 91 | # To add custom fonts to your application, add a fonts section here, 92 | # in this "flutter" section. Each entry in this list should have a 93 | # "family" key with the font family name, and a "fonts" key with a 94 | # list giving the asset and other descriptors for the font. For 95 | # example: 96 | fonts: 97 | - family: myIcon 98 | fonts: 99 | - asset: fonts/iconfont.ttf 100 | - family: fileIcon 101 | fonts: 102 | - asset: fonts/fileiconfont.ttf 103 | # fonts: 104 | # - family: Schyler 105 | # fonts: 106 | # - asset: fonts/Schyler-Regular.ttf 107 | # - asset: fonts/Schyler-Italic.ttf 108 | # style: italic 109 | # - family: Trajan Pro 110 | # fonts: 111 | # - asset: fonts/TrajanPro.ttf 112 | # - asset: fonts/TrajanPro_Bold.ttf 113 | # weight: 700 114 | # 115 | # For details regarding fonts from package dependencies, 116 | # see https://flutter.dev/custom-fonts/#from-packages 117 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:fluttergithub/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | --------------------------------------------------------------------------------