├── .github └── FUNDING.yml ├── .gitignore ├── .readme ├── img1.png ├── img2.png ├── img3.png ├── img4.png ├── img5.png └── img6.png ├── .vscode └── launch.json ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── sutech │ │ │ │ └── github_repo_explorer │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── build.yaml ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── 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 ├── lib ├── api │ └── github_api.dart ├── controllers │ └── theme_mode_controller.dart ├── main.dart ├── models │ ├── models.dart │ ├── repository.dart │ ├── repository.freezed.dart │ └── repository.g.dart ├── pages │ ├── bookmark │ │ └── bookmark_page.dart │ ├── bookmarks │ │ ├── bookmarks_controller.dart │ │ ├── bookmarks_controller.freezed.dart │ │ └── bookmarks_page.dart │ ├── repositories │ │ ├── repositories_controller.dart │ │ ├── repositories_controller.freezed.dart │ │ ├── repositories_item.dart │ │ └── repositories_page.dart │ ├── repository │ │ └── repository_page.dart │ └── tab │ │ └── main_tab.dart └── widgets │ ├── author_label.dart │ ├── gaps.dart │ ├── repository_content.dart │ ├── repository_label.dart │ ├── space.dart │ ├── stargazer_label.dart │ └── widgets.dart ├── pubspec.lock ├── pubspec.yaml └── test └── widget_test.dart /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: sgr-ksmt 2 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.readme/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/.readme/img1.png -------------------------------------------------------------------------------- /.readme/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/.readme/img2.png -------------------------------------------------------------------------------- /.readme/img3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/.readme/img3.png -------------------------------------------------------------------------------- /.readme/img4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/.readme/img4.png -------------------------------------------------------------------------------- /.readme/img5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/.readme/img5.png -------------------------------------------------------------------------------- /.readme/img6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/.readme/img6.png -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [{ 7 | "name": "Flutter", 8 | "request": "launch", 9 | "type": "dart" 10 | }] 11 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Suguru Kishimoto 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 | # Flutter GitHub repo explorer 2 | 3 | This is an example application with Flutter. 4 | A lot of popular packages are used in the example: 5 | 6 | - [river_pod](https://github.com/rrousselGit/river_pod) 7 | - [flutter_hooks](https://github.com/rrousselGit/flutter_hooks) 8 | - [state_notifier](https://github.com/rrousselGit/state_notifier) 9 | - [freezed](https://github.com/rrousselGit/freezed) 10 | - etc.. 11 | 12 | ## Summary 13 | 14 | - Search GitHub repositories with specified keyword (e.g.: `Flutter`). 15 | - Display fetched GitHub repository data. 16 | - Can look through repository data detail. 17 | - Can change `light/dark` theme. 18 | - Can add repository data to Bookmarks. 19 | - Can remove repository data from Bookmarks. 20 | 21 | 22 | | ![1](.readme/img1.png) | ![2](.readme/img2.png) | ![3](.readme/img3.png) | 23 | | ---------------------- | ---------------------- | ---------------------- | 24 | | ![4](.readme/img4.png) | ![5](.readme/img5.png) | ![6](.readme/img6.png) | 25 | 26 | ## TODO 27 | - [ ] Add more examples using river_pod 28 | - [ ] Family 29 | - [ ] `.autoDispose` 30 | - [ ] Search 31 | - [ ] Pagination 32 | - [ ] Retry handling 33 | - [ ] Refine whole designs 34 | - [ ] Testing 35 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:pedantic_mono/analysis_options.yaml 2 | 3 | analyzer: 4 | exclude: 5 | - "**/*.freezed.dart" 6 | - "**/*g.dart" 7 | - "*.g.dart" 8 | errors: 9 | mixin_inherits_from_not_object: ignore 10 | unused_import: error 11 | directives_ordering: error 12 | 13 | linter: 14 | rules: 15 | avoid_classes_with_only_static_members: false 16 | prefer_constructors_over_static_methods: false 17 | avoid_function_literals_in_foreach_calls: false 18 | flutter_style_todos: false 19 | type_annotate_public_apis: false -------------------------------------------------------------------------------- /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 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.sutech.github_repo_explorer" 42 | minSdkVersion 16 43 | targetSdkVersion 28 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | } 47 | 48 | buildTypes { 49 | release { 50 | // TODO: Add your own signing config for the release build. 51 | // Signing with the debug keys for now, so `flutter run --release` works. 52 | signingConfig signingConfigs.debug 53 | } 54 | } 55 | } 56 | 57 | flutter { 58 | source '../..' 59 | } 60 | 61 | dependencies { 62 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 63 | } 64 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 12 | 19 | 23 | 27 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/sutech/github_repo_explorer/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.sutech.github_repo_explorer 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/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 | // Copyright 2014 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | include ':app' 6 | 7 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 8 | def properties = new Properties() 9 | 10 | assert localPropertiesFile.exists() 11 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 12 | 13 | def flutterSdkPath = properties.getProperty("flutter.sdk") 14 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 15 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 16 | -------------------------------------------------------------------------------- /build.yaml: -------------------------------------------------------------------------------- 1 | targets: 2 | $default: 3 | builders: 4 | freezed: 5 | generate_for: 6 | include: 7 | - lib/**/*state.dart 8 | - lib/**/*controller.dart 9 | - lib/models/*.dart 10 | json_serializable: 11 | generate_for: 12 | include: 13 | - lib/models/*.dart 14 | options: 15 | explicit_to_json: true 16 | any_map: true -------------------------------------------------------------------------------- /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 "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | generated_key_values = {} 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) do |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | generated_key_values[podname] = podpath 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | end 32 | generated_key_values 33 | end 34 | 35 | target 'Runner' do 36 | use_frameworks! 37 | use_modular_headers! 38 | 39 | # Flutter Pod 40 | 41 | copied_flutter_dir = File.join(__dir__, 'Flutter') 42 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') 43 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') 44 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) 45 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. 46 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. 47 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. 48 | 49 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') 50 | unless File.exist?(generated_xcode_build_settings_path) 51 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" 52 | end 53 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) 54 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; 55 | 56 | unless File.exist?(copied_framework_path) 57 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) 58 | end 59 | unless File.exist?(copied_podspec_path) 60 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) 61 | end 62 | end 63 | 64 | # Keep pod path relative so it can be checked into Podfile.lock. 65 | pod 'Flutter', :path => 'Flutter' 66 | 67 | # Plugin Pods 68 | 69 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 70 | # referring to absolute paths on developers' machines. 71 | system('rm -rf .symlinks') 72 | system('mkdir -p .symlinks/plugins') 73 | plugin_pods = parse_KV_file('../.flutter-plugins') 74 | plugin_pods.each do |name, path| 75 | symlink = File.join('.symlinks', 'plugins', name) 76 | File.symlink(path, symlink) 77 | pod name, :path => File.join(symlink, 'ios') 78 | end 79 | end 80 | 81 | post_install do |installer| 82 | installer.pods_project.targets.each do |target| 83 | target.build_configurations.each do |config| 84 | config.build_settings['ENABLE_BITCODE'] = 'NO' 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - FMDB (2.7.5): 4 | - FMDB/standard (= 2.7.5) 5 | - FMDB/standard (2.7.5) 6 | - path_provider (0.0.1): 7 | - Flutter 8 | - path_provider_linux (0.0.1): 9 | - Flutter 10 | - path_provider_macos (0.0.1): 11 | - Flutter 12 | - sqflite (0.0.1): 13 | - Flutter 14 | - FMDB (~> 2.7.2) 15 | 16 | DEPENDENCIES: 17 | - Flutter (from `Flutter`) 18 | - path_provider (from `.symlinks/plugins/path_provider/ios`) 19 | - path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`) 20 | - path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`) 21 | - sqflite (from `.symlinks/plugins/sqflite/ios`) 22 | 23 | SPEC REPOS: 24 | trunk: 25 | - FMDB 26 | 27 | EXTERNAL SOURCES: 28 | Flutter: 29 | :path: Flutter 30 | path_provider: 31 | :path: ".symlinks/plugins/path_provider/ios" 32 | path_provider_linux: 33 | :path: ".symlinks/plugins/path_provider_linux/ios" 34 | path_provider_macos: 35 | :path: ".symlinks/plugins/path_provider_macos/ios" 36 | sqflite: 37 | :path: ".symlinks/plugins/sqflite/ios" 38 | 39 | SPEC CHECKSUMS: 40 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec 41 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a 42 | path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c 43 | path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4 44 | path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0 45 | sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0 46 | 47 | PODFILE CHECKSUM: c34e2287a9ccaa606aeceab922830efb9a6ff69a 48 | 49 | COCOAPODS: 1.9.1 50 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 40883BEA93C325C154C02A9C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6D38330B714B7C059D663F09 /* Pods_Runner.framework */; }; 13 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 14 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 15 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 16 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXCopyFilesBuildPhase section */ 20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 21 | isa = PBXCopyFilesBuildPhase; 22 | buildActionMask = 2147483647; 23 | dstPath = ""; 24 | dstSubfolderSpec = 10; 25 | files = ( 26 | ); 27 | name = "Embed Frameworks"; 28 | runOnlyForDeploymentPostprocessing = 0; 29 | }; 30 | /* End PBXCopyFilesBuildPhase section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 34 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 35 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 36 | 6A08B0EB9A9059B171641EC4 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 37 | 6D38330B714B7C059D663F09 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 39 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 40 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 41 | 942A55759726F3BD1147071B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 42 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 43 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 44 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 46 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 47 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 48 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49 | B739A7972505A580471FD642 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | 40883BEA93C325C154C02A9C /* Pods_Runner.framework in Frameworks */, 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | 475C025D06274FEB7270242F /* Frameworks */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 6D38330B714B7C059D663F09 /* Pods_Runner.framework */, 68 | ); 69 | name = Frameworks; 70 | sourceTree = ""; 71 | }; 72 | 9740EEB11CF90186004384FC /* Flutter */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 76 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 77 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 78 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 79 | ); 80 | name = Flutter; 81 | sourceTree = ""; 82 | }; 83 | 97C146E51CF9000F007C117D = { 84 | isa = PBXGroup; 85 | children = ( 86 | 9740EEB11CF90186004384FC /* Flutter */, 87 | 97C146F01CF9000F007C117D /* Runner */, 88 | 97C146EF1CF9000F007C117D /* Products */, 89 | EBDA8F18C1CE21C4124F4A4F /* Pods */, 90 | 475C025D06274FEB7270242F /* Frameworks */, 91 | ); 92 | sourceTree = ""; 93 | }; 94 | 97C146EF1CF9000F007C117D /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 97C146EE1CF9000F007C117D /* Runner.app */, 98 | ); 99 | name = Products; 100 | sourceTree = ""; 101 | }; 102 | 97C146F01CF9000F007C117D /* Runner */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 106 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 107 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 108 | 97C147021CF9000F007C117D /* Info.plist */, 109 | 97C146F11CF9000F007C117D /* Supporting Files */, 110 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 111 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 112 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 113 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 114 | ); 115 | path = Runner; 116 | sourceTree = ""; 117 | }; 118 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | ); 122 | name = "Supporting Files"; 123 | sourceTree = ""; 124 | }; 125 | EBDA8F18C1CE21C4124F4A4F /* Pods */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 942A55759726F3BD1147071B /* Pods-Runner.debug.xcconfig */, 129 | 6A08B0EB9A9059B171641EC4 /* Pods-Runner.release.xcconfig */, 130 | B739A7972505A580471FD642 /* Pods-Runner.profile.xcconfig */, 131 | ); 132 | name = Pods; 133 | path = Pods; 134 | sourceTree = ""; 135 | }; 136 | /* End PBXGroup section */ 137 | 138 | /* Begin PBXNativeTarget section */ 139 | 97C146ED1CF9000F007C117D /* Runner */ = { 140 | isa = PBXNativeTarget; 141 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 142 | buildPhases = ( 143 | 61F047F7C03B5D8D83A7ABF5 /* [CP] Check Pods Manifest.lock */, 144 | 9740EEB61CF901F6004384FC /* Run Script */, 145 | 97C146EA1CF9000F007C117D /* Sources */, 146 | 97C146EB1CF9000F007C117D /* Frameworks */, 147 | 97C146EC1CF9000F007C117D /* Resources */, 148 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 149 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 150 | FEFDDE754C71B2860F0BC6B0 /* [CP] Embed Pods Frameworks */, 151 | ); 152 | buildRules = ( 153 | ); 154 | dependencies = ( 155 | ); 156 | name = Runner; 157 | productName = Runner; 158 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 159 | productType = "com.apple.product-type.application"; 160 | }; 161 | /* End PBXNativeTarget section */ 162 | 163 | /* Begin PBXProject section */ 164 | 97C146E61CF9000F007C117D /* Project object */ = { 165 | isa = PBXProject; 166 | attributes = { 167 | LastUpgradeCheck = 1020; 168 | ORGANIZATIONNAME = ""; 169 | TargetAttributes = { 170 | 97C146ED1CF9000F007C117D = { 171 | CreatedOnToolsVersion = 7.3.1; 172 | LastSwiftMigration = 1100; 173 | }; 174 | }; 175 | }; 176 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 177 | compatibilityVersion = "Xcode 9.3"; 178 | developmentRegion = en; 179 | hasScannedForEncodings = 0; 180 | knownRegions = ( 181 | en, 182 | Base, 183 | ); 184 | mainGroup = 97C146E51CF9000F007C117D; 185 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 186 | projectDirPath = ""; 187 | projectRoot = ""; 188 | targets = ( 189 | 97C146ED1CF9000F007C117D /* Runner */, 190 | ); 191 | }; 192 | /* End PBXProject section */ 193 | 194 | /* Begin PBXResourcesBuildPhase section */ 195 | 97C146EC1CF9000F007C117D /* Resources */ = { 196 | isa = PBXResourcesBuildPhase; 197 | buildActionMask = 2147483647; 198 | files = ( 199 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 200 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 201 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 202 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 203 | ); 204 | runOnlyForDeploymentPostprocessing = 0; 205 | }; 206 | /* End PBXResourcesBuildPhase section */ 207 | 208 | /* Begin PBXShellScriptBuildPhase section */ 209 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 210 | isa = PBXShellScriptBuildPhase; 211 | buildActionMask = 2147483647; 212 | files = ( 213 | ); 214 | inputPaths = ( 215 | ); 216 | name = "Thin Binary"; 217 | outputPaths = ( 218 | ); 219 | runOnlyForDeploymentPostprocessing = 0; 220 | shellPath = /bin/sh; 221 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 222 | }; 223 | 61F047F7C03B5D8D83A7ABF5 /* [CP] Check Pods Manifest.lock */ = { 224 | isa = PBXShellScriptBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | ); 228 | inputFileListPaths = ( 229 | ); 230 | inputPaths = ( 231 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 232 | "${PODS_ROOT}/Manifest.lock", 233 | ); 234 | name = "[CP] Check Pods Manifest.lock"; 235 | outputFileListPaths = ( 236 | ); 237 | outputPaths = ( 238 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 239 | ); 240 | runOnlyForDeploymentPostprocessing = 0; 241 | shellPath = /bin/sh; 242 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 243 | showEnvVarsInLog = 0; 244 | }; 245 | 9740EEB61CF901F6004384FC /* Run Script */ = { 246 | isa = PBXShellScriptBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | ); 250 | inputPaths = ( 251 | ); 252 | name = "Run Script"; 253 | outputPaths = ( 254 | ); 255 | runOnlyForDeploymentPostprocessing = 0; 256 | shellPath = /bin/sh; 257 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 258 | }; 259 | FEFDDE754C71B2860F0BC6B0 /* [CP] Embed Pods Frameworks */ = { 260 | isa = PBXShellScriptBuildPhase; 261 | buildActionMask = 2147483647; 262 | files = ( 263 | ); 264 | inputPaths = ( 265 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", 266 | "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", 267 | "${PODS_ROOT}/../Flutter/Flutter.framework", 268 | "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", 269 | "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", 270 | ); 271 | name = "[CP] Embed Pods Frameworks"; 272 | outputPaths = ( 273 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", 274 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", 275 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", 276 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | shellPath = /bin/sh; 280 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 281 | showEnvVarsInLog = 0; 282 | }; 283 | /* End PBXShellScriptBuildPhase section */ 284 | 285 | /* Begin PBXSourcesBuildPhase section */ 286 | 97C146EA1CF9000F007C117D /* Sources */ = { 287 | isa = PBXSourcesBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 291 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | }; 295 | /* End PBXSourcesBuildPhase section */ 296 | 297 | /* Begin PBXVariantGroup section */ 298 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 299 | isa = PBXVariantGroup; 300 | children = ( 301 | 97C146FB1CF9000F007C117D /* Base */, 302 | ); 303 | name = Main.storyboard; 304 | sourceTree = ""; 305 | }; 306 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 307 | isa = PBXVariantGroup; 308 | children = ( 309 | 97C147001CF9000F007C117D /* Base */, 310 | ); 311 | name = LaunchScreen.storyboard; 312 | sourceTree = ""; 313 | }; 314 | /* End PBXVariantGroup section */ 315 | 316 | /* Begin XCBuildConfiguration section */ 317 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 318 | isa = XCBuildConfiguration; 319 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 320 | buildSettings = { 321 | ALWAYS_SEARCH_USER_PATHS = NO; 322 | CLANG_ANALYZER_NONNULL = YES; 323 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 324 | CLANG_CXX_LIBRARY = "libc++"; 325 | CLANG_ENABLE_MODULES = YES; 326 | CLANG_ENABLE_OBJC_ARC = YES; 327 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 328 | CLANG_WARN_BOOL_CONVERSION = YES; 329 | CLANG_WARN_COMMA = YES; 330 | CLANG_WARN_CONSTANT_CONVERSION = YES; 331 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 332 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 333 | CLANG_WARN_EMPTY_BODY = YES; 334 | CLANG_WARN_ENUM_CONVERSION = YES; 335 | CLANG_WARN_INFINITE_RECURSION = YES; 336 | CLANG_WARN_INT_CONVERSION = YES; 337 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 338 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 339 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 340 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 341 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 342 | CLANG_WARN_STRICT_PROTOTYPES = YES; 343 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 344 | CLANG_WARN_UNREACHABLE_CODE = YES; 345 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 346 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 347 | COPY_PHASE_STRIP = NO; 348 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 349 | ENABLE_NS_ASSERTIONS = NO; 350 | ENABLE_STRICT_OBJC_MSGSEND = YES; 351 | GCC_C_LANGUAGE_STANDARD = gnu99; 352 | GCC_NO_COMMON_BLOCKS = YES; 353 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 354 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 355 | GCC_WARN_UNDECLARED_SELECTOR = YES; 356 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 357 | GCC_WARN_UNUSED_FUNCTION = YES; 358 | GCC_WARN_UNUSED_VARIABLE = YES; 359 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 360 | MTL_ENABLE_DEBUG_INFO = NO; 361 | SDKROOT = iphoneos; 362 | SUPPORTED_PLATFORMS = iphoneos; 363 | TARGETED_DEVICE_FAMILY = "1,2"; 364 | VALIDATE_PRODUCT = YES; 365 | }; 366 | name = Profile; 367 | }; 368 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 369 | isa = XCBuildConfiguration; 370 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 371 | buildSettings = { 372 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 373 | CLANG_ENABLE_MODULES = YES; 374 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 375 | ENABLE_BITCODE = NO; 376 | FRAMEWORK_SEARCH_PATHS = ( 377 | "$(inherited)", 378 | "$(PROJECT_DIR)/Flutter", 379 | ); 380 | INFOPLIST_FILE = Runner/Info.plist; 381 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 382 | LIBRARY_SEARCH_PATHS = ( 383 | "$(inherited)", 384 | "$(PROJECT_DIR)/Flutter", 385 | ); 386 | PRODUCT_BUNDLE_IDENTIFIER = "com.su-tech.githubRepoExplorer"; 387 | PRODUCT_NAME = "$(TARGET_NAME)"; 388 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 389 | SWIFT_VERSION = 5.0; 390 | VERSIONING_SYSTEM = "apple-generic"; 391 | }; 392 | name = Profile; 393 | }; 394 | 97C147031CF9000F007C117D /* Debug */ = { 395 | isa = XCBuildConfiguration; 396 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 397 | buildSettings = { 398 | ALWAYS_SEARCH_USER_PATHS = NO; 399 | CLANG_ANALYZER_NONNULL = YES; 400 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 401 | CLANG_CXX_LIBRARY = "libc++"; 402 | CLANG_ENABLE_MODULES = YES; 403 | CLANG_ENABLE_OBJC_ARC = YES; 404 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 405 | CLANG_WARN_BOOL_CONVERSION = YES; 406 | CLANG_WARN_COMMA = YES; 407 | CLANG_WARN_CONSTANT_CONVERSION = YES; 408 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 409 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 410 | CLANG_WARN_EMPTY_BODY = YES; 411 | CLANG_WARN_ENUM_CONVERSION = YES; 412 | CLANG_WARN_INFINITE_RECURSION = YES; 413 | CLANG_WARN_INT_CONVERSION = YES; 414 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 415 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 416 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 417 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 418 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 419 | CLANG_WARN_STRICT_PROTOTYPES = YES; 420 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 421 | CLANG_WARN_UNREACHABLE_CODE = YES; 422 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 423 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 424 | COPY_PHASE_STRIP = NO; 425 | DEBUG_INFORMATION_FORMAT = dwarf; 426 | ENABLE_STRICT_OBJC_MSGSEND = YES; 427 | ENABLE_TESTABILITY = YES; 428 | GCC_C_LANGUAGE_STANDARD = gnu99; 429 | GCC_DYNAMIC_NO_PIC = NO; 430 | GCC_NO_COMMON_BLOCKS = YES; 431 | GCC_OPTIMIZATION_LEVEL = 0; 432 | GCC_PREPROCESSOR_DEFINITIONS = ( 433 | "DEBUG=1", 434 | "$(inherited)", 435 | ); 436 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 437 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 438 | GCC_WARN_UNDECLARED_SELECTOR = YES; 439 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 440 | GCC_WARN_UNUSED_FUNCTION = YES; 441 | GCC_WARN_UNUSED_VARIABLE = YES; 442 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 443 | MTL_ENABLE_DEBUG_INFO = YES; 444 | ONLY_ACTIVE_ARCH = YES; 445 | SDKROOT = iphoneos; 446 | TARGETED_DEVICE_FAMILY = "1,2"; 447 | }; 448 | name = Debug; 449 | }; 450 | 97C147041CF9000F007C117D /* Release */ = { 451 | isa = XCBuildConfiguration; 452 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 453 | buildSettings = { 454 | ALWAYS_SEARCH_USER_PATHS = NO; 455 | CLANG_ANALYZER_NONNULL = YES; 456 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 457 | CLANG_CXX_LIBRARY = "libc++"; 458 | CLANG_ENABLE_MODULES = YES; 459 | CLANG_ENABLE_OBJC_ARC = YES; 460 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 461 | CLANG_WARN_BOOL_CONVERSION = YES; 462 | CLANG_WARN_COMMA = YES; 463 | CLANG_WARN_CONSTANT_CONVERSION = YES; 464 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 465 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 466 | CLANG_WARN_EMPTY_BODY = YES; 467 | CLANG_WARN_ENUM_CONVERSION = YES; 468 | CLANG_WARN_INFINITE_RECURSION = YES; 469 | CLANG_WARN_INT_CONVERSION = YES; 470 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 471 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 472 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 473 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 474 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 475 | CLANG_WARN_STRICT_PROTOTYPES = YES; 476 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 477 | CLANG_WARN_UNREACHABLE_CODE = YES; 478 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 479 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 480 | COPY_PHASE_STRIP = NO; 481 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 482 | ENABLE_NS_ASSERTIONS = NO; 483 | ENABLE_STRICT_OBJC_MSGSEND = YES; 484 | GCC_C_LANGUAGE_STANDARD = gnu99; 485 | GCC_NO_COMMON_BLOCKS = YES; 486 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 487 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 488 | GCC_WARN_UNDECLARED_SELECTOR = YES; 489 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 490 | GCC_WARN_UNUSED_FUNCTION = YES; 491 | GCC_WARN_UNUSED_VARIABLE = YES; 492 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 493 | MTL_ENABLE_DEBUG_INFO = NO; 494 | SDKROOT = iphoneos; 495 | SUPPORTED_PLATFORMS = iphoneos; 496 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 497 | TARGETED_DEVICE_FAMILY = "1,2"; 498 | VALIDATE_PRODUCT = YES; 499 | }; 500 | name = Release; 501 | }; 502 | 97C147061CF9000F007C117D /* Debug */ = { 503 | isa = XCBuildConfiguration; 504 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 505 | buildSettings = { 506 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 507 | CLANG_ENABLE_MODULES = YES; 508 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 509 | ENABLE_BITCODE = NO; 510 | FRAMEWORK_SEARCH_PATHS = ( 511 | "$(inherited)", 512 | "$(PROJECT_DIR)/Flutter", 513 | ); 514 | INFOPLIST_FILE = Runner/Info.plist; 515 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 516 | LIBRARY_SEARCH_PATHS = ( 517 | "$(inherited)", 518 | "$(PROJECT_DIR)/Flutter", 519 | ); 520 | PRODUCT_BUNDLE_IDENTIFIER = "com.su-tech.githubRepoExplorer"; 521 | PRODUCT_NAME = "$(TARGET_NAME)"; 522 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 523 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 524 | SWIFT_VERSION = 5.0; 525 | VERSIONING_SYSTEM = "apple-generic"; 526 | }; 527 | name = Debug; 528 | }; 529 | 97C147071CF9000F007C117D /* Release */ = { 530 | isa = XCBuildConfiguration; 531 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 532 | buildSettings = { 533 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 534 | CLANG_ENABLE_MODULES = YES; 535 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 536 | ENABLE_BITCODE = NO; 537 | FRAMEWORK_SEARCH_PATHS = ( 538 | "$(inherited)", 539 | "$(PROJECT_DIR)/Flutter", 540 | ); 541 | INFOPLIST_FILE = Runner/Info.plist; 542 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 543 | LIBRARY_SEARCH_PATHS = ( 544 | "$(inherited)", 545 | "$(PROJECT_DIR)/Flutter", 546 | ); 547 | PRODUCT_BUNDLE_IDENTIFIER = "com.su-tech.githubRepoExplorer"; 548 | PRODUCT_NAME = "$(TARGET_NAME)"; 549 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 550 | SWIFT_VERSION = 5.0; 551 | VERSIONING_SYSTEM = "apple-generic"; 552 | }; 553 | name = Release; 554 | }; 555 | /* End XCBuildConfiguration section */ 556 | 557 | /* Begin XCConfigurationList section */ 558 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 559 | isa = XCConfigurationList; 560 | buildConfigurations = ( 561 | 97C147031CF9000F007C117D /* Debug */, 562 | 97C147041CF9000F007C117D /* Release */, 563 | 249021D3217E4FDB00AE95B9 /* Profile */, 564 | ); 565 | defaultConfigurationIsVisible = 0; 566 | defaultConfigurationName = Release; 567 | }; 568 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 569 | isa = XCConfigurationList; 570 | buildConfigurations = ( 571 | 97C147061CF9000F007C117D /* Debug */, 572 | 97C147071CF9000F007C117D /* Release */, 573 | 249021D4217E4FDB00AE95B9 /* Profile */, 574 | ); 575 | defaultConfigurationIsVisible = 0; 576 | defaultConfigurationName = Release; 577 | }; 578 | /* End XCConfigurationList section */ 579 | }; 580 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 581 | } 582 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 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 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sgr-ksmt/flutter-github-repo-explorer/74378900fc9ad989789f22f93179b5d295bcd7e3/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 | github_repo_explorer 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" 2 | -------------------------------------------------------------------------------- /lib/api/github_api.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | import 'package:http/http.dart'; 5 | 6 | import 'package:github_repo_explorer/models/models.dart'; 7 | 8 | class GitHubAPI { 9 | const GitHubAPI._(); 10 | static final _client = Client(); 11 | static const _baseURL = 'https://api.github.com'; 12 | 13 | static final searchRepositories = 14 | FutureProvider.family((ref, String query) async { 15 | const path = '/search/repositories'; 16 | final result = await _client.get( 17 | '$_baseURL$path?q=$query', 18 | ); 19 | // ignore: unnecessary_parenthesis 20 | final json = (jsonDecode(result.body) as Map); 21 | final elements = json['items'].cast>() 22 | as List>; 23 | final list = elements.map((e) => Repository.fromJson(e)).toList(); 24 | return list; 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /lib/controllers/theme_mode_controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:state_notifier/state_notifier.dart'; 4 | 5 | class ThemeModeController extends StateNotifier { 6 | ThemeModeController._() : super(ThemeMode.dark); 7 | 8 | static final provider = StateNotifierProvider( 9 | (ref) => ThemeModeController._(), 10 | ); 11 | 12 | void toggle() { 13 | state = state == ThemeMode.light ? ThemeMode.dark : ThemeMode.light; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:github_repo_explorer/controllers/theme_mode_controller.dart'; 3 | import 'package:github_repo_explorer/pages/tab/main_tab.dart'; 4 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 5 | import 'package:flutter_hooks/flutter_hooks.dart'; 6 | 7 | void main() => runApp(ProviderScope(child: MyApp())); 8 | 9 | class MyApp extends HookWidget { 10 | @override 11 | Widget build(BuildContext context) { 12 | return MaterialApp( 13 | title: 'Flutter Demo', 14 | themeMode: useProvider(ThemeModeController.provider.state), 15 | darkTheme: ThemeData.dark(), 16 | theme: ThemeData.light(), 17 | home: const MainTab(), 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/models/models.dart: -------------------------------------------------------------------------------- 1 | export './repository.dart'; 2 | -------------------------------------------------------------------------------- /lib/models/repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | 4 | part 'repository.freezed.dart'; 5 | part 'repository.g.dart'; 6 | 7 | @freezed 8 | abstract class Repository with _$Repository { 9 | factory Repository({ 10 | @Default(0) int id, 11 | @Default('') String name, 12 | @Default(0) @JsonKey(name: 'stargazers_count') int stargazers, 13 | @Default('') String description, 14 | @required RepositoryOwner owner, 15 | }) = _Repository; 16 | 17 | factory Repository.fromJson(Map json) => 18 | _$RepositoryFromJson(json); 19 | 20 | @late 21 | String get formattedStargazers => (() { 22 | if (stargazers / 1000000 >= 1) { 23 | return '${(stargazers / 1000000).toStringAsFixed(1)}M'; 24 | } else if (stargazers / 1000 >= 1) { 25 | return '${(stargazers / 1000).toStringAsFixed(1)}K'; 26 | } else { 27 | return stargazers.toString(); 28 | } 29 | })(); 30 | } 31 | 32 | @freezed 33 | abstract class RepositoryOwner with _$RepositoryOwner { 34 | const factory RepositoryOwner({ 35 | @Default(0) int id, 36 | @Default('') @JsonKey(name: 'login') String name, 37 | @Default('') @JsonKey(name: 'avatar_url') String avatarURL, 38 | }) = _RepositoryOwner; 39 | 40 | factory RepositoryOwner.fromJson(Map json) => 41 | _$RepositoryOwnerFromJson(json); 42 | } 43 | -------------------------------------------------------------------------------- /lib/models/repository.freezed.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | // ignore_for_file: deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies 3 | 4 | part of 'repository.dart'; 5 | 6 | // ************************************************************************** 7 | // FreezedGenerator 8 | // ************************************************************************** 9 | 10 | T _$identity(T value) => value; 11 | Repository _$RepositoryFromJson(Map json) { 12 | return _Repository.fromJson(json); 13 | } 14 | 15 | class _$RepositoryTearOff { 16 | const _$RepositoryTearOff(); 17 | 18 | // ignore: unused_element 19 | _Repository call( 20 | {int id = 0, 21 | String name = '', 22 | @JsonKey(name: 'stargazers_count') int stargazers = 0, 23 | String description = '', 24 | @required RepositoryOwner owner}) { 25 | return _Repository( 26 | id: id, 27 | name: name, 28 | stargazers: stargazers, 29 | description: description, 30 | owner: owner, 31 | ); 32 | } 33 | } 34 | 35 | // ignore: unused_element 36 | const $Repository = _$RepositoryTearOff(); 37 | 38 | mixin _$Repository { 39 | int get id; 40 | String get name; 41 | @JsonKey(name: 'stargazers_count') 42 | int get stargazers; 43 | String get description; 44 | RepositoryOwner get owner; 45 | 46 | Map toJson(); 47 | $RepositoryCopyWith get copyWith; 48 | } 49 | 50 | abstract class $RepositoryCopyWith<$Res> { 51 | factory $RepositoryCopyWith( 52 | Repository value, $Res Function(Repository) then) = 53 | _$RepositoryCopyWithImpl<$Res>; 54 | $Res call( 55 | {int id, 56 | String name, 57 | @JsonKey(name: 'stargazers_count') int stargazers, 58 | String description, 59 | RepositoryOwner owner}); 60 | 61 | $RepositoryOwnerCopyWith<$Res> get owner; 62 | } 63 | 64 | class _$RepositoryCopyWithImpl<$Res> implements $RepositoryCopyWith<$Res> { 65 | _$RepositoryCopyWithImpl(this._value, this._then); 66 | 67 | final Repository _value; 68 | // ignore: unused_field 69 | final $Res Function(Repository) _then; 70 | 71 | @override 72 | $Res call({ 73 | Object id = freezed, 74 | Object name = freezed, 75 | Object stargazers = freezed, 76 | Object description = freezed, 77 | Object owner = freezed, 78 | }) { 79 | return _then(_value.copyWith( 80 | id: id == freezed ? _value.id : id as int, 81 | name: name == freezed ? _value.name : name as String, 82 | stargazers: stargazers == freezed ? _value.stargazers : stargazers as int, 83 | description: 84 | description == freezed ? _value.description : description as String, 85 | owner: owner == freezed ? _value.owner : owner as RepositoryOwner, 86 | )); 87 | } 88 | 89 | @override 90 | $RepositoryOwnerCopyWith<$Res> get owner { 91 | if (_value.owner == null) { 92 | return null; 93 | } 94 | return $RepositoryOwnerCopyWith<$Res>(_value.owner, (value) { 95 | return _then(_value.copyWith(owner: value)); 96 | }); 97 | } 98 | } 99 | 100 | abstract class _$RepositoryCopyWith<$Res> implements $RepositoryCopyWith<$Res> { 101 | factory _$RepositoryCopyWith( 102 | _Repository value, $Res Function(_Repository) then) = 103 | __$RepositoryCopyWithImpl<$Res>; 104 | @override 105 | $Res call( 106 | {int id, 107 | String name, 108 | @JsonKey(name: 'stargazers_count') int stargazers, 109 | String description, 110 | RepositoryOwner owner}); 111 | 112 | @override 113 | $RepositoryOwnerCopyWith<$Res> get owner; 114 | } 115 | 116 | class __$RepositoryCopyWithImpl<$Res> extends _$RepositoryCopyWithImpl<$Res> 117 | implements _$RepositoryCopyWith<$Res> { 118 | __$RepositoryCopyWithImpl( 119 | _Repository _value, $Res Function(_Repository) _then) 120 | : super(_value, (v) => _then(v as _Repository)); 121 | 122 | @override 123 | _Repository get _value => super._value as _Repository; 124 | 125 | @override 126 | $Res call({ 127 | Object id = freezed, 128 | Object name = freezed, 129 | Object stargazers = freezed, 130 | Object description = freezed, 131 | Object owner = freezed, 132 | }) { 133 | return _then(_Repository( 134 | id: id == freezed ? _value.id : id as int, 135 | name: name == freezed ? _value.name : name as String, 136 | stargazers: stargazers == freezed ? _value.stargazers : stargazers as int, 137 | description: 138 | description == freezed ? _value.description : description as String, 139 | owner: owner == freezed ? _value.owner : owner as RepositoryOwner, 140 | )); 141 | } 142 | } 143 | 144 | @JsonSerializable() 145 | class _$_Repository with DiagnosticableTreeMixin implements _Repository { 146 | _$_Repository( 147 | {this.id = 0, 148 | this.name = '', 149 | @JsonKey(name: 'stargazers_count') this.stargazers = 0, 150 | this.description = '', 151 | @required this.owner}) 152 | : assert(id != null), 153 | assert(name != null), 154 | assert(stargazers != null), 155 | assert(description != null), 156 | assert(owner != null); 157 | 158 | factory _$_Repository.fromJson(Map json) => 159 | _$_$_RepositoryFromJson(json); 160 | 161 | @JsonKey(defaultValue: 0) 162 | @override 163 | final int id; 164 | @JsonKey(defaultValue: '') 165 | @override 166 | final String name; 167 | @override 168 | @JsonKey(name: 'stargazers_count') 169 | final int stargazers; 170 | @JsonKey(defaultValue: '') 171 | @override 172 | final String description; 173 | @override 174 | final RepositoryOwner owner; 175 | 176 | bool _didformattedStargazers = false; 177 | String _formattedStargazers; 178 | 179 | @override 180 | String get formattedStargazers { 181 | if (_didformattedStargazers == false) { 182 | _didformattedStargazers = true; 183 | _formattedStargazers = (() { 184 | if (stargazers / 1000000 >= 1) { 185 | return '${(stargazers / 1000000).toStringAsFixed(1)}M'; 186 | } else if (stargazers / 1000 >= 1) { 187 | return '${(stargazers / 1000).toStringAsFixed(1)}K'; 188 | } else { 189 | return stargazers.toString(); 190 | } 191 | })(); 192 | } 193 | return _formattedStargazers; 194 | } 195 | 196 | @override 197 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { 198 | return 'Repository(id: $id, name: $name, stargazers: $stargazers, description: $description, owner: $owner, formattedStargazers: $formattedStargazers)'; 199 | } 200 | 201 | @override 202 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { 203 | super.debugFillProperties(properties); 204 | properties 205 | ..add(DiagnosticsProperty('type', 'Repository')) 206 | ..add(DiagnosticsProperty('id', id)) 207 | ..add(DiagnosticsProperty('name', name)) 208 | ..add(DiagnosticsProperty('stargazers', stargazers)) 209 | ..add(DiagnosticsProperty('description', description)) 210 | ..add(DiagnosticsProperty('owner', owner)) 211 | ..add(DiagnosticsProperty('formattedStargazers', formattedStargazers)); 212 | } 213 | 214 | @override 215 | bool operator ==(dynamic other) { 216 | return identical(this, other) || 217 | (other is _Repository && 218 | (identical(other.id, id) || 219 | const DeepCollectionEquality().equals(other.id, id)) && 220 | (identical(other.name, name) || 221 | const DeepCollectionEquality().equals(other.name, name)) && 222 | (identical(other.stargazers, stargazers) || 223 | const DeepCollectionEquality() 224 | .equals(other.stargazers, stargazers)) && 225 | (identical(other.description, description) || 226 | const DeepCollectionEquality() 227 | .equals(other.description, description)) && 228 | (identical(other.owner, owner) || 229 | const DeepCollectionEquality().equals(other.owner, owner))); 230 | } 231 | 232 | @override 233 | int get hashCode => 234 | runtimeType.hashCode ^ 235 | const DeepCollectionEquality().hash(id) ^ 236 | const DeepCollectionEquality().hash(name) ^ 237 | const DeepCollectionEquality().hash(stargazers) ^ 238 | const DeepCollectionEquality().hash(description) ^ 239 | const DeepCollectionEquality().hash(owner); 240 | 241 | @override 242 | _$RepositoryCopyWith<_Repository> get copyWith => 243 | __$RepositoryCopyWithImpl<_Repository>(this, _$identity); 244 | 245 | @override 246 | Map toJson() { 247 | return _$_$_RepositoryToJson(this); 248 | } 249 | } 250 | 251 | abstract class _Repository implements Repository { 252 | factory _Repository( 253 | {int id, 254 | String name, 255 | @JsonKey(name: 'stargazers_count') int stargazers, 256 | String description, 257 | @required RepositoryOwner owner}) = _$_Repository; 258 | 259 | factory _Repository.fromJson(Map json) = 260 | _$_Repository.fromJson; 261 | 262 | @override 263 | int get id; 264 | @override 265 | String get name; 266 | @override 267 | @JsonKey(name: 'stargazers_count') 268 | int get stargazers; 269 | @override 270 | String get description; 271 | @override 272 | RepositoryOwner get owner; 273 | @override 274 | _$RepositoryCopyWith<_Repository> get copyWith; 275 | } 276 | 277 | RepositoryOwner _$RepositoryOwnerFromJson(Map json) { 278 | return _RepositoryOwner.fromJson(json); 279 | } 280 | 281 | class _$RepositoryOwnerTearOff { 282 | const _$RepositoryOwnerTearOff(); 283 | 284 | // ignore: unused_element 285 | _RepositoryOwner call( 286 | {int id = 0, 287 | @JsonKey(name: 'login') String name = '', 288 | @JsonKey(name: 'avatar_url') String avatarURL = ''}) { 289 | return _RepositoryOwner( 290 | id: id, 291 | name: name, 292 | avatarURL: avatarURL, 293 | ); 294 | } 295 | } 296 | 297 | // ignore: unused_element 298 | const $RepositoryOwner = _$RepositoryOwnerTearOff(); 299 | 300 | mixin _$RepositoryOwner { 301 | int get id; 302 | @JsonKey(name: 'login') 303 | String get name; 304 | @JsonKey(name: 'avatar_url') 305 | String get avatarURL; 306 | 307 | Map toJson(); 308 | $RepositoryOwnerCopyWith get copyWith; 309 | } 310 | 311 | abstract class $RepositoryOwnerCopyWith<$Res> { 312 | factory $RepositoryOwnerCopyWith( 313 | RepositoryOwner value, $Res Function(RepositoryOwner) then) = 314 | _$RepositoryOwnerCopyWithImpl<$Res>; 315 | $Res call( 316 | {int id, 317 | @JsonKey(name: 'login') String name, 318 | @JsonKey(name: 'avatar_url') String avatarURL}); 319 | } 320 | 321 | class _$RepositoryOwnerCopyWithImpl<$Res> 322 | implements $RepositoryOwnerCopyWith<$Res> { 323 | _$RepositoryOwnerCopyWithImpl(this._value, this._then); 324 | 325 | final RepositoryOwner _value; 326 | // ignore: unused_field 327 | final $Res Function(RepositoryOwner) _then; 328 | 329 | @override 330 | $Res call({ 331 | Object id = freezed, 332 | Object name = freezed, 333 | Object avatarURL = freezed, 334 | }) { 335 | return _then(_value.copyWith( 336 | id: id == freezed ? _value.id : id as int, 337 | name: name == freezed ? _value.name : name as String, 338 | avatarURL: avatarURL == freezed ? _value.avatarURL : avatarURL as String, 339 | )); 340 | } 341 | } 342 | 343 | abstract class _$RepositoryOwnerCopyWith<$Res> 344 | implements $RepositoryOwnerCopyWith<$Res> { 345 | factory _$RepositoryOwnerCopyWith( 346 | _RepositoryOwner value, $Res Function(_RepositoryOwner) then) = 347 | __$RepositoryOwnerCopyWithImpl<$Res>; 348 | @override 349 | $Res call( 350 | {int id, 351 | @JsonKey(name: 'login') String name, 352 | @JsonKey(name: 'avatar_url') String avatarURL}); 353 | } 354 | 355 | class __$RepositoryOwnerCopyWithImpl<$Res> 356 | extends _$RepositoryOwnerCopyWithImpl<$Res> 357 | implements _$RepositoryOwnerCopyWith<$Res> { 358 | __$RepositoryOwnerCopyWithImpl( 359 | _RepositoryOwner _value, $Res Function(_RepositoryOwner) _then) 360 | : super(_value, (v) => _then(v as _RepositoryOwner)); 361 | 362 | @override 363 | _RepositoryOwner get _value => super._value as _RepositoryOwner; 364 | 365 | @override 366 | $Res call({ 367 | Object id = freezed, 368 | Object name = freezed, 369 | Object avatarURL = freezed, 370 | }) { 371 | return _then(_RepositoryOwner( 372 | id: id == freezed ? _value.id : id as int, 373 | name: name == freezed ? _value.name : name as String, 374 | avatarURL: avatarURL == freezed ? _value.avatarURL : avatarURL as String, 375 | )); 376 | } 377 | } 378 | 379 | @JsonSerializable() 380 | class _$_RepositoryOwner 381 | with DiagnosticableTreeMixin 382 | implements _RepositoryOwner { 383 | const _$_RepositoryOwner( 384 | {this.id = 0, 385 | @JsonKey(name: 'login') this.name = '', 386 | @JsonKey(name: 'avatar_url') this.avatarURL = ''}) 387 | : assert(id != null), 388 | assert(name != null), 389 | assert(avatarURL != null); 390 | 391 | factory _$_RepositoryOwner.fromJson(Map json) => 392 | _$_$_RepositoryOwnerFromJson(json); 393 | 394 | @JsonKey(defaultValue: 0) 395 | @override 396 | final int id; 397 | @override 398 | @JsonKey(name: 'login') 399 | final String name; 400 | @override 401 | @JsonKey(name: 'avatar_url') 402 | final String avatarURL; 403 | 404 | @override 405 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { 406 | return 'RepositoryOwner(id: $id, name: $name, avatarURL: $avatarURL)'; 407 | } 408 | 409 | @override 410 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { 411 | super.debugFillProperties(properties); 412 | properties 413 | ..add(DiagnosticsProperty('type', 'RepositoryOwner')) 414 | ..add(DiagnosticsProperty('id', id)) 415 | ..add(DiagnosticsProperty('name', name)) 416 | ..add(DiagnosticsProperty('avatarURL', avatarURL)); 417 | } 418 | 419 | @override 420 | bool operator ==(dynamic other) { 421 | return identical(this, other) || 422 | (other is _RepositoryOwner && 423 | (identical(other.id, id) || 424 | const DeepCollectionEquality().equals(other.id, id)) && 425 | (identical(other.name, name) || 426 | const DeepCollectionEquality().equals(other.name, name)) && 427 | (identical(other.avatarURL, avatarURL) || 428 | const DeepCollectionEquality() 429 | .equals(other.avatarURL, avatarURL))); 430 | } 431 | 432 | @override 433 | int get hashCode => 434 | runtimeType.hashCode ^ 435 | const DeepCollectionEquality().hash(id) ^ 436 | const DeepCollectionEquality().hash(name) ^ 437 | const DeepCollectionEquality().hash(avatarURL); 438 | 439 | @override 440 | _$RepositoryOwnerCopyWith<_RepositoryOwner> get copyWith => 441 | __$RepositoryOwnerCopyWithImpl<_RepositoryOwner>(this, _$identity); 442 | 443 | @override 444 | Map toJson() { 445 | return _$_$_RepositoryOwnerToJson(this); 446 | } 447 | } 448 | 449 | abstract class _RepositoryOwner implements RepositoryOwner { 450 | const factory _RepositoryOwner( 451 | {int id, 452 | @JsonKey(name: 'login') String name, 453 | @JsonKey(name: 'avatar_url') String avatarURL}) = _$_RepositoryOwner; 454 | 455 | factory _RepositoryOwner.fromJson(Map json) = 456 | _$_RepositoryOwner.fromJson; 457 | 458 | @override 459 | int get id; 460 | @override 461 | @JsonKey(name: 'login') 462 | String get name; 463 | @override 464 | @JsonKey(name: 'avatar_url') 465 | String get avatarURL; 466 | @override 467 | _$RepositoryOwnerCopyWith<_RepositoryOwner> get copyWith; 468 | } 469 | -------------------------------------------------------------------------------- /lib/models/repository.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'repository.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$_Repository _$_$_RepositoryFromJson(Map json) { 10 | return _$_Repository( 11 | id: json['id'] as int ?? 0, 12 | name: json['name'] as String ?? '', 13 | stargazers: json['stargazers_count'] as int, 14 | description: json['description'] as String ?? '', 15 | owner: json['owner'] == null 16 | ? null 17 | : RepositoryOwner.fromJson((json['owner'] as Map)?.map( 18 | (k, e) => MapEntry(k as String, e), 19 | )), 20 | ); 21 | } 22 | 23 | Map _$_$_RepositoryToJson(_$_Repository instance) => 24 | { 25 | 'id': instance.id, 26 | 'name': instance.name, 27 | 'stargazers_count': instance.stargazers, 28 | 'description': instance.description, 29 | 'owner': instance.owner?.toJson(), 30 | }; 31 | 32 | _$_RepositoryOwner _$_$_RepositoryOwnerFromJson(Map json) { 33 | return _$_RepositoryOwner( 34 | id: json['id'] as int ?? 0, 35 | name: json['login'] as String, 36 | avatarURL: json['avatar_url'] as String, 37 | ); 38 | } 39 | 40 | Map _$_$_RepositoryOwnerToJson(_$_RepositoryOwner instance) => 41 | { 42 | 'id': instance.id, 43 | 'login': instance.name, 44 | 'avatar_url': instance.avatarURL, 45 | }; 46 | -------------------------------------------------------------------------------- /lib/pages/bookmark/bookmark_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_hooks/flutter_hooks.dart'; 3 | import 'package:github_repo_explorer/pages/bookmarks/bookmarks_controller.dart'; 4 | import 'package:github_repo_explorer/widgets/repository_content.dart'; 5 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 6 | 7 | class BookmarkPage extends HookWidget { 8 | const BookmarkPage({this.id}); 9 | 10 | final int id; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | final repository = 15 | useProvider(BookmarksController.provider.state).repository(id); 16 | if (repository == null) { 17 | return const SizedBox.shrink(); 18 | } 19 | final isBookmarked = 20 | useProvider(BookmarksController.provider.state).has(repository); 21 | 22 | return GestureDetector( 23 | child: RepositoryContent( 24 | repository: repository, 25 | isBookmarked: isBookmarked, 26 | onPressedAddBookmark: () => 27 | BookmarksController.provider.read(context).add(repository), 28 | onPressedDeleteBookmark: () { 29 | BookmarksController.provider.read(context).delete(repository); 30 | Navigator.of(context).pop(); 31 | }, 32 | ), 33 | onTap: Navigator.of(context).pop, 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/pages/bookmarks/bookmarks_controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | import 'package:github_repo_explorer/models/models.dart'; 4 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 5 | import 'package:state_notifier/state_notifier.dart'; 6 | 7 | part 'bookmarks_controller.freezed.dart'; 8 | 9 | @freezed 10 | abstract class BookmarksState implements _$BookmarksState { 11 | factory BookmarksState({ 12 | @Default([]) List repositories, 13 | }) = _BookmarksState; 14 | 15 | BookmarksState._(); 16 | @late 17 | Map get _map => Map.fromEntries( 18 | repositories.map( 19 | (r) => MapEntry(r.id, r), 20 | ), 21 | ); 22 | 23 | @late 24 | bool get isEmpty => repositories.isEmpty; 25 | 26 | Repository repository(int id) => _map[id]; 27 | bool has(Repository repository) => 28 | repositories.firstWhere( 29 | (r) => r.id == repository.id, 30 | orElse: () => null, 31 | ) != 32 | null; 33 | } 34 | 35 | class BookmarksController extends StateNotifier { 36 | BookmarksController._(this._ref) : super(BookmarksState()); 37 | 38 | static final provider = StateNotifierProvider( 39 | (ref) => BookmarksController._(ref), 40 | ); 41 | 42 | ProviderReference _ref; 43 | 44 | void add(Repository repository) { 45 | if (state.has(repository)) { 46 | return; 47 | } 48 | state = state.copyWith( 49 | repositories: [...state.repositories]..add(repository), 50 | ); 51 | } 52 | 53 | void delete(Repository repository) { 54 | state = state.copyWith( 55 | repositories: [...state.repositories] 56 | ..removeWhere((r) => r.id == repository.id), 57 | ); 58 | } 59 | 60 | void deleteAll() { 61 | state = state.copyWith(repositories: []); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/pages/bookmarks/bookmarks_controller.freezed.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | // ignore_for_file: deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies 3 | 4 | part of 'bookmarks_controller.dart'; 5 | 6 | // ************************************************************************** 7 | // FreezedGenerator 8 | // ************************************************************************** 9 | 10 | T _$identity(T value) => value; 11 | 12 | class _$BookmarksStateTearOff { 13 | const _$BookmarksStateTearOff(); 14 | 15 | // ignore: unused_element 16 | _BookmarksState call({List repositories = const []}) { 17 | return _BookmarksState( 18 | repositories: repositories, 19 | ); 20 | } 21 | } 22 | 23 | // ignore: unused_element 24 | const $BookmarksState = _$BookmarksStateTearOff(); 25 | 26 | mixin _$BookmarksState { 27 | List get repositories; 28 | 29 | $BookmarksStateCopyWith get copyWith; 30 | } 31 | 32 | abstract class $BookmarksStateCopyWith<$Res> { 33 | factory $BookmarksStateCopyWith( 34 | BookmarksState value, $Res Function(BookmarksState) then) = 35 | _$BookmarksStateCopyWithImpl<$Res>; 36 | $Res call({List repositories}); 37 | } 38 | 39 | class _$BookmarksStateCopyWithImpl<$Res> 40 | implements $BookmarksStateCopyWith<$Res> { 41 | _$BookmarksStateCopyWithImpl(this._value, this._then); 42 | 43 | final BookmarksState _value; 44 | // ignore: unused_field 45 | final $Res Function(BookmarksState) _then; 46 | 47 | @override 48 | $Res call({ 49 | Object repositories = freezed, 50 | }) { 51 | return _then(_value.copyWith( 52 | repositories: repositories == freezed 53 | ? _value.repositories 54 | : repositories as List, 55 | )); 56 | } 57 | } 58 | 59 | abstract class _$BookmarksStateCopyWith<$Res> 60 | implements $BookmarksStateCopyWith<$Res> { 61 | factory _$BookmarksStateCopyWith( 62 | _BookmarksState value, $Res Function(_BookmarksState) then) = 63 | __$BookmarksStateCopyWithImpl<$Res>; 64 | @override 65 | $Res call({List repositories}); 66 | } 67 | 68 | class __$BookmarksStateCopyWithImpl<$Res> 69 | extends _$BookmarksStateCopyWithImpl<$Res> 70 | implements _$BookmarksStateCopyWith<$Res> { 71 | __$BookmarksStateCopyWithImpl( 72 | _BookmarksState _value, $Res Function(_BookmarksState) _then) 73 | : super(_value, (v) => _then(v as _BookmarksState)); 74 | 75 | @override 76 | _BookmarksState get _value => super._value as _BookmarksState; 77 | 78 | @override 79 | $Res call({ 80 | Object repositories = freezed, 81 | }) { 82 | return _then(_BookmarksState( 83 | repositories: repositories == freezed 84 | ? _value.repositories 85 | : repositories as List, 86 | )); 87 | } 88 | } 89 | 90 | class _$_BookmarksState extends _BookmarksState with DiagnosticableTreeMixin { 91 | _$_BookmarksState({this.repositories = const []}) 92 | : assert(repositories != null), 93 | super._(); 94 | 95 | @JsonKey(defaultValue: const []) 96 | @override 97 | final List repositories; 98 | 99 | bool _did_map = false; 100 | Map __map; 101 | 102 | @override 103 | Map get _map { 104 | if (_did_map == false) { 105 | _did_map = true; 106 | __map = Map.fromEntries( 107 | repositories.map( 108 | (r) => MapEntry(r.id, r), 109 | ), 110 | ); 111 | } 112 | return __map; 113 | } 114 | 115 | bool _didisEmpty = false; 116 | bool _isEmpty; 117 | 118 | @override 119 | bool get isEmpty { 120 | if (_didisEmpty == false) { 121 | _didisEmpty = true; 122 | _isEmpty = repositories.isEmpty; 123 | } 124 | return _isEmpty; 125 | } 126 | 127 | @override 128 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { 129 | return 'BookmarksState(repositories: $repositories, _map: $_map, isEmpty: $isEmpty)'; 130 | } 131 | 132 | @override 133 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { 134 | super.debugFillProperties(properties); 135 | properties 136 | ..add(DiagnosticsProperty('type', 'BookmarksState')) 137 | ..add(DiagnosticsProperty('repositories', repositories)) 138 | ..add(DiagnosticsProperty('_map', _map)) 139 | ..add(DiagnosticsProperty('isEmpty', isEmpty)); 140 | } 141 | 142 | @override 143 | bool operator ==(dynamic other) { 144 | return identical(this, other) || 145 | (other is _BookmarksState && 146 | (identical(other.repositories, repositories) || 147 | const DeepCollectionEquality() 148 | .equals(other.repositories, repositories))); 149 | } 150 | 151 | @override 152 | int get hashCode => 153 | runtimeType.hashCode ^ const DeepCollectionEquality().hash(repositories); 154 | 155 | @override 156 | _$BookmarksStateCopyWith<_BookmarksState> get copyWith => 157 | __$BookmarksStateCopyWithImpl<_BookmarksState>(this, _$identity); 158 | } 159 | 160 | abstract class _BookmarksState extends BookmarksState { 161 | _BookmarksState._() : super._(); 162 | factory _BookmarksState({List repositories}) = _$_BookmarksState; 163 | 164 | @override 165 | List get repositories; 166 | @override 167 | _$BookmarksStateCopyWith<_BookmarksState> get copyWith; 168 | } 169 | -------------------------------------------------------------------------------- /lib/pages/bookmarks/bookmarks_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:adaptive_dialog/adaptive_dialog.dart'; 2 | import 'package:animations/animations.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:github_repo_explorer/pages/bookmark/bookmark_page.dart'; 5 | import 'package:github_repo_explorer/pages/bookmarks/bookmarks_controller.dart'; 6 | import 'package:github_repo_explorer/pages/repositories/repositories_item.dart'; 7 | import 'package:github_repo_explorer/widgets/widgets.dart'; 8 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 9 | import 'package:flutter_hooks/flutter_hooks.dart'; 10 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; 11 | 12 | class BookmarksPage extends HookWidget { 13 | const BookmarksPage(); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar( 19 | title: const Text('Bookmarks'), 20 | actions: [ 21 | IconButton( 22 | icon: Icon(MdiIcons.delete), 23 | onPressed: () async { 24 | final result = await showOkCancelAlertDialog( 25 | context: context, 26 | title: 'Confirm', 27 | message: 'Are you sure to delete all bookmarks?', 28 | okLabel: 'Delete', 29 | cancelLabel: 'Cancel', 30 | isDestructiveAction: true, 31 | ); 32 | if (result != OkCancelResult.ok) { 33 | return; 34 | } 35 | BookmarksController.provider.read(context).deleteAll(); 36 | }, 37 | ), 38 | ], 39 | ), 40 | body: _body(), 41 | ); 42 | } 43 | 44 | Widget _body() { 45 | final isEmpty = useProvider( 46 | BookmarksController.provider.state.select((s) => s.isEmpty)); 47 | return isEmpty ? const _EmptyView() : const _List(); 48 | } 49 | } 50 | 51 | class _List extends HookWidget { 52 | const _List(); 53 | 54 | @override 55 | Widget build(BuildContext context) { 56 | final repositories = useProvider( 57 | BookmarksController.provider.state.select((s) => s.repositories), 58 | ); 59 | 60 | return ListView.separated( 61 | itemBuilder: (context, index) => RepositoriesItem( 62 | id: repositories[index].id, 63 | onTap: () async { 64 | await showModal( 65 | context: context, 66 | configuration: const FadeScaleTransitionConfiguration(), 67 | builder: (_) => BookmarkPage(id: repositories[index].id), 68 | ); 69 | }, 70 | ), 71 | separatorBuilder: (_, __) => Gaps.xsmall, 72 | itemCount: repositories.length, 73 | padding: const EdgeInsets.all(Space.xsmall), 74 | ); 75 | } 76 | } 77 | 78 | class _EmptyView extends StatelessWidget { 79 | const _EmptyView(); 80 | 81 | @override 82 | Widget build(BuildContext context) { 83 | return const Center( 84 | child: Text( 85 | 'There are no bookmarks.\nLet\'s try to add bookmark!', 86 | textAlign: TextAlign.center, 87 | ), 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/pages/repositories/repositories_controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | import 'package:github_repo_explorer/api/github_api.dart'; 4 | import 'package:github_repo_explorer/models/models.dart'; 5 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 6 | import 'package:state_notifier/state_notifier.dart'; 7 | 8 | part 'repositories_controller.freezed.dart'; 9 | 10 | enum RepositoriesViewStatus { 11 | initial, 12 | loading, 13 | loaded, 14 | error, 15 | empty, 16 | } 17 | 18 | @freezed 19 | abstract class RepositoriesState implements _$RepositoriesState { 20 | factory RepositoriesState({ 21 | @Default(RepositoriesViewStatus.initial) RepositoriesViewStatus status, 22 | @Default([]) List repositories, 23 | }) = _RepositoriesState; 24 | 25 | RepositoriesState._(); 26 | 27 | @late 28 | Map get _map => Map.fromEntries( 29 | repositories.map( 30 | (r) => MapEntry(r.id, r), 31 | ), 32 | ); 33 | 34 | Repository repository(int id) => _map[id]; 35 | } 36 | 37 | class RepositoriesController extends StateNotifier { 38 | RepositoriesController._(this._ref) : super(RepositoriesState()) { 39 | _load(); 40 | } 41 | static final provider = StateNotifierProvider( 42 | (ref) => RepositoriesController._(ref), 43 | ); 44 | 45 | final ProviderReference _ref; 46 | 47 | Future _load() async { 48 | state = state.copyWith(status: RepositoriesViewStatus.loading); 49 | 50 | state = state.copyWith( 51 | status: RepositoriesViewStatus.loaded, 52 | repositories: await _ref.read( 53 | GitHubAPI.searchRepositories('flutter'), 54 | ), 55 | ); 56 | } 57 | // TODO: implement search feature. 58 | } 59 | -------------------------------------------------------------------------------- /lib/pages/repositories/repositories_controller.freezed.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | // ignore_for_file: deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies 3 | 4 | part of 'repositories_controller.dart'; 5 | 6 | // ************************************************************************** 7 | // FreezedGenerator 8 | // ************************************************************************** 9 | 10 | T _$identity(T value) => value; 11 | 12 | class _$RepositoriesStateTearOff { 13 | const _$RepositoriesStateTearOff(); 14 | 15 | // ignore: unused_element 16 | _RepositoriesState call( 17 | {RepositoriesViewStatus status = RepositoriesViewStatus.initial, 18 | List repositories = const []}) { 19 | return _RepositoriesState( 20 | status: status, 21 | repositories: repositories, 22 | ); 23 | } 24 | } 25 | 26 | // ignore: unused_element 27 | const $RepositoriesState = _$RepositoriesStateTearOff(); 28 | 29 | mixin _$RepositoriesState { 30 | RepositoriesViewStatus get status; 31 | List get repositories; 32 | 33 | $RepositoriesStateCopyWith get copyWith; 34 | } 35 | 36 | abstract class $RepositoriesStateCopyWith<$Res> { 37 | factory $RepositoriesStateCopyWith( 38 | RepositoriesState value, $Res Function(RepositoriesState) then) = 39 | _$RepositoriesStateCopyWithImpl<$Res>; 40 | $Res call({RepositoriesViewStatus status, List repositories}); 41 | } 42 | 43 | class _$RepositoriesStateCopyWithImpl<$Res> 44 | implements $RepositoriesStateCopyWith<$Res> { 45 | _$RepositoriesStateCopyWithImpl(this._value, this._then); 46 | 47 | final RepositoriesState _value; 48 | // ignore: unused_field 49 | final $Res Function(RepositoriesState) _then; 50 | 51 | @override 52 | $Res call({ 53 | Object status = freezed, 54 | Object repositories = freezed, 55 | }) { 56 | return _then(_value.copyWith( 57 | status: 58 | status == freezed ? _value.status : status as RepositoriesViewStatus, 59 | repositories: repositories == freezed 60 | ? _value.repositories 61 | : repositories as List, 62 | )); 63 | } 64 | } 65 | 66 | abstract class _$RepositoriesStateCopyWith<$Res> 67 | implements $RepositoriesStateCopyWith<$Res> { 68 | factory _$RepositoriesStateCopyWith( 69 | _RepositoriesState value, $Res Function(_RepositoriesState) then) = 70 | __$RepositoriesStateCopyWithImpl<$Res>; 71 | @override 72 | $Res call({RepositoriesViewStatus status, List repositories}); 73 | } 74 | 75 | class __$RepositoriesStateCopyWithImpl<$Res> 76 | extends _$RepositoriesStateCopyWithImpl<$Res> 77 | implements _$RepositoriesStateCopyWith<$Res> { 78 | __$RepositoriesStateCopyWithImpl( 79 | _RepositoriesState _value, $Res Function(_RepositoriesState) _then) 80 | : super(_value, (v) => _then(v as _RepositoriesState)); 81 | 82 | @override 83 | _RepositoriesState get _value => super._value as _RepositoriesState; 84 | 85 | @override 86 | $Res call({ 87 | Object status = freezed, 88 | Object repositories = freezed, 89 | }) { 90 | return _then(_RepositoriesState( 91 | status: 92 | status == freezed ? _value.status : status as RepositoriesViewStatus, 93 | repositories: repositories == freezed 94 | ? _value.repositories 95 | : repositories as List, 96 | )); 97 | } 98 | } 99 | 100 | class _$_RepositoriesState extends _RepositoriesState 101 | with DiagnosticableTreeMixin { 102 | _$_RepositoriesState( 103 | {this.status = RepositoriesViewStatus.initial, 104 | this.repositories = const []}) 105 | : assert(status != null), 106 | assert(repositories != null), 107 | super._(); 108 | 109 | @JsonKey(defaultValue: RepositoriesViewStatus.initial) 110 | @override 111 | final RepositoriesViewStatus status; 112 | @JsonKey(defaultValue: const []) 113 | @override 114 | final List repositories; 115 | 116 | bool _did_map = false; 117 | Map __map; 118 | 119 | @override 120 | Map get _map { 121 | if (_did_map == false) { 122 | _did_map = true; 123 | __map = Map.fromEntries( 124 | repositories.map( 125 | (r) => MapEntry(r.id, r), 126 | ), 127 | ); 128 | } 129 | return __map; 130 | } 131 | 132 | @override 133 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { 134 | return 'RepositoriesState(status: $status, repositories: $repositories, _map: $_map)'; 135 | } 136 | 137 | @override 138 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { 139 | super.debugFillProperties(properties); 140 | properties 141 | ..add(DiagnosticsProperty('type', 'RepositoriesState')) 142 | ..add(DiagnosticsProperty('status', status)) 143 | ..add(DiagnosticsProperty('repositories', repositories)) 144 | ..add(DiagnosticsProperty('_map', _map)); 145 | } 146 | 147 | @override 148 | bool operator ==(dynamic other) { 149 | return identical(this, other) || 150 | (other is _RepositoriesState && 151 | (identical(other.status, status) || 152 | const DeepCollectionEquality().equals(other.status, status)) && 153 | (identical(other.repositories, repositories) || 154 | const DeepCollectionEquality() 155 | .equals(other.repositories, repositories))); 156 | } 157 | 158 | @override 159 | int get hashCode => 160 | runtimeType.hashCode ^ 161 | const DeepCollectionEquality().hash(status) ^ 162 | const DeepCollectionEquality().hash(repositories); 163 | 164 | @override 165 | _$RepositoriesStateCopyWith<_RepositoriesState> get copyWith => 166 | __$RepositoriesStateCopyWithImpl<_RepositoriesState>(this, _$identity); 167 | } 168 | 169 | abstract class _RepositoriesState extends RepositoriesState { 170 | _RepositoriesState._() : super._(); 171 | factory _RepositoriesState( 172 | {RepositoriesViewStatus status, 173 | List repositories}) = _$_RepositoriesState; 174 | 175 | @override 176 | RepositoriesViewStatus get status; 177 | @override 178 | List get repositories; 179 | @override 180 | _$RepositoriesStateCopyWith<_RepositoriesState> get copyWith; 181 | } 182 | -------------------------------------------------------------------------------- /lib/pages/repositories/repositories_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:flutter_hooks/flutter_hooks.dart'; 4 | import 'package:github_repo_explorer/pages/repositories/repositories_controller.dart'; 5 | import 'package:github_repo_explorer/widgets/widgets.dart'; 6 | 7 | class RepositoriesItem extends HookWidget { 8 | const RepositoriesItem({ 9 | @required this.id, 10 | this.onTap, 11 | }); 12 | final int id; 13 | final VoidCallback onTap; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | final repository = 18 | useProvider(RepositoriesController.provider.state).repository(id); 19 | return Card( 20 | clipBehavior: Clip.antiAlias, 21 | elevation: 5, 22 | child: InkWell( 23 | child: Padding( 24 | padding: const EdgeInsets.all(Space.medium), 25 | child: Column( 26 | mainAxisSize: MainAxisSize.min, 27 | crossAxisAlignment: CrossAxisAlignment.start, 28 | children: [ 29 | RepositoryLabel(repository: repository), 30 | Gaps.xxsmall, 31 | Row( 32 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 33 | children: [ 34 | AuthorLabel(repository: repository), 35 | StargazerLabel(repository: repository), 36 | ], 37 | ), 38 | ], 39 | ), 40 | ), 41 | onTap: onTap ?? () {}, 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/pages/repositories/repositories_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations/animations.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:github_repo_explorer/controllers/theme_mode_controller.dart'; 4 | import 'package:github_repo_explorer/pages/repositories/repositories_controller.dart'; 5 | import 'package:github_repo_explorer/pages/repositories/repositories_item.dart'; 6 | import 'package:github_repo_explorer/pages/repository/repository_page.dart'; 7 | import 'package:github_repo_explorer/widgets/widgets.dart'; 8 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; 9 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 10 | import 'package:flutter_hooks/flutter_hooks.dart'; 11 | 12 | class RepositoriesPage extends HookWidget { 13 | const RepositoriesPage(); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar( 19 | title: const Text('Repositories'), 20 | actions: [ 21 | IconButton( 22 | icon: Icon(MdiIcons.themeLightDark), 23 | onPressed: useProvider(ThemeModeController.provider).toggle, 24 | ), 25 | ], 26 | ), 27 | body: _body(), 28 | ); 29 | } 30 | 31 | Widget _body() { 32 | final status = useProvider( 33 | RepositoriesController.provider.state.select( 34 | (s) => s.status, 35 | ), 36 | ); 37 | switch (status) { 38 | case RepositoriesViewStatus.loading: 39 | return const _LoadingView(); 40 | case RepositoriesViewStatus.loaded: 41 | return const _List(); 42 | case RepositoriesViewStatus.error: 43 | return const _ErrorView(); 44 | case RepositoriesViewStatus.empty: 45 | return const _EmptyView(); 46 | default: 47 | assert(false, 'invalid condition'); 48 | return const SizedBox.shrink(); 49 | } 50 | } 51 | } 52 | 53 | class _LoadingView extends StatelessWidget { 54 | const _LoadingView(); 55 | 56 | @override 57 | Widget build(BuildContext context) { 58 | return const Center( 59 | child: CircularProgressIndicator(), 60 | ); 61 | } 62 | } 63 | 64 | class _List extends HookWidget { 65 | const _List(); 66 | 67 | @override 68 | Widget build(BuildContext context) { 69 | final repositories = useProvider( 70 | RepositoriesController.provider.state.select((s) => s.repositories), 71 | ); 72 | return ListView.separated( 73 | itemBuilder: (context, index) => RepositoriesItem( 74 | id: repositories[index].id, 75 | onTap: () async { 76 | await showModal( 77 | context: context, 78 | configuration: const FadeScaleTransitionConfiguration(), 79 | builder: (_) => RepositoryPage(id: repositories[index].id), 80 | ); 81 | }, 82 | ), 83 | separatorBuilder: (_, __) => Gaps.xsmall, 84 | itemCount: repositories.length, 85 | padding: const EdgeInsets.all(Space.xsmall), 86 | ); 87 | } 88 | } 89 | 90 | class _ErrorView extends StatelessWidget { 91 | const _ErrorView(); 92 | 93 | @override 94 | Widget build(BuildContext context) { 95 | return Center( 96 | child: Column( 97 | mainAxisAlignment: MainAxisAlignment.center, 98 | children: [ 99 | const Text( 100 | 'Error occurred!!\n Please try again.', 101 | textAlign: TextAlign.center, 102 | ), 103 | Gaps.medium, 104 | OutlineButton( 105 | child: const Text('Retry'), 106 | onPressed: () { 107 | // TODO: handle retry. 108 | }, 109 | ), 110 | ], 111 | ), 112 | ); 113 | } 114 | } 115 | 116 | class _EmptyView extends StatelessWidget { 117 | const _EmptyView(); 118 | 119 | @override 120 | Widget build(BuildContext context) { 121 | return const Center( 122 | child: Text( 123 | 'Repository not found!!\n Please search with another word.', 124 | textAlign: TextAlign.center, 125 | ), 126 | ); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /lib/pages/repository/repository_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_hooks/flutter_hooks.dart'; 3 | import 'package:github_repo_explorer/pages/bookmarks/bookmarks_controller.dart'; 4 | import 'package:github_repo_explorer/pages/repositories/repositories_controller.dart'; 5 | import 'package:github_repo_explorer/widgets/repository_content.dart'; 6 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 7 | 8 | class RepositoryPage extends HookWidget { 9 | const RepositoryPage({this.id}); 10 | 11 | final int id; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | final repository = 16 | useProvider(RepositoriesController.provider.state).repository(id); 17 | 18 | if (repository == null) { 19 | return const SizedBox.shrink(); 20 | } 21 | 22 | final isBookmarked = 23 | useProvider(BookmarksController.provider.state).has(repository); 24 | 25 | return GestureDetector( 26 | child: RepositoryContent( 27 | repository: repository, 28 | isBookmarked: isBookmarked, 29 | onPressedAddBookmark: () => 30 | BookmarksController.provider.read(context).add(repository), 31 | onPressedDeleteBookmark: () => 32 | BookmarksController.provider.read(context).delete(repository), 33 | ), 34 | onTap: Navigator.of(context).pop, 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/pages/tab/main_tab.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_hooks/flutter_hooks.dart'; 3 | import 'package:github_repo_explorer/pages/bookmarks/bookmarks_page.dart'; 4 | import 'package:github_repo_explorer/pages/repositories/repositories_page.dart'; 5 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 6 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; 7 | 8 | @immutable 9 | class _Tab { 10 | const _Tab({this.page, this.item}); 11 | final Widget page; 12 | final BottomNavigationBarItem item; 13 | } 14 | 15 | final List<_Tab> _tabs = [ 16 | _Tab( 17 | page: const RepositoriesPage(), 18 | item: BottomNavigationBarItem( 19 | title: const Text('Repositories'), 20 | icon: Icon(MdiIcons.sourceRepositoryMultiple), 21 | ), 22 | ), 23 | _Tab( 24 | page: const BookmarksPage(), 25 | item: BottomNavigationBarItem( 26 | title: const Text('Bookmarks'), 27 | icon: Icon(MdiIcons.bookmark), 28 | ), 29 | ), 30 | ]; 31 | 32 | final _provider = StateProvider((ref) => 0); 33 | 34 | class MainTab extends HookWidget { 35 | const MainTab(); 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return const Scaffold( 40 | bottomNavigationBar: _BottomNavBar(), 41 | body: _Pages(), 42 | ); 43 | } 44 | } 45 | 46 | class _Pages extends HookWidget { 47 | const _Pages(); 48 | 49 | @override 50 | Widget build(BuildContext context) { 51 | return IndexedStack( 52 | index: useProvider(_provider).state, 53 | children: _tabs.map((tab) => tab.page).toList(), 54 | ); 55 | } 56 | } 57 | 58 | class _BottomNavBar extends HookWidget { 59 | const _BottomNavBar(); 60 | 61 | @override 62 | Widget build(BuildContext context) { 63 | return BottomNavigationBar( 64 | showSelectedLabels: false, 65 | showUnselectedLabels: false, 66 | currentIndex: useProvider(_provider).state, 67 | items: _tabs.map((t) => t.item).toList(), 68 | onTap: (index) => _provider.read(context).state = index, 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/widgets/author_label.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:github_repo_explorer/models/repository.dart'; 3 | import 'package:github_repo_explorer/widgets/widgets.dart'; 4 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; 5 | 6 | class AuthorLabel extends StatelessWidget { 7 | const AuthorLabel({this.repository}); 8 | final Repository repository; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Row( 13 | mainAxisSize: MainAxisSize.min, 14 | children: [ 15 | Icon( 16 | MdiIcons.account, 17 | size: 16, 18 | ), 19 | Gaps.xxsmall, 20 | Flexible( 21 | child: Text( 22 | repository.owner.name, 23 | style: Theme.of(context).textTheme.bodyText1, 24 | overflow: TextOverflow.ellipsis, 25 | ), 26 | ), 27 | ], 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/widgets/gaps.dart: -------------------------------------------------------------------------------- 1 | import 'package:gap/gap.dart'; 2 | import 'package:github_repo_explorer/widgets/space.dart'; 3 | 4 | class Gaps { 5 | const Gaps._(); 6 | 7 | static const xxsmall = Gap(Space.xxsmall); 8 | static const xsmall = Gap(Space.xsmall); 9 | static const small = Gap(Space.small); 10 | static const medium = Gap(Space.medium); 11 | } 12 | -------------------------------------------------------------------------------- /lib/widgets/repository_content.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:github_repo_explorer/models/models.dart'; 3 | import 'package:github_repo_explorer/widgets/widgets.dart'; 4 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; 5 | 6 | class RepositoryContent extends StatelessWidget { 7 | const RepositoryContent({ 8 | @required this.repository, 9 | @required this.isBookmarked, 10 | @required this.onPressedAddBookmark, 11 | @required this.onPressedDeleteBookmark, 12 | }); 13 | 14 | final Repository repository; 15 | final bool isBookmarked; 16 | final VoidCallback onPressedAddBookmark; 17 | final VoidCallback onPressedDeleteBookmark; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Padding( 22 | padding: EdgeInsets.all(Space.medium), 23 | child: Center( 24 | child: SizedBox( 25 | width: double.infinity, 26 | child: Card( 27 | child: Padding( 28 | padding: EdgeInsets.all(Space.medium), 29 | child: Column( 30 | mainAxisSize: MainAxisSize.min, 31 | crossAxisAlignment: CrossAxisAlignment.center, 32 | children: [ 33 | RepositoryLabel(repository: repository), 34 | Gaps.medium, 35 | Row( 36 | mainAxisSize: MainAxisSize.min, 37 | children: [ 38 | AuthorLabel(repository: repository), 39 | Gaps.xsmall, 40 | StargazerLabel(repository: repository), 41 | ], 42 | ), 43 | Gaps.medium, 44 | Text(repository.description), 45 | Gaps.medium, 46 | !isBookmarked 47 | ? _AddButton( 48 | onPressed: onPressedAddBookmark, 49 | ) 50 | : _DeleteButton( 51 | onPressed: onPressedDeleteBookmark, 52 | ), 53 | ], 54 | ), 55 | ), 56 | ), 57 | ), 58 | ), 59 | ); 60 | } 61 | } 62 | 63 | class _AddButton extends StatelessWidget { 64 | const _AddButton({ 65 | @required this.onPressed, 66 | }); 67 | final VoidCallback onPressed; 68 | 69 | @override 70 | Widget build(BuildContext context) { 71 | return RaisedButton( 72 | child: Row( 73 | mainAxisAlignment: MainAxisAlignment.center, 74 | children: [ 75 | Icon(MdiIcons.bookmark), 76 | const Text('Add to bookmarks'), 77 | ], 78 | ), 79 | onPressed: onPressed, 80 | ); 81 | } 82 | } 83 | 84 | class _DeleteButton extends StatelessWidget { 85 | const _DeleteButton({ 86 | @required this.onPressed, 87 | }); 88 | final VoidCallback onPressed; 89 | 90 | @override 91 | Widget build(BuildContext context) { 92 | return OutlineButton( 93 | child: Row( 94 | mainAxisAlignment: MainAxisAlignment.center, 95 | children: [ 96 | Icon(MdiIcons.bookmark), 97 | const Text('Delete from bookmarks'), 98 | ], 99 | ), 100 | onPressed: onPressed, 101 | ); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /lib/widgets/repository_label.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:github_repo_explorer/models/models.dart'; 4 | import 'package:github_repo_explorer/widgets/widgets.dart'; 5 | 6 | class RepositoryLabel extends StatelessWidget { 7 | const RepositoryLabel({ 8 | @required this.repository, 9 | }); 10 | final Repository repository; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Row( 15 | mainAxisSize: MainAxisSize.min, 16 | children: [ 17 | SizedBox( 18 | width: 20, 19 | height: 20, 20 | child: ClipRRect( 21 | borderRadius: BorderRadius.circular(4), 22 | child: CachedNetworkImage( 23 | imageUrl: repository.owner.avatarURL, 24 | fit: BoxFit.cover, 25 | ), 26 | ), 27 | ), 28 | Gaps.xsmall, 29 | Flexible( 30 | child: Text( 31 | repository.name, 32 | style: Theme.of(context).textTheme.subtitle1.copyWith( 33 | fontWeight: FontWeight.bold, 34 | ), 35 | overflow: TextOverflow.ellipsis, 36 | ), 37 | ), 38 | ], 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/widgets/space.dart: -------------------------------------------------------------------------------- 1 | class Space { 2 | const Space._(); 3 | static const double xxsmall = 4; 4 | static const double xsmall = 8; 5 | static const double small = 12; 6 | static const double medium = 16; 7 | } 8 | -------------------------------------------------------------------------------- /lib/widgets/stargazer_label.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:github_repo_explorer/models/models.dart'; 3 | import 'package:github_repo_explorer/widgets/widgets.dart'; 4 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; 5 | 6 | class StargazerLabel extends StatelessWidget { 7 | const StargazerLabel({@required this.repository}); 8 | final Repository repository; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Row( 13 | mainAxisSize: MainAxisSize.min, 14 | children: [ 15 | Icon( 16 | MdiIcons.star, 17 | size: 16, 18 | color: Colors.yellow, 19 | ), 20 | Gaps.xxsmall, 21 | Flexible( 22 | child: Text( 23 | repository.formattedStargazers, 24 | style: Theme.of(context).textTheme.bodyText1, 25 | ), 26 | ), 27 | ], 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/widgets/widgets.dart: -------------------------------------------------------------------------------- 1 | export './author_label.dart'; 2 | export './gaps.dart'; 3 | export './repository_label.dart'; 4 | export './space.dart'; 5 | export './stargazer_label.dart'; 6 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "6.0.0" 11 | adaptive_dialog: 12 | dependency: "direct main" 13 | description: 14 | name: adaptive_dialog 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "0.7.5" 18 | analyzer: 19 | dependency: transitive 20 | description: 21 | name: analyzer 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "0.39.14" 25 | animations: 26 | dependency: "direct main" 27 | description: 28 | name: animations 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.1.1" 32 | archive: 33 | dependency: transitive 34 | description: 35 | name: archive 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "2.0.13" 39 | args: 40 | dependency: transitive 41 | description: 42 | name: args 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.6.0" 46 | async: 47 | dependency: transitive 48 | description: 49 | name: async 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "2.4.1" 53 | boolean_selector: 54 | dependency: transitive 55 | description: 56 | name: boolean_selector 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "2.0.0" 60 | build: 61 | dependency: transitive 62 | description: 63 | name: build 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.3.0" 67 | build_config: 68 | dependency: transitive 69 | description: 70 | name: build_config 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "0.4.2" 74 | build_daemon: 75 | dependency: transitive 76 | description: 77 | name: build_daemon 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "2.1.4" 81 | build_resolvers: 82 | dependency: transitive 83 | description: 84 | name: build_resolvers 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "1.3.10" 88 | build_runner: 89 | dependency: "direct dev" 90 | description: 91 | name: build_runner 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "1.10.0" 95 | build_runner_core: 96 | dependency: transitive 97 | description: 98 | name: build_runner_core 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "5.2.0" 102 | built_collection: 103 | dependency: transitive 104 | description: 105 | name: built_collection 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "4.3.2" 109 | built_value: 110 | dependency: transitive 111 | description: 112 | name: built_value 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "7.1.0" 116 | cached_network_image: 117 | dependency: "direct main" 118 | description: 119 | name: cached_network_image 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "2.2.0+1" 123 | charcode: 124 | dependency: transitive 125 | description: 126 | name: charcode 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "1.1.3" 130 | checked_yaml: 131 | dependency: transitive 132 | description: 133 | name: checked_yaml 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "1.0.2" 137 | cli_util: 138 | dependency: transitive 139 | description: 140 | name: cli_util 141 | url: "https://pub.dartlang.org" 142 | source: hosted 143 | version: "0.1.4" 144 | clock: 145 | dependency: transitive 146 | description: 147 | name: clock 148 | url: "https://pub.dartlang.org" 149 | source: hosted 150 | version: "1.0.1" 151 | code_builder: 152 | dependency: transitive 153 | description: 154 | name: code_builder 155 | url: "https://pub.dartlang.org" 156 | source: hosted 157 | version: "3.4.0" 158 | collection: 159 | dependency: transitive 160 | description: 161 | name: collection 162 | url: "https://pub.dartlang.org" 163 | source: hosted 164 | version: "1.14.12" 165 | convert: 166 | dependency: transitive 167 | description: 168 | name: convert 169 | url: "https://pub.dartlang.org" 170 | source: hosted 171 | version: "2.1.1" 172 | crypto: 173 | dependency: transitive 174 | description: 175 | name: crypto 176 | url: "https://pub.dartlang.org" 177 | source: hosted 178 | version: "2.1.4" 179 | csslib: 180 | dependency: transitive 181 | description: 182 | name: csslib 183 | url: "https://pub.dartlang.org" 184 | source: hosted 185 | version: "0.16.1" 186 | cupertino_icons: 187 | dependency: "direct main" 188 | description: 189 | name: cupertino_icons 190 | url: "https://pub.dartlang.org" 191 | source: hosted 192 | version: "0.1.3" 193 | dart_style: 194 | dependency: transitive 195 | description: 196 | name: dart_style 197 | url: "https://pub.dartlang.org" 198 | source: hosted 199 | version: "1.3.6" 200 | file: 201 | dependency: transitive 202 | description: 203 | name: file 204 | url: "https://pub.dartlang.org" 205 | source: hosted 206 | version: "5.2.1" 207 | fixnum: 208 | dependency: transitive 209 | description: 210 | name: fixnum 211 | url: "https://pub.dartlang.org" 212 | source: hosted 213 | version: "0.10.11" 214 | flutter: 215 | dependency: "direct main" 216 | description: flutter 217 | source: sdk 218 | version: "0.0.0" 219 | flutter_cache_manager: 220 | dependency: transitive 221 | description: 222 | name: flutter_cache_manager 223 | url: "https://pub.dartlang.org" 224 | source: hosted 225 | version: "1.4.1" 226 | flutter_hooks: 227 | dependency: transitive 228 | description: 229 | name: flutter_hooks 230 | url: "https://pub.dartlang.org" 231 | source: hosted 232 | version: "0.12.0" 233 | flutter_riverpod: 234 | dependency: transitive 235 | description: 236 | name: flutter_riverpod 237 | url: "https://pub.dartlang.org" 238 | source: hosted 239 | version: "0.5.1" 240 | flutter_state_notifier: 241 | dependency: "direct main" 242 | description: 243 | name: flutter_state_notifier 244 | url: "https://pub.dartlang.org" 245 | source: hosted 246 | version: "0.4.2" 247 | flutter_test: 248 | dependency: "direct dev" 249 | description: flutter 250 | source: sdk 251 | version: "0.0.0" 252 | freezed: 253 | dependency: "direct dev" 254 | description: 255 | name: freezed 256 | url: "https://pub.dartlang.org" 257 | source: hosted 258 | version: "0.11.4" 259 | freezed_annotation: 260 | dependency: "direct main" 261 | description: 262 | name: freezed_annotation 263 | url: "https://pub.dartlang.org" 264 | source: hosted 265 | version: "0.11.0" 266 | gap: 267 | dependency: "direct main" 268 | description: 269 | name: gap 270 | url: "https://pub.dartlang.org" 271 | source: hosted 272 | version: "1.2.0" 273 | glob: 274 | dependency: transitive 275 | description: 276 | name: glob 277 | url: "https://pub.dartlang.org" 278 | source: hosted 279 | version: "1.2.0" 280 | google_fonts: 281 | dependency: "direct main" 282 | description: 283 | name: google_fonts 284 | url: "https://pub.dartlang.org" 285 | source: hosted 286 | version: "1.1.0" 287 | graphs: 288 | dependency: transitive 289 | description: 290 | name: graphs 291 | url: "https://pub.dartlang.org" 292 | source: hosted 293 | version: "0.2.0" 294 | hooks_riverpod: 295 | dependency: "direct main" 296 | description: 297 | name: hooks_riverpod 298 | url: "https://pub.dartlang.org" 299 | source: hosted 300 | version: "0.5.1" 301 | html: 302 | dependency: transitive 303 | description: 304 | name: html 305 | url: "https://pub.dartlang.org" 306 | source: hosted 307 | version: "0.14.0+3" 308 | http: 309 | dependency: transitive 310 | description: 311 | name: http 312 | url: "https://pub.dartlang.org" 313 | source: hosted 314 | version: "0.12.2" 315 | http_multi_server: 316 | dependency: transitive 317 | description: 318 | name: http_multi_server 319 | url: "https://pub.dartlang.org" 320 | source: hosted 321 | version: "2.2.0" 322 | http_parser: 323 | dependency: transitive 324 | description: 325 | name: http_parser 326 | url: "https://pub.dartlang.org" 327 | source: hosted 328 | version: "3.1.4" 329 | image: 330 | dependency: transitive 331 | description: 332 | name: image 333 | url: "https://pub.dartlang.org" 334 | source: hosted 335 | version: "2.1.12" 336 | intl: 337 | dependency: transitive 338 | description: 339 | name: intl 340 | url: "https://pub.dartlang.org" 341 | source: hosted 342 | version: "0.16.1" 343 | io: 344 | dependency: transitive 345 | description: 346 | name: io 347 | url: "https://pub.dartlang.org" 348 | source: hosted 349 | version: "0.3.4" 350 | js: 351 | dependency: transitive 352 | description: 353 | name: js 354 | url: "https://pub.dartlang.org" 355 | source: hosted 356 | version: "0.6.2" 357 | json_annotation: 358 | dependency: "direct dev" 359 | description: 360 | name: json_annotation 361 | url: "https://pub.dartlang.org" 362 | source: hosted 363 | version: "3.0.1" 364 | json_serializable: 365 | dependency: "direct main" 366 | description: 367 | name: json_serializable 368 | url: "https://pub.dartlang.org" 369 | source: hosted 370 | version: "3.3.0" 371 | logging: 372 | dependency: transitive 373 | description: 374 | name: logging 375 | url: "https://pub.dartlang.org" 376 | source: hosted 377 | version: "0.11.4" 378 | matcher: 379 | dependency: transitive 380 | description: 381 | name: matcher 382 | url: "https://pub.dartlang.org" 383 | source: hosted 384 | version: "0.12.6" 385 | material_design_icons_flutter: 386 | dependency: "direct main" 387 | description: 388 | name: material_design_icons_flutter 389 | url: "https://pub.dartlang.org" 390 | source: hosted 391 | version: "4.0.5345" 392 | meta: 393 | dependency: transitive 394 | description: 395 | name: meta 396 | url: "https://pub.dartlang.org" 397 | source: hosted 398 | version: "1.1.8" 399 | mime: 400 | dependency: transitive 401 | description: 402 | name: mime 403 | url: "https://pub.dartlang.org" 404 | source: hosted 405 | version: "0.9.6+3" 406 | nested: 407 | dependency: transitive 408 | description: 409 | name: nested 410 | url: "https://pub.dartlang.org" 411 | source: hosted 412 | version: "0.0.4" 413 | node_interop: 414 | dependency: transitive 415 | description: 416 | name: node_interop 417 | url: "https://pub.dartlang.org" 418 | source: hosted 419 | version: "1.1.1" 420 | node_io: 421 | dependency: transitive 422 | description: 423 | name: node_io 424 | url: "https://pub.dartlang.org" 425 | source: hosted 426 | version: "1.1.1" 427 | package_config: 428 | dependency: transitive 429 | description: 430 | name: package_config 431 | url: "https://pub.dartlang.org" 432 | source: hosted 433 | version: "1.9.3" 434 | path: 435 | dependency: transitive 436 | description: 437 | name: path 438 | url: "https://pub.dartlang.org" 439 | source: hosted 440 | version: "1.6.4" 441 | path_provider: 442 | dependency: transitive 443 | description: 444 | name: path_provider 445 | url: "https://pub.dartlang.org" 446 | source: hosted 447 | version: "1.6.11" 448 | path_provider_linux: 449 | dependency: transitive 450 | description: 451 | name: path_provider_linux 452 | url: "https://pub.dartlang.org" 453 | source: hosted 454 | version: "0.0.1+2" 455 | path_provider_macos: 456 | dependency: transitive 457 | description: 458 | name: path_provider_macos 459 | url: "https://pub.dartlang.org" 460 | source: hosted 461 | version: "0.0.4+3" 462 | path_provider_platform_interface: 463 | dependency: transitive 464 | description: 465 | name: path_provider_platform_interface 466 | url: "https://pub.dartlang.org" 467 | source: hosted 468 | version: "1.0.2" 469 | pedantic: 470 | dependency: transitive 471 | description: 472 | name: pedantic 473 | url: "https://pub.dartlang.org" 474 | source: hosted 475 | version: "1.9.0" 476 | pedantic_mono: 477 | dependency: "direct dev" 478 | description: 479 | name: pedantic_mono 480 | url: "https://pub.dartlang.org" 481 | source: hosted 482 | version: "1.9.1" 483 | petitparser: 484 | dependency: transitive 485 | description: 486 | name: petitparser 487 | url: "https://pub.dartlang.org" 488 | source: hosted 489 | version: "2.4.0" 490 | platform: 491 | dependency: transitive 492 | description: 493 | name: platform 494 | url: "https://pub.dartlang.org" 495 | source: hosted 496 | version: "2.2.1" 497 | plugin_platform_interface: 498 | dependency: transitive 499 | description: 500 | name: plugin_platform_interface 501 | url: "https://pub.dartlang.org" 502 | source: hosted 503 | version: "1.0.2" 504 | pool: 505 | dependency: transitive 506 | description: 507 | name: pool 508 | url: "https://pub.dartlang.org" 509 | source: hosted 510 | version: "1.4.0" 511 | process: 512 | dependency: transitive 513 | description: 514 | name: process 515 | url: "https://pub.dartlang.org" 516 | source: hosted 517 | version: "3.0.13" 518 | provider: 519 | dependency: transitive 520 | description: 521 | name: provider 522 | url: "https://pub.dartlang.org" 523 | source: hosted 524 | version: "4.3.1" 525 | pub_semver: 526 | dependency: transitive 527 | description: 528 | name: pub_semver 529 | url: "https://pub.dartlang.org" 530 | source: hosted 531 | version: "1.4.4" 532 | pubspec_parse: 533 | dependency: transitive 534 | description: 535 | name: pubspec_parse 536 | url: "https://pub.dartlang.org" 537 | source: hosted 538 | version: "0.1.5" 539 | quiver: 540 | dependency: transitive 541 | description: 542 | name: quiver 543 | url: "https://pub.dartlang.org" 544 | source: hosted 545 | version: "2.1.3" 546 | riverpod: 547 | dependency: transitive 548 | description: 549 | name: riverpod 550 | url: "https://pub.dartlang.org" 551 | source: hosted 552 | version: "0.5.1" 553 | rxdart: 554 | dependency: transitive 555 | description: 556 | name: rxdart 557 | url: "https://pub.dartlang.org" 558 | source: hosted 559 | version: "0.24.1" 560 | shelf: 561 | dependency: transitive 562 | description: 563 | name: shelf 564 | url: "https://pub.dartlang.org" 565 | source: hosted 566 | version: "0.7.7" 567 | shelf_web_socket: 568 | dependency: transitive 569 | description: 570 | name: shelf_web_socket 571 | url: "https://pub.dartlang.org" 572 | source: hosted 573 | version: "0.2.3" 574 | sky_engine: 575 | dependency: transitive 576 | description: flutter 577 | source: sdk 578 | version: "0.0.99" 579 | source_gen: 580 | dependency: transitive 581 | description: 582 | name: source_gen 583 | url: "https://pub.dartlang.org" 584 | source: hosted 585 | version: "0.9.6" 586 | source_span: 587 | dependency: transitive 588 | description: 589 | name: source_span 590 | url: "https://pub.dartlang.org" 591 | source: hosted 592 | version: "1.7.0" 593 | sqflite: 594 | dependency: transitive 595 | description: 596 | name: sqflite 597 | url: "https://pub.dartlang.org" 598 | source: hosted 599 | version: "1.3.1" 600 | sqflite_common: 601 | dependency: transitive 602 | description: 603 | name: sqflite_common 604 | url: "https://pub.dartlang.org" 605 | source: hosted 606 | version: "1.0.2+1" 607 | stack_trace: 608 | dependency: transitive 609 | description: 610 | name: stack_trace 611 | url: "https://pub.dartlang.org" 612 | source: hosted 613 | version: "1.9.3" 614 | state_notifier: 615 | dependency: transitive 616 | description: 617 | name: state_notifier 618 | url: "https://pub.dartlang.org" 619 | source: hosted 620 | version: "0.5.0" 621 | stream_channel: 622 | dependency: transitive 623 | description: 624 | name: stream_channel 625 | url: "https://pub.dartlang.org" 626 | source: hosted 627 | version: "2.0.0" 628 | stream_transform: 629 | dependency: transitive 630 | description: 631 | name: stream_transform 632 | url: "https://pub.dartlang.org" 633 | source: hosted 634 | version: "1.2.0" 635 | string_scanner: 636 | dependency: transitive 637 | description: 638 | name: string_scanner 639 | url: "https://pub.dartlang.org" 640 | source: hosted 641 | version: "1.0.5" 642 | synchronized: 643 | dependency: transitive 644 | description: 645 | name: synchronized 646 | url: "https://pub.dartlang.org" 647 | source: hosted 648 | version: "2.2.0+2" 649 | term_glyph: 650 | dependency: transitive 651 | description: 652 | name: term_glyph 653 | url: "https://pub.dartlang.org" 654 | source: hosted 655 | version: "1.1.0" 656 | test_api: 657 | dependency: transitive 658 | description: 659 | name: test_api 660 | url: "https://pub.dartlang.org" 661 | source: hosted 662 | version: "0.2.15" 663 | timing: 664 | dependency: transitive 665 | description: 666 | name: timing 667 | url: "https://pub.dartlang.org" 668 | source: hosted 669 | version: "0.1.1+2" 670 | typed_data: 671 | dependency: transitive 672 | description: 673 | name: typed_data 674 | url: "https://pub.dartlang.org" 675 | source: hosted 676 | version: "1.1.6" 677 | uuid: 678 | dependency: transitive 679 | description: 680 | name: uuid 681 | url: "https://pub.dartlang.org" 682 | source: hosted 683 | version: "2.2.0" 684 | vector_math: 685 | dependency: transitive 686 | description: 687 | name: vector_math 688 | url: "https://pub.dartlang.org" 689 | source: hosted 690 | version: "2.0.8" 691 | watcher: 692 | dependency: transitive 693 | description: 694 | name: watcher 695 | url: "https://pub.dartlang.org" 696 | source: hosted 697 | version: "0.9.7+15" 698 | web_socket_channel: 699 | dependency: transitive 700 | description: 701 | name: web_socket_channel 702 | url: "https://pub.dartlang.org" 703 | source: hosted 704 | version: "1.1.0" 705 | xdg_directories: 706 | dependency: transitive 707 | description: 708 | name: xdg_directories 709 | url: "https://pub.dartlang.org" 710 | source: hosted 711 | version: "0.1.0" 712 | xml: 713 | dependency: transitive 714 | description: 715 | name: xml 716 | url: "https://pub.dartlang.org" 717 | source: hosted 718 | version: "3.6.1" 719 | yaml: 720 | dependency: transitive 721 | description: 722 | name: yaml 723 | url: "https://pub.dartlang.org" 724 | source: hosted 725 | version: "2.2.1" 726 | sdks: 727 | dart: ">=2.8.0 <3.0.0" 728 | flutter: ">=1.17.5 <2.0.0" 729 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: github_repo_explorer 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.7.0 <3.0.0" 22 | flutter: ^1.17.5 23 | 24 | dependencies: 25 | flutter: 26 | sdk: flutter 27 | 28 | hooks_riverpod: ^0.5.0 29 | flutter_state_notifier: 30 | freezed_annotation: 31 | json_serializable: 32 | 33 | cupertino_icons: 34 | google_fonts: 35 | material_design_icons_flutter: 36 | gap: 37 | cached_network_image: 38 | adaptive_dialog: 39 | animations: 40 | 41 | dev_dependencies: 42 | flutter_test: 43 | sdk: flutter 44 | 45 | pedantic_mono: 46 | build_runner: 47 | freezed: 48 | json_annotation: 49 | 50 | 51 | # For information on the generic Dart part of this file, see the 52 | # following page: https://dart.dev/tools/pub/pubspec 53 | 54 | # The following section is specific to Flutter. 55 | flutter: 56 | 57 | # The following line ensures that the Material Icons font is 58 | # included with your application, so that you can use the icons in 59 | # the material Icons class. 60 | uses-material-design: true 61 | 62 | # To add assets to your application, add an assets section, like this: 63 | # assets: 64 | # - images/a_dot_burr.jpeg 65 | # - images/a_dot_ham.jpeg 66 | 67 | # An image asset can refer to one or more resolution-specific "variants", see 68 | # https://flutter.dev/assets-and-images/#resolution-aware. 69 | 70 | # For details regarding adding assets from package dependencies, see 71 | # https://flutter.dev/assets-and-images/#from-packages 72 | 73 | # To add custom fonts to your application, add a fonts section here, 74 | # in this "flutter" section. Each entry in this list should have a 75 | # "family" key with the font family name, and a "fonts" key with a 76 | # list giving the asset and other descriptors for the font. For 77 | # example: 78 | # fonts: 79 | # - family: Schyler 80 | # fonts: 81 | # - asset: fonts/Schyler-Regular.ttf 82 | # - asset: fonts/Schyler-Italic.ttf 83 | # style: italic 84 | # - family: Trajan Pro 85 | # fonts: 86 | # - asset: fonts/TrajanPro.ttf 87 | # - asset: fonts/TrajanPro_Bold.ttf 88 | # weight: 700 89 | # 90 | # For details regarding fonts from package dependencies, 91 | # see https://flutter.dev/custom-fonts/#from-packages 92 | -------------------------------------------------------------------------------- /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:github_repo_explorer/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 | --------------------------------------------------------------------------------