├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── winwang │ │ │ │ └── open_eye │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── 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-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ ├── profile │ │ └── AndroidManifest.xml │ │ └── release │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets └── images │ ├── back_mine.png │ ├── back_placeholder.png │ ├── back_ticket.png │ ├── common_empty_img.png │ ├── head_mine.jpeg │ ├── icon_about.png │ ├── icon_close.png │ ├── icon_collect.png │ ├── icon_collect_grey.png │ ├── icon_complain.png │ ├── icon_custom.png │ ├── icon_explore.png │ ├── icon_focus.png │ ├── icon_image_upload.png │ ├── icon_kefu_avator.png │ ├── icon_left_triangle_white.png │ ├── icon_my_feedback.png │ ├── icon_pause.png │ ├── icon_play.png │ ├── icon_rank.png │ ├── icon_right_triangle_white.png │ ├── icon_select_tag.png │ ├── icon_submit_question.png │ ├── icon_text_tag.png │ ├── icon_topic.png │ ├── icon_type.png │ ├── icon_unselect_tag.png │ ├── line_ticket.png │ ├── loading │ ├── common_loading.png │ ├── loding_00000.webp │ ├── loding_00001.webp │ ├── loding_00002.webp │ ├── loding_00003.webp │ ├── loding_00004.webp │ ├── loding_00005.webp │ ├── loding_00006.webp │ ├── loding_00007.webp │ ├── loding_00008.webp │ ├── loding_00009.webp │ ├── loding_00010.webp │ ├── loding_00011.webp │ ├── loding_00012.webp │ ├── loding_00013.webp │ ├── loding_00014.webp │ ├── loding_00015.webp │ ├── loding_00016.webp │ ├── loding_00017.webp │ ├── loding_00018.webp │ ├── loding_00019.webp │ ├── loding_00020.webp │ ├── loding_00021.webp │ ├── loding_00022.webp │ └── loding_00023.webp │ ├── movie-lazy.gif │ └── timeout.png ├── 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 ├── base │ ├── component │ │ └── base_component.dart │ ├── controller │ │ ├── base_controller.dart │ │ └── base_refresh_controller.dart │ └── pageWidget │ │ ├── base_stateful_widget.dart │ │ ├── base_stateless_widget.dart │ │ ├── common_stateful_widget.dart │ │ └── common_stateless_widget.dart ├── business │ ├── common │ │ └── photo_preview_page.dart │ ├── complain │ │ ├── complain_common_page.dart │ │ ├── complain_home_page.dart │ │ ├── complain_my_list_page.dart │ │ ├── complain_recod_page.dart │ │ ├── complain_submit_page.dart │ │ ├── model │ │ │ ├── Feedback_detail_list_entity.dart │ │ │ ├── Feedback_detail_list_entity.g.dart │ │ │ ├── feedback_list_item_entity.dart │ │ │ ├── feedback_list_item_entity.g.dart │ │ │ ├── my_feedback_entity.dart │ │ │ └── my_feedback_entity.g.dart │ │ └── widget │ │ │ ├── item_common_question_widget.dart │ │ │ ├── item_feedback_record_widget.dart │ │ │ ├── item_my_feedback_widget.dart │ │ │ └── item_question_type_widget.dart │ ├── custom_paint_page │ │ ├── CustomPaintPage.dart │ │ ├── model │ │ │ └── radar_view_entity.dart │ │ ├── painter │ │ │ ├── bar_chart_painter.dart │ │ │ ├── circel_chart_painter.dart │ │ │ ├── horizental_line_chart_painter.dart │ │ │ ├── line_chart_painter.dart │ │ │ ├── radar_chart_painter.dart │ │ │ └── vote_painter.dart │ │ └── widget │ │ │ ├── bar_chart_widget.dart │ │ │ ├── line_chart_widget.dart │ │ │ └── lines_chart_widget.dart │ ├── detail_page │ │ ├── detail_page.dart │ │ └── widget │ │ │ ├── item_video_detail_widget.dart │ │ │ └── video_list_component.dart │ ├── find_page │ │ ├── children_page │ │ │ ├── category_page.dart │ │ │ ├── focus_page.dart │ │ │ └── topic_page.dart │ │ ├── find_page.dart │ │ ├── model │ │ │ ├── Data.dart │ │ │ ├── Focus_Data_entity.dart │ │ │ ├── Focus_Data_entity.g.dart │ │ │ ├── Focus_Entity.dart │ │ │ ├── Focus_Entity.g.dart │ │ │ ├── Focus_Item_Entity.dart │ │ │ ├── Focus_Item_Entity.g.dart │ │ │ ├── Follow.dart │ │ │ ├── Follow.g.dart │ │ │ ├── Header_entity.dart │ │ │ ├── Header_entity.g.dart │ │ │ ├── ItemList.dart │ │ │ ├── Label.dart │ │ │ ├── Topic_data_entity.dart │ │ │ ├── Topic_data_entity.g.dart │ │ │ ├── Topic_entity.dart │ │ │ ├── Topic_entity.g.dart │ │ │ ├── Topic_item_entity.dart │ │ │ ├── Topic_item_entity.g.dart │ │ │ ├── Type_entity.dart │ │ │ └── Type_entity.g.dart │ │ └── widget │ │ │ ├── item_category_widget.dart │ │ │ ├── item_focus_inner_widget.dart │ │ │ └── item_focus_outer_widget.dart │ ├── home_page │ │ ├── home_page.dart │ │ ├── model │ │ │ ├── Author.dart │ │ │ ├── Author.g.dart │ │ │ ├── Consumption.dart │ │ │ ├── Consumption.g.dart │ │ │ ├── Cover.dart │ │ │ ├── Cover.g.dart │ │ │ ├── Data.dart │ │ │ ├── Data.g.dart │ │ │ ├── Feed_entity.dart │ │ │ ├── Feed_entity.g.dart │ │ │ ├── Follow.dart │ │ │ ├── Follow.g.dart │ │ │ ├── IssueList.dart │ │ │ ├── IssueList.g.dart │ │ │ ├── ItemList.dart │ │ │ ├── ItemList.g.dart │ │ │ ├── Provider.dart │ │ │ ├── Provider.g.dart │ │ │ ├── Shield.dart │ │ │ ├── Shield.g.dart │ │ │ ├── WebUrl.dart │ │ │ └── WebUrl.g.dart │ │ └── widget │ │ │ └── item_home_widget.dart │ ├── hot_page │ │ ├── children_page │ │ │ └── rank_list_page.dart │ │ ├── hot_page.dart │ │ └── widget │ │ │ └── item_rank_widget.dart │ ├── main_page.dart │ ├── mine_page │ │ └── mine_page.dart │ ├── seach_page │ │ └── search_page.dart │ ├── test_page │ │ └── test_page.dart │ ├── topic_detail │ │ ├── model │ │ │ ├── Topic_ItemList.dart │ │ │ ├── Topic_ItemList.g.dart │ │ │ ├── Topic_detail_entity.dart │ │ │ └── Topic_detail_entity.g.dart │ │ ├── topic_detail_page.dart │ │ └── widget │ │ │ └── item_topic_detail_widget.dart │ └── type_detail │ │ └── type_detail_page.dart ├── constant │ ├── api_constant.dart │ ├── common_constant.dart │ └── http_url.dart ├── ext │ └── get_extension.dart ├── http │ ├── apiservice │ │ ├── api_service.dart │ │ ├── api_service.g.dart │ │ ├── common_api.dart │ │ ├── common_api.g.dart │ │ ├── gateway_api.dart │ │ └── gateway_api.g.dart │ ├── app_except.dart │ ├── dio_client.dart │ ├── interceptor │ │ ├── error_interceptor.dart │ │ └── http_params_interceptor.dart │ ├── request_params.dart │ └── result │ │ ├── base_page_result.dart │ │ ├── base_page_result.g.dart │ │ ├── base_result.dart │ │ ├── base_result.g.dart │ │ ├── base_wan_result.dart │ │ └── base_wan_result.g.dart ├── main.dart ├── mixin │ ├── dialog │ │ └── dialog_mixin.dart │ └── toast │ │ └── toast_mixin.dart ├── model │ ├── upload_img_entity.dart │ └── upload_img_entity.g.dart ├── res │ ├── button_style.dart │ ├── colors.dart │ ├── strings.dart │ └── style.dart ├── route │ ├── router_auth_middleware.dart │ ├── router_utils.dart │ └── routes.dart ├── utils │ ├── injection.dart │ ├── keyboard_util.dart │ ├── log_utils.dart │ ├── method_channel.dart │ ├── preference_utils.dart │ └── sp_utils.dart └── widget │ ├── base_network_image.dart │ ├── behavior │ └── over_scroll_behavior.dart │ ├── dialog │ ├── dialog_common_style.dart │ └── dialog_loading.dart │ ├── fijkplayer_skin │ ├── fijkplayer_skin.dart │ ├── simple_panel_skin.dart │ ├── slider.dart │ └── video_config.dart │ ├── frame_animate_widget.dart │ ├── image_extends.dart │ ├── keep_alive_wrapper.dart │ ├── load_state_widget.dart │ ├── loading_widget.dart │ └── pull_smart_refresher.dart ├── pubspec.lock ├── pubspec.yaml ├── screenshot ├── 1.png ├── 10.png ├── 11.png ├── 12.png ├── 13.png ├── 14.jpg ├── 15.jpg ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png ├── 9.png ├── demo.gif └── download.png └── test └── widget_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: cf4400006550b70f28e4b4af815151d1e74846c6 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /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 flutter.compileSdkVersion 30 | 31 | compileOptions { 32 | sourceCompatibility JavaVersion.VERSION_1_8 33 | targetCompatibility JavaVersion.VERSION_1_8 34 | } 35 | 36 | signingConfigs { 37 | config { 38 | storeFile file("${app_keystore_filepath}") 39 | storePassword "${app_keystore_password}" 40 | keyAlias "${app_keystore_alias}" 41 | keyPassword "${app_keystore_keypassword}" 42 | } 43 | } 44 | 45 | kotlinOptions { 46 | jvmTarget = '1.8' 47 | } 48 | 49 | sourceSets { 50 | main.java.srcDirs += 'src/main/kotlin' 51 | } 52 | 53 | defaultConfig { 54 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 55 | applicationId "com.winwang.open_eye" 56 | minSdkVersion flutter.minSdkVersion 57 | targetSdkVersion flutter.targetSdkVersion 58 | versionCode flutterVersionCode.toInteger() 59 | versionName flutterVersionName 60 | } 61 | 62 | buildTypes { 63 | release { 64 | // TODO: Add your own signing config for the release build. 65 | // Signing with the debug keys for now, so `flutter run --release` works. 66 | signingConfig signingConfigs.config 67 | } 68 | debug { 69 | // TODO: Add your own signing config for the release build. 70 | // Signing with the debug keys for now, so `flutter run --release` works. 71 | signingConfig signingConfigs.config 72 | } 73 | } 74 | } 75 | 76 | flutter { 77 | source '../..' 78 | } 79 | 80 | dependencies { 81 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 82 | } 83 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 21 | 25 | 29 | 30 | 31 | 32 | 33 | 34 | 36 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/winwang/open_eye/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.winwang.open_eye 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /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 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/app/src/release/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 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.useAndroidX=true 3 | android.enableJetifier=true 4 | 5 | app_keystore_filepath=release/stockcircle.jks 6 | app_keystore_password=jds123456 7 | app_keystore_alias=stock 8 | app_keystore_keypassword=jds123456 9 | -------------------------------------------------------------------------------- /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-6.7-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /assets/images/back_mine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/back_mine.png -------------------------------------------------------------------------------- /assets/images/back_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/back_placeholder.png -------------------------------------------------------------------------------- /assets/images/back_ticket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/back_ticket.png -------------------------------------------------------------------------------- /assets/images/common_empty_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/common_empty_img.png -------------------------------------------------------------------------------- /assets/images/head_mine.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/head_mine.jpeg -------------------------------------------------------------------------------- /assets/images/icon_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_about.png -------------------------------------------------------------------------------- /assets/images/icon_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_close.png -------------------------------------------------------------------------------- /assets/images/icon_collect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_collect.png -------------------------------------------------------------------------------- /assets/images/icon_collect_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_collect_grey.png -------------------------------------------------------------------------------- /assets/images/icon_complain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_complain.png -------------------------------------------------------------------------------- /assets/images/icon_custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_custom.png -------------------------------------------------------------------------------- /assets/images/icon_explore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_explore.png -------------------------------------------------------------------------------- /assets/images/icon_focus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_focus.png -------------------------------------------------------------------------------- /assets/images/icon_image_upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_image_upload.png -------------------------------------------------------------------------------- /assets/images/icon_kefu_avator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_kefu_avator.png -------------------------------------------------------------------------------- /assets/images/icon_left_triangle_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_left_triangle_white.png -------------------------------------------------------------------------------- /assets/images/icon_my_feedback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_my_feedback.png -------------------------------------------------------------------------------- /assets/images/icon_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_pause.png -------------------------------------------------------------------------------- /assets/images/icon_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_play.png -------------------------------------------------------------------------------- /assets/images/icon_rank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_rank.png -------------------------------------------------------------------------------- /assets/images/icon_right_triangle_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_right_triangle_white.png -------------------------------------------------------------------------------- /assets/images/icon_select_tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_select_tag.png -------------------------------------------------------------------------------- /assets/images/icon_submit_question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_submit_question.png -------------------------------------------------------------------------------- /assets/images/icon_text_tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_text_tag.png -------------------------------------------------------------------------------- /assets/images/icon_topic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_topic.png -------------------------------------------------------------------------------- /assets/images/icon_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_type.png -------------------------------------------------------------------------------- /assets/images/icon_unselect_tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/icon_unselect_tag.png -------------------------------------------------------------------------------- /assets/images/line_ticket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/line_ticket.png -------------------------------------------------------------------------------- /assets/images/loading/common_loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/common_loading.png -------------------------------------------------------------------------------- /assets/images/loading/loding_00000.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00000.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00001.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00001.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00002.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00002.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00003.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00003.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00004.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00004.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00005.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00005.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00006.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00006.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00007.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00007.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00008.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00008.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00009.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00009.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00010.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00010.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00011.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00011.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00012.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00012.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00013.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00013.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00014.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00014.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00015.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00015.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00016.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00016.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00017.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00017.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00018.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00018.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00019.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00019.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00020.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00020.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00021.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00021.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00022.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00022.webp -------------------------------------------------------------------------------- /assets/images/loading/loding_00023.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/loading/loding_00023.webp -------------------------------------------------------------------------------- /assets/images/movie-lazy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/movie-lazy.gif -------------------------------------------------------------------------------- /assets/images/timeout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/assets/images/timeout.png -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | 9.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 flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /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.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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/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/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/base/component/base_component.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:get/get.dart'; 3 | import 'package:open_eye/base/controller/base_controller.dart'; 4 | import 'package:open_eye/widget/load_state_widget.dart'; 5 | import 'package:open_eye/widget/loading_widget.dart'; 6 | 7 | ///定义View组件--页面内某个模块cheng 8 | abstract class BaseComponent extends GetView { 9 | String? componentTag; 10 | 11 | BaseComponent({Key? key, this.componentTag}) : super(key: key); 12 | 13 | @override 14 | String? get tag => componentTag; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return controller.obx((state) => buildContent(context), 19 | onLoading: Center( 20 | child: LoadingWidget(), 21 | ), 22 | onError: (error) => createErroWidget(controller, error), 23 | onEmpty: createEmptyWidget(controller)); 24 | } 25 | 26 | ///showSuccess展示成功的布局 27 | Widget buildContent(BuildContext context); 28 | } 29 | -------------------------------------------------------------------------------- /lib/base/controller/base_refresh_controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get_rx/src/rx_types/rx_types.dart'; 2 | import 'package:open_eye/utils/log_utils.dart'; 3 | import 'package:open_eye/widget/pull_smart_refresher.dart'; 4 | import 'package:pull_to_refresh/pull_to_refresh.dart'; 5 | 6 | import 'base_controller.dart'; 7 | 8 | ///带有刷新器的状态控制器 9 | abstract class BaseRefreshController extends BaseController { 10 | ///加载状态 0加载中 1加载成功 2加载数据为空 3加载失败 11 | var loadState = 0.obs; 12 | 13 | RefreshController refreshController = RefreshController(); 14 | 15 | ///当前页数 16 | int pageIndex = 0; 17 | 18 | ///是否初次加载 19 | var isInit = true; 20 | 21 | ///预留上拉刷新 22 | onLoadRefresh() { 23 | pageIndex = 1; 24 | requestPageData(refresh: Refresh.pull); 25 | } 26 | 27 | ///预留下拉加载 28 | onLoadMore() { 29 | ++pageIndex; 30 | requestPageData(refresh: Refresh.down); 31 | } 32 | 33 | ///网络请求在此处进行,不用在重复进行上拉下拉的处理 34 | void requestPageData({Refresh refresh = Refresh.first}) {} 35 | 36 | @override 37 | void loadNet() {} 38 | 39 | ///刷新控件停止刷新方法 40 | void hideRefresh( 41 | RefreshController refreshController, { 42 | bool? finishLoadMore, 43 | }) { 44 | if (refreshController.isRefresh) { 45 | LogWTF(">>>>>>>>>结束刷新"); 46 | refreshController.refreshCompleted(); 47 | } else if (refreshController.isLoading) { 48 | LogWTF(">>>>>>>>>结束加载"); 49 | if (finishLoadMore ?? false) { 50 | refreshController.loadNoData(); 51 | } else { 52 | refreshController.loadComplete(); 53 | } 54 | } else { 55 | LogWTF(">>>>>>>>>结束WTF"); 56 | if (finishLoadMore ?? false) { 57 | refreshController.loadNoData(); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/base/pageWidget/base_stateless_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:get/get.dart'; 3 | import 'package:open_eye/base/controller/base_controller.dart'; 4 | import 'package:open_eye/mixin/toast/toast_mixin.dart'; 5 | import 'package:open_eye/widget/load_state_widget.dart'; 6 | import 'package:open_eye/widget/loading_widget.dart'; 7 | 8 | ///常用页面无状态page封装,基本依赖Controller+OBX实现原有State+StatefulWidget效果 9 | abstract class BaseStatelessWidget extends GetView 10 | with ToastMixin { 11 | const BaseStatelessWidget({Key? key}) : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: _createAppBar(context), 17 | body: _buildBody(context), 18 | drawer: showDrawer() ? createDrawer() : null, 19 | ); 20 | } 21 | 22 | ///AppBar生成逻辑 23 | AppBar? _createAppBar(BuildContext context) { 24 | if (showTitleBar()) { 25 | return createAppBar( 26 | titleString(), showBackButton(), appBarActionWidget(context), 27 | titleWidget: titleWidget()); 28 | } else { 29 | return null; 30 | } 31 | } 32 | 33 | ///构建侧边栏内容 34 | Widget createDrawer() { 35 | return Container(); 36 | } 37 | 38 | ///创建AppBar ActionView 39 | List? appBarActionWidget(BuildContext context) {} 40 | 41 | ///构建Scaffold-body主体内容 42 | Widget _buildBody(BuildContext context) { 43 | if (useLoadSir()) { 44 | return controller.obx((state) => buildContent(context), 45 | onLoading: Center( 46 | child: LoadingWidget(), 47 | ), 48 | onError: (error) => createErroWidget(controller, error), 49 | onEmpty: createEmptyWidget(controller)); 50 | } else { 51 | return buildContent(context); 52 | } 53 | } 54 | 55 | ///是否展示titleBar标题栏 56 | bool showTitleBar() => true; 57 | 58 | ///侧边栏 59 | bool showDrawer() => false; 60 | 61 | ///页面标题设置 62 | String titleString() => "标题"; 63 | 64 | ///标题栏title的Widget 65 | Widget? titleWidget() {} 66 | 67 | ///是否开启加载状态 68 | bool useLoadSir() => true; 69 | 70 | ///是否展示回退按钮 71 | bool showBackButton() => true; 72 | 73 | ///showSuccess展示成功的布局 74 | Widget buildContent(BuildContext context); 75 | } 76 | -------------------------------------------------------------------------------- /lib/base/pageWidget/common_stateful_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:open_eye/mixin/toast/toast_mixin.dart'; 3 | 4 | 5 | ///实现一些基础功能SatefulWidget组件(例如Toast等,可继续拓展) 6 | abstract class CommonStatefulWidget extends StatefulWidget with ToastMixin {} 7 | -------------------------------------------------------------------------------- /lib/base/pageWidget/common_stateless_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:open_eye/mixin/toast/toast_mixin.dart'; 3 | 4 | ///实现一些基础功能的StatelessWidget(例如Toast等) 5 | abstract class CommonStatelessWidget extends StatelessWidget with ToastMixin { 6 | const CommonStatelessWidget({Key? key}) : super(key: key); 7 | } 8 | -------------------------------------------------------------------------------- /lib/business/common/photo_preview_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:get/get.dart'; 4 | import 'package:open_eye/base/controller/base_controller.dart'; 5 | import 'package:open_eye/base/pageWidget/base_stateless_widget.dart'; 6 | import 'package:open_eye/res/colors.dart'; 7 | import 'package:photo_view/photo_view.dart'; 8 | 9 | ///图片预览页面 10 | class PhotoPreviewPage extends BaseStatelessWidget { 11 | const PhotoPreviewPage({Key? key}) : super(key: key); 12 | 13 | @override 14 | Widget buildContent(BuildContext context) { 15 | return Obx(() => Container( 16 | height: double.infinity, 17 | width: double.infinity, 18 | alignment: Alignment.center, 19 | color: ColorStyle.color_black, 20 | child: GestureDetector( 21 | child: _createImageProvider(), 22 | onTap: () { 23 | Get.back(); 24 | }, 25 | ), 26 | )); 27 | } 28 | 29 | Widget _createImageProvider() { 30 | if (controller.imageUrl.value.isNotEmpty) { 31 | return Obx(() => PhotoView( 32 | imageProvider: 33 | CachedNetworkImageProvider(controller.imageUrl.value), 34 | )); 35 | } else { 36 | return const SizedBox(); 37 | } 38 | } 39 | 40 | @override 41 | bool useLoadSir() => false; 42 | 43 | @override 44 | bool showTitleBar() => false; 45 | } 46 | 47 | ///页面控制器 48 | class PhotoPreviewController extends BaseController { 49 | ///单张图片 50 | RxString imageUrl = "".obs; 51 | 52 | ///多张图片列表 53 | RxList imageUrlList = [].obs; 54 | 55 | @override 56 | void loadNet() {} 57 | 58 | @override 59 | void onReady() { 60 | super.onReady(); 61 | imageUrl.value = Get.arguments; 62 | } 63 | } 64 | 65 | ///依赖绑定数据类 66 | class PhotoPreviewBinding extends Bindings { 67 | @override 68 | void dependencies() { 69 | Get.lazyPut(() => PhotoPreviewController()); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/business/complain/complain_common_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:open_eye/base/controller/base_controller.dart'; 4 | import 'package:open_eye/base/pageWidget/base_stateless_widget.dart'; 5 | import 'package:open_eye/res/colors.dart'; 6 | import 'package:open_eye/res/style.dart'; 7 | import 'package:get/get.dart'; 8 | 9 | ///常见问题展示页面 10 | class ComplainCommonPage extends BaseStatelessWidget { 11 | const ComplainCommonPage({Key? key}) : super(key: key); 12 | 13 | @override 14 | Widget buildContent(BuildContext context) { 15 | return Obx(() => Column( 16 | children: [ 17 | Container( 18 | height: 88.w, 19 | padding: EdgeInsets.only(left: 32.w), 20 | alignment: Alignment.centerLeft, 21 | child: Text( 22 | controller.aqTitle.value, 23 | style: TextStyle( 24 | fontSize: 32.sp, 25 | color: ColorStyle.color_333333, 26 | fontWeight: FontWeight.bold), 27 | ), 28 | ), 29 | DividerStyle.divider1Half, 30 | Container( 31 | alignment: Alignment.centerLeft, 32 | padding: EdgeInsets.all(32.w), 33 | child: Text( 34 | controller.aqDesc.value, 35 | style: 36 | TextStyle(fontSize: 28.sp, color: ColorStyle.color_666666), 37 | ), 38 | ) 39 | ], 40 | )); 41 | } 42 | 43 | @override 44 | String titleString() => "常见问题"; 45 | 46 | @override 47 | bool useLoadSir() => false; 48 | } 49 | 50 | class ComplainCommonController extends BaseController { 51 | RxString aqTitle = "".obs; //问题标题 52 | RxString aqDesc = "".obs; //问题描述 53 | 54 | @override 55 | void loadNet() {} 56 | 57 | @override 58 | void onReady() { 59 | super.onReady(); 60 | aqTitle.value = Get.parameters["aqTitle"] ?? ""; 61 | aqDesc.value = Get.parameters["aqDesc"] ?? ""; 62 | } 63 | } 64 | 65 | class ComplainCommonBinding extends Bindings { 66 | @override 67 | void dependencies() { 68 | Get.lazyPut(() => ComplainCommonController()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/business/complain/complain_my_list_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:get/get.dart'; 3 | import 'package:open_eye/base/controller/base_refresh_controller.dart'; 4 | import 'package:open_eye/base/pageWidget/base_stateless_widget.dart'; 5 | import 'package:open_eye/business/complain/model/my_feedback_entity.dart'; 6 | import 'package:open_eye/business/complain/widget/item_my_feedback_widget.dart'; 7 | import 'package:open_eye/http/apiservice/gateway_api.dart'; 8 | import 'package:open_eye/http/result/base_result.dart'; 9 | import 'package:open_eye/route/router_utils.dart'; 10 | import 'package:open_eye/widget/pull_smart_refresher.dart'; 11 | 12 | ///我的反馈列表 13 | class ComplainMyListPage extends BaseStatelessWidget { 14 | const ComplainMyListPage({Key? key}) : super(key: key); 15 | 16 | @override 17 | Widget buildContent(BuildContext context) { 18 | return Obx(() => SizedBox( 19 | height: double.infinity, 20 | width: double.infinity, 21 | child: RefreshWidget( 22 | refreshController: controller.refreshController, 23 | enablePullUp: false, 24 | child: ListView.builder( 25 | itemBuilder: (context, index) { 26 | return GestureDetector( 27 | child: ItemMyFeedbackWidget(controller.feedbackList[index]), 28 | onTap: () { 29 | RouterUtils.toComplainRecordPage( 30 | controller.feedbackList[index].id); 31 | }, 32 | ); 33 | }, 34 | itemCount: controller.feedbackList.length, 35 | )), 36 | )); 37 | } 38 | 39 | @override 40 | String titleString() => "我的反馈"; 41 | } 42 | 43 | class ComplainMyListController extends BaseRefreshController { 44 | RxList feedbackList = [].obs; 45 | 46 | @override 47 | void onReady() { 48 | super.onReady(); 49 | loadNet(); 50 | } 51 | 52 | @override 53 | void loadNet() { 54 | super.loadNet(); 55 | requestPageData(); 56 | } 57 | 58 | @override 59 | void requestPageData({Refresh refresh = Refresh.first}) { 60 | httpRequest>>(api.queryMyFeedback(), 61 | (value) { 62 | if (refresh == Refresh.first || refresh == Refresh.pull) { 63 | feedbackList.clear(); 64 | } 65 | feedbackList.addAll(value.resObject!); 66 | if(feedbackList.isEmpty){ 67 | showEmpty(); 68 | } 69 | hideRefresh(refreshController); 70 | }); 71 | } 72 | } 73 | 74 | ///依赖绑定 75 | class ComplainMyListBinding extends Bindings { 76 | @override 77 | void dependencies() { 78 | Get.lazyPut(() => ComplainMyListController()); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/business/complain/model/Feedback_detail_list_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'package:open_eye/business/complain/model/feedback_list_item_entity.dart'; 3 | 4 | part 'Feedback_detail_list_entity.g.dart'; 5 | @JsonSerializable(explicitToJson: true) 6 | class FeedbackDetailListEntity { 7 | FeedbackDetailListEntity({ 8 | this.list,}); 9 | 10 | List? list; 11 | 12 | factory FeedbackDetailListEntity.fromJson(Map json) => _$FeedbackDetailListEntityFromJson(json); 13 | 14 | Map toJson() => _$FeedbackDetailListEntityToJson(this); 15 | 16 | 17 | } -------------------------------------------------------------------------------- /lib/business/complain/model/Feedback_detail_list_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Feedback_detail_list_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | FeedbackDetailListEntity _$FeedbackDetailListEntityFromJson( 10 | Map json) => 11 | FeedbackDetailListEntity( 12 | list: (json['list'] as List?) 13 | ?.map( 14 | (e) => FeedbackListItemEntity.fromJson(e as Map)) 15 | .toList(), 16 | ); 17 | 18 | Map _$FeedbackDetailListEntityToJson( 19 | FeedbackDetailListEntity instance) => 20 | { 21 | 'list': instance.list?.map((e) => e.toJson()).toList(), 22 | }; 23 | -------------------------------------------------------------------------------- /lib/business/complain/model/feedback_list_item_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'feedback_list_item_entity.g.dart'; 4 | 5 | @JsonSerializable() 6 | class FeedbackListItemEntity { 7 | FeedbackListItemEntity({ 8 | this.userName, 9 | this.replyTime, 10 | this.content, 11 | this.contentType, 12 | this.type, 13 | }); 14 | 15 | String? userName; 16 | String? replyTime; 17 | String? content; 18 | int? contentType; 19 | int? type; 20 | 21 | factory FeedbackListItemEntity.fromJson(Map json) => 22 | _$FeedbackListItemEntityFromJson(json); 23 | 24 | Map toJson() => _$FeedbackListItemEntityToJson(this); 25 | } 26 | -------------------------------------------------------------------------------- /lib/business/complain/model/feedback_list_item_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'feedback_list_item_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | FeedbackListItemEntity _$FeedbackListItemEntityFromJson( 10 | Map json) => 11 | FeedbackListItemEntity( 12 | userName: json['userName'] as String?, 13 | replyTime: json['replyTime'] as String?, 14 | content: json['content'] as String?, 15 | contentType: json['contentType'] as int?, 16 | type: json['type'] as int?, 17 | ); 18 | 19 | Map _$FeedbackListItemEntityToJson( 20 | FeedbackListItemEntity instance) => 21 | { 22 | 'userName': instance.userName, 23 | 'replyTime': instance.replyTime, 24 | 'content': instance.content, 25 | 'contentType': instance.contentType, 26 | 'type': instance.type, 27 | }; 28 | -------------------------------------------------------------------------------- /lib/business/complain/model/my_feedback_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'my_feedback_entity.g.dart'; 4 | 5 | @JsonSerializable() 6 | class MyFeedbackEntity { 7 | MyFeedbackEntity({ 8 | this.id, 9 | this.type, 10 | this.content, 11 | this.contentType, 12 | this.questionTime, 13 | }); 14 | 15 | int? id; 16 | int? type; 17 | String? content; 18 | int? contentType; 19 | String? questionTime; 20 | 21 | factory MyFeedbackEntity.fromJson(Map json) => 22 | _$MyFeedbackEntityFromJson(json); 23 | 24 | Map toJson() => _$MyFeedbackEntityToJson(this); 25 | 26 | String getContentTypeString() { 27 | if (type == 0) { 28 | return "功能建议"; 29 | } else if (type == 1) { 30 | return "功能异常"; 31 | } else { 32 | return "其他反馈"; 33 | } 34 | } 35 | 36 | String getDateString() { 37 | var split = questionTime?.split("T"); 38 | if (split != null) { 39 | return split[0]; 40 | } else { 41 | return ""; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/business/complain/model/my_feedback_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'my_feedback_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | MyFeedbackEntity _$MyFeedbackEntityFromJson(Map json) => 10 | MyFeedbackEntity( 11 | id: json['id'] as int?, 12 | type: json['type'] as int?, 13 | content: json['content'] as String?, 14 | contentType: json['contentType'] as int?, 15 | questionTime: json['questionTime'] as String?, 16 | ); 17 | 18 | Map _$MyFeedbackEntityToJson(MyFeedbackEntity instance) => 19 | { 20 | 'id': instance.id, 21 | 'type': instance.type, 22 | 'content': instance.content, 23 | 'contentType': instance.contentType, 24 | 'questionTime': instance.questionTime, 25 | }; 26 | -------------------------------------------------------------------------------- /lib/business/complain/widget/item_common_question_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:get/get.dart'; 4 | import 'package:open_eye/base/pageWidget/common_stateless_widget.dart'; 5 | import 'package:open_eye/res/colors.dart'; 6 | import 'package:open_eye/res/strings.dart'; 7 | import 'package:open_eye/route/routes.dart'; 8 | 9 | // ignore: must_be_immutable 10 | class ItemCommonQuestionWidget extends CommonStatelessWidget { 11 | String? item; 12 | 13 | ItemCommonQuestionWidget(this.item, {Key? key}) : super(key: key); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return GestureDetector( 18 | child: Container( 19 | height: 88.w, 20 | width: double.infinity, 21 | margin: EdgeInsets.only(left: 32.w, right: 32.w), 22 | decoration: BoxDecoration( 23 | border: Border( 24 | bottom: BorderSide(width: 1.w, color: ColorStyle.colorShadow)), 25 | ), 26 | child: Row( 27 | children: [ 28 | Text( 29 | item ?? "", 30 | style: TextStyle( 31 | fontSize: 28.sp, 32 | color: ColorStyle.color_333333, 33 | ), 34 | ), 35 | const Spacer(), 36 | Icon(Icons.arrow_forward_ios, size: 32.w), 37 | ], 38 | ), 39 | ), 40 | onTap: () { 41 | Map params = { 42 | "aqTitle": item ?? "", 43 | "aqDesc": StringStyles.complainAQMap[item] ?? "" 44 | }; 45 | Get.toNamed( 46 | AppRoutes.complainHomePage + AppRoutes.complainCommonPage, 47 | parameters: params); 48 | }, 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/business/complain/widget/item_my_feedback_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:open_eye/base/pageWidget/common_stateless_widget.dart'; 4 | import 'package:open_eye/business/complain/model/my_feedback_entity.dart'; 5 | import 'package:open_eye/res/colors.dart'; 6 | import 'package:open_eye/res/style.dart'; 7 | 8 | // ignore: must_be_immutable 9 | class ItemMyFeedbackWidget extends CommonStatelessWidget { 10 | MyFeedbackEntity item; 11 | 12 | ItemMyFeedbackWidget(this.item, {Key? key}) : super(key: key); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Container( 17 | color: Colors.transparent, 18 | height: 144.w, 19 | padding: EdgeInsets.only(left: 32.w, right: 32.w), 20 | alignment: Alignment.center, 21 | width: double.infinity, 22 | child: Container( 23 | height: 88.w, 24 | alignment: Alignment.centerLeft, 25 | child: Row( 26 | children: [ 27 | CircleAvatar( 28 | child: const Text(""), 29 | backgroundImage: const NetworkImage( 30 | "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp01%2F1ZZQ20QJS6-0-lp.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1647411091&t=5ae667f54b72a3b742dbb26e13aa6131"), 31 | radius: 44.w, 32 | backgroundColor: Colors.transparent, 33 | ), 34 | Box.wBox16, 35 | Expanded( 36 | flex: 1, 37 | child: Column( 38 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 39 | crossAxisAlignment: CrossAxisAlignment.start, 40 | children: [ 41 | Text( 42 | item.getContentTypeString(), 43 | style: TextStyle( 44 | fontSize: 32.sp, 45 | fontWeight: FontWeight.bold, 46 | color: ColorStyle.color_333333), 47 | maxLines: 1, 48 | ), 49 | Text( 50 | item.content ?? "", 51 | style: TextStyle( 52 | fontSize: 28.sp, color: ColorStyle.color_999999), 53 | maxLines: 1, 54 | overflow: TextOverflow.ellipsis, 55 | ) 56 | ], 57 | ), 58 | ), 59 | Container( 60 | height: double.infinity, 61 | alignment: Alignment.topLeft, 62 | child: Text( 63 | item.getDateString(), 64 | style: 65 | TextStyle(fontSize: 24.sp, color: ColorStyle.color_999999), 66 | ), 67 | ) 68 | ], 69 | ), 70 | ), 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/business/complain/widget/item_question_type_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:open_eye/base/pageWidget/common_stateless_widget.dart'; 4 | import 'package:open_eye/res/colors.dart'; 5 | 6 | // ignore: must_be_immutable 7 | class ItemQuestionTypeWidget extends CommonStatelessWidget { 8 | String itemValue; 9 | bool hasSelect; 10 | ValueChanged valueChanged; 11 | 12 | ItemQuestionTypeWidget(this.itemValue, this.hasSelect, this.valueChanged, 13 | {Key? key}) 14 | : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return GestureDetector( 19 | child: Container( 20 | width: 216.w, 21 | height: 96.w, 22 | alignment: Alignment.center, 23 | margin: EdgeInsets.only(right: 20.w), 24 | decoration: BoxDecoration( 25 | color: ColorStyle.color_F5F5F5, 26 | borderRadius: BorderRadius.all(Radius.circular(10.w)), 27 | border: Border.all( 28 | width: 1.5.w, 29 | color: 30 | hasSelect ? ColorStyle.color_EA4C43 : Colors.transparent)), 31 | child: Text( 32 | itemValue, 33 | style: TextStyle( 34 | fontSize: 32.sp, 35 | color: hasSelect 36 | ? ColorStyle.color_EA4C43 37 | : ColorStyle.color_666666), 38 | ), 39 | ), 40 | onTap: () { 41 | valueChanged.call(itemValue); 42 | }, 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/business/custom_paint_page/model/radar_view_entity.dart: -------------------------------------------------------------------------------- 1 | class RadarViewEntity{ 2 | 3 | String tag; 4 | double value; 5 | 6 | RadarViewEntity(this.tag, this.value); 7 | } -------------------------------------------------------------------------------- /lib/business/custom_paint_page/painter/circel_chart_painter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:open_eye/res/colors.dart'; 5 | import 'package:open_eye/utils/log_utils.dart'; 6 | 7 | class CircleChartPainter extends CustomPainter { 8 | List chartList; 9 | double totalValue = 0; 10 | 11 | var colorList = [ 12 | ColorStyle.color_EA4C43, 13 | ColorStyle.color_FE8C28, 14 | ColorStyle.color_FFAE2E, 15 | ColorStyle.color_FBE240, 16 | ColorStyle.color_24CF5F, 17 | ColorStyle.color_1A2F51, 18 | ColorStyle.color_EA4C43, 19 | ColorStyle.color_FE8C28, 20 | ColorStyle.color_FFAE2E, 21 | ColorStyle.color_FBE240, 22 | ColorStyle.color_24CF5F, 23 | ColorStyle.color_1A2F51, 24 | ]; 25 | 26 | late Paint circlePaint; 27 | 28 | CircleChartPainter(this.chartList) { 29 | circlePaint = Paint() 30 | ..style = PaintingStyle.fill 31 | ..color = ColorStyle.color_black 32 | ..isAntiAlias = true; 33 | for (var value in chartList) { 34 | totalValue += value; 35 | } 36 | } 37 | 38 | @override 39 | void paint(Canvas canvas, Size size) { 40 | var rect = Offset.zero & size; 41 | 42 | ///Android和Flutter一样的API,用的却不同,Android是角度,FLutter需要用弧度,比较坑 43 | ///弧度 = 角度 * PI/180; 44 | /// 45 | ///角度 = 弧度 * 180/PI; 46 | double startAngle = -90 * pi / 180; 47 | var percentAngle = 360 / totalValue; 48 | for (int i = 0; i < chartList.length; i++) { 49 | var value = chartList[i]; 50 | circlePaint.color = colorList[i]; 51 | var percent = value / totalValue; 52 | var angel = percentAngle * value * pi / 180; 53 | // LogD("$startAngle角度>>>>>>$angel<<<<<<"); 54 | canvas.drawArc(rect, startAngle, angel, true, circlePaint); 55 | startAngle += angel; 56 | } 57 | } 58 | 59 | @override 60 | bool shouldRepaint(covariant CustomPainter oldDelegate) { 61 | return true; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/business/custom_paint_page/painter/vote_painter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:open_eye/res/colors.dart'; 4 | 5 | class VotePainter extends CustomPainter { 6 | double positiveNum; 7 | double negativeNum; 8 | 9 | //倾斜角度 10 | double slideWidth = 10.w; 11 | 12 | //斜线间距 13 | double gapWidth = 10.w; 14 | 15 | VotePainter(this.positiveNum, this.negativeNum); 16 | 17 | var votePaint = Paint() 18 | ..isAntiAlias = true 19 | ..style = PaintingStyle.fill; 20 | 21 | @override 22 | void paint(Canvas canvas, Size size) { 23 | var width = size.width; 24 | var height = size.height; 25 | var leftRatio = negativeNum / (negativeNum + positiveNum); 26 | var righRation = positiveNum / (negativeNum + positiveNum); 27 | 28 | var negativeTopRight = leftRatio * width + slideWidth - gapWidth; 29 | var negativeBottomRight = negativeTopRight - slideWidth; 30 | var positionLeftBottom = negativeBottomRight + gapWidth; 31 | var positionLeftTop = positionLeftBottom + slideWidth; 32 | 33 | //切除方角 34 | var clipPath = Path(); 35 | // var rRect = RRect.fromLTRBAndCorners(0, 0, width, height,topLeft: Radius.circular(height/2)); 36 | var rRect = 37 | RRect.fromLTRBR(0, 0, width, height, Radius.circular(height / 2)); 38 | clipPath.addRRect(rRect); 39 | canvas.clipPath(clipPath); 40 | 41 | //绘制左边 42 | var leftPath = Path(); 43 | leftPath.moveTo(0, 0); 44 | leftPath.lineTo(negativeTopRight, 0); 45 | leftPath.lineTo(negativeBottomRight, height); 46 | leftPath.lineTo(0, height); 47 | leftPath.close(); 48 | votePaint.color = ColorStyle.color_24CF5F; 49 | canvas.drawPath(leftPath, votePaint); 50 | //绘制右边 51 | var rightPath = Path(); 52 | rightPath.moveTo(width, 0); 53 | rightPath.lineTo(width, height); 54 | rightPath.lineTo(positionLeftBottom, height); 55 | rightPath.lineTo(positionLeftTop, 0); 56 | rightPath.close(); 57 | votePaint.color = ColorStyle.color_EA4C43; 58 | canvas.drawPath(rightPath, votePaint); 59 | } 60 | 61 | @override 62 | bool shouldRepaint(covariant CustomPainter oldDelegate) { 63 | return false; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/business/custom_paint_page/widget/bar_chart_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:open_eye/base/pageWidget/common_stateful_widget.dart'; 5 | import 'package:open_eye/business/custom_paint_page/painter/bar_chart_painter.dart'; 6 | import 'dart:ui' as ui; 7 | 8 | import 'package:open_eye/utils/log_utils.dart'; 9 | 10 | class BarChartWidget extends CommonStatefulWidget { 11 | List barList; 12 | 13 | BarChartWidget(this.barList); 14 | 15 | @override 16 | State createState() { 17 | return BarChartState(); 18 | } 19 | } 20 | 21 | class BarChartState extends State { 22 | double dx = -1; 23 | double dy = -1; 24 | bool hasTouchDown = false; 25 | ui.Image?_image; 26 | 27 | @override 28 | void initState() { 29 | super.initState(); 30 | // LogE(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>初始状态msg"); 31 | load("assets/images/icon_text_tag.png") 32 | .then((value) { 33 | // LogE("获取图片>>>>>>>>>>>" + value.toString()); 34 | setState(() { 35 | _image = value; 36 | }); 37 | }); 38 | } 39 | 40 | @override 41 | Widget build(BuildContext context) { 42 | return GestureDetector( 43 | child: CustomPaint( 44 | size: Size(double.infinity, 300.w), 45 | painter: BarChartPainter(widget.barList, hasTouchDown, dx, dy, _image), 46 | ), 47 | onHorizontalDragUpdate: (details) { 48 | setState(() { 49 | hasTouchDown = true; 50 | dx = details.localPosition.dx; 51 | dy = details.localPosition.dy; 52 | }); 53 | }, 54 | onHorizontalDragEnd: (details) { 55 | setState(() { 56 | hasTouchDown = false; 57 | dx = -1; 58 | dy = -1; 59 | }); 60 | }, 61 | onLongPressDown: (details) { 62 | setState(() { 63 | hasTouchDown = true; 64 | dx = details.localPosition.dx; 65 | dy = details.localPosition.dy; 66 | }); 67 | }, 68 | onLongPressMoveUpdate: (details) { 69 | setState(() { 70 | hasTouchDown = true; 71 | dx = details.localPosition.dx; 72 | dy = details.localPosition.dy; 73 | }); 74 | }, 75 | onLongPressEnd: (details) { 76 | setState(() { 77 | hasTouchDown = false; 78 | dx = -1; 79 | dy = -1; 80 | }); 81 | }, 82 | ); 83 | } 84 | 85 | /// 通过assets路径,获取资源图片 86 | Future load(String asset) async { 87 | ByteData data = await rootBundle.load(asset); 88 | ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List()); 89 | ui.FrameInfo fi = await codec.getNextFrame(); 90 | return fi.image; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /lib/business/custom_paint_page/widget/line_chart_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/gestures.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:open_eye/base/pageWidget/common_stateful_widget.dart'; 5 | import 'package:open_eye/utils/log_utils.dart'; 6 | 7 | import '../painter/line_chart_painter.dart'; 8 | 9 | class LineChartWidget extends CommonStatefulWidget { 10 | List chartList; 11 | 12 | LineChartWidget({Key? key, required this.chartList}); 13 | 14 | @override 15 | State createState() { 16 | return LineChartState(); 17 | } 18 | } 19 | 20 | class LineChartState extends State { 21 | double dx = -1; //触摸很想 22 | double dy = -1; 23 | bool hasDown = false; 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return GestureDetector( 28 | child: CustomPaint( 29 | painter: LineChartPainter( 30 | chartList: widget.chartList, dx: dx, dy: dy, hasDown: hasDown), 31 | size: Size(double.infinity, 400.w), 32 | ), 33 | onTapDown: (details) { 34 | // LogD("msg>>>>>>>手指放下"); 35 | }, 36 | onTapUp: (details) { 37 | // LogD("msg>>>>>>>手指抬起"); 38 | setState(() { 39 | hasDown = false; 40 | dx = -1; 41 | dy = -1; 42 | }); 43 | }, 44 | onLongPressDown: (LongPressDownDetails details) { 45 | // LogD("msg>>>>>>手指长按下"); 46 | setState(() { 47 | hasDown = true; 48 | dx = details.localPosition.dx; 49 | dy = details.localPosition.dy; 50 | }); 51 | }, 52 | onLongPressUp: () { 53 | // LogD("msg>>>>>>>长按手指抬起"); 54 | setState(() { 55 | hasDown = false; 56 | dx = -1; 57 | dy = -1; 58 | }); 59 | }, 60 | onLongPressMoveUpdate: (LongPressMoveUpdateDetails details) { 61 | // LogD("${details.localPosition.dx}>>>>>${details.localPosition.dy}"); 62 | setState(() { 63 | dx = details.localPosition.dx; 64 | dy = details.localPosition.dy; 65 | }); 66 | }, 67 | onLongPressEnd: (LongPressEndDetails details) { 68 | // LogD("msg>>>>>>>>>长按结束"); 69 | setState(() { 70 | hasDown = false; 71 | dx = -1; 72 | dy = -1; 73 | }); 74 | }, 75 | 76 | onHorizontalDragDown: (details){ 77 | // LogD("msg>>>>>>>>>>>onHorizontalDragDown"); 78 | }, 79 | 80 | onHorizontalDragUpdate: (details){ 81 | // LogD("msg>>>>>>>>>>onHorizontalDragUpdate"); 82 | setState(() { 83 | dx = details.localPosition.dx; 84 | dy = details.localPosition.dy; 85 | }); 86 | }, 87 | 88 | onHorizontalDragEnd: (details){ 89 | setState(() { 90 | hasDown = false; 91 | dx = -1; 92 | dy = -1; 93 | }); 94 | }, 95 | 96 | ); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /lib/business/custom_paint_page/widget/lines_chart_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:open_eye/base/pageWidget/common_stateful_widget.dart'; 4 | import 'package:open_eye/business/custom_paint_page/painter/horizental_line_chart_painter.dart'; 5 | import 'package:open_eye/utils/log_utils.dart'; 6 | 7 | class LinesChartWidget extends CommonStatefulWidget { 8 | List dataList; 9 | 10 | LinesChartWidget(this.dataList); 11 | 12 | @override 13 | State createState() { 14 | return LinesChartState(); 15 | } 16 | } 17 | 18 | class LinesChartState extends State { 19 | ///手指按下位置 20 | double tapDownX = 0; 21 | 22 | ///手指横向滚动距离 23 | double tapDeltaX = 0; 24 | 25 | ///上次滑动横向距离记录 26 | double lastDeltaX = 0; 27 | 28 | ///横向方向缩放比例 29 | double horizentalScale = 1.0; 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | return GestureDetector( 34 | child: CustomPaint( 35 | size: Size(double.infinity, 400.w), 36 | painter: HorizentalLineChartPainter( 37 | widget.dataList, tapDeltaX, horizentalScale, (deltaX) { 38 | tapDeltaX = deltaX; 39 | lastDeltaX = tapDeltaX; 40 | }), 41 | ), 42 | onHorizontalDragStart: (details) {}, 43 | onHorizontalDragEnd: (details) { 44 | lastDeltaX = tapDeltaX; 45 | }, 46 | onHorizontalDragUpdate: (details) { 47 | setState(() { 48 | var tempX = lastDeltaX + details.localPosition.dx - tapDownX; 49 | if (tempX > 0) { 50 | tempX = 0; 51 | } 52 | tapDeltaX = tempX; 53 | }); 54 | }, 55 | onHorizontalDragCancel: () {}, 56 | onHorizontalDragDown: (details) { 57 | tapDownX = details.localPosition.dx; 58 | }, 59 | onScaleStart: (details) {}, 60 | onScaleUpdate: (details) { 61 | setState(() { 62 | horizentalScale = details.horizontalScale; 63 | }); 64 | 65 | LogD( 66 | "监听手指状态放大缩小>>>>>>>>>${details.focalPoint.dx}>>>>>>${details.horizontalScale}"); 67 | }, 68 | onScaleEnd: (details) {}, 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/business/detail_page/widget/item_video_detail_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:open_eye/base/pageWidget/common_stateless_widget.dart'; 5 | import 'package:open_eye/business/find_page/model/Focus_Item_Entity.dart'; 6 | import 'package:open_eye/res/colors.dart'; 7 | import 'package:open_eye/res/style.dart'; 8 | 9 | // ignore: must_be_immutable 10 | class ItemVideoDetailWidget extends CommonStatelessWidget { 11 | FocusItemEntity itemData; 12 | 13 | int selectIndex; 14 | 15 | int itemIndex; 16 | 17 | ItemVideoDetailWidget(this.itemData, this.selectIndex, this.itemIndex, 18 | {Key? key}) 19 | : super(key: key); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return Container( 24 | color: ColorStyle.color_white, 25 | padding: EdgeInsets.only(left: 20.w, right: 20.w), 26 | height: 180.w, 27 | child: Row( 28 | children: [ 29 | // BaseNetworkImage( 30 | // itemData.data?.cover?.feed ?? "", 31 | // height: 160.w, 32 | // width: 250.w, 33 | // fit: BoxFit.fill, 34 | // ), 35 | Container( 36 | width: 250.w, 37 | height: 160.w, 38 | decoration: BoxDecoration( 39 | borderRadius: BorderRadius.all(Radius.circular(10.w)), 40 | image: DecorationImage( 41 | image: CachedNetworkImageProvider( 42 | itemData.data?.cover?.feed ?? "", 43 | ), 44 | fit: BoxFit.cover)), 45 | ), 46 | Box.wBox16, 47 | Expanded( 48 | child: Column( 49 | crossAxisAlignment: CrossAxisAlignment.start, 50 | children: [ 51 | Text( 52 | itemData.data?.title ?? "", 53 | style: TextStyle( 54 | color: selectIndex == itemIndex 55 | ? ColorStyle.color_EA4C43 56 | : ColorStyle.color_333333, 57 | fontSize: 28.w), 58 | overflow: TextOverflow.ellipsis, 59 | maxLines: 2, 60 | ), 61 | Box.hBox15, 62 | Text( 63 | itemData.data?.description ?? "", 64 | style: 65 | TextStyle(color: selectIndex == itemIndex 66 | ? ColorStyle.color_EA4C43 67 | : ColorStyle.color_999999, fontSize: 24.w), 68 | overflow: TextOverflow.ellipsis, 69 | maxLines: 2, 70 | ) 71 | ], 72 | )) 73 | ], 74 | ), 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/business/detail_page/widget/video_list_component.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:get/get_core/src/get_main.dart'; 3 | import 'package:get/get_navigation/src/extension_navigation.dart'; 4 | import 'package:get/get_rx/src/rx_types/rx_types.dart'; 5 | import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart'; 6 | import 'package:open_eye/base/component/base_component.dart'; 7 | import 'package:open_eye/base/controller/base_controller.dart'; 8 | import 'package:open_eye/business/find_page/model/Focus_Entity.dart'; 9 | import 'package:open_eye/business/find_page/model/Focus_Item_Entity.dart'; 10 | import 'package:open_eye/http/apiservice/api_service.dart'; 11 | 12 | import 'item_video_detail_widget.dart'; 13 | 14 | typedef ItemClickCallback = void Function(String title, String videoUrl); 15 | 16 | // ignore: must_be_immutable 17 | class VideoListComponent extends BaseComponent { 18 | ItemClickCallback callback; 19 | 20 | VideoListComponent(this.callback, {Key? key}) : super(key: key); 21 | 22 | @override 23 | Widget buildContent(BuildContext context) { 24 | return ListView.builder( 25 | shrinkWrap: true, 26 | itemBuilder: (BuildContext context, int index) { 27 | return Obx(() => GestureDetector( 28 | child: ItemVideoDetailWidget(controller.dataList[index], 29 | controller.selectIndex.value, index), 30 | onTap: () { 31 | if (index == controller.selectIndex.value) { 32 | return; 33 | } 34 | controller.selectIndex.value = index; 35 | var playUrl = controller.dataList[index].data?.playUrl ?? ""; 36 | var title = controller.dataList[index].data?.title ?? ""; 37 | callback(title, playUrl); 38 | }, 39 | )); 40 | }, 41 | itemCount: controller.dataList.length, 42 | ); 43 | } 44 | } 45 | 46 | class VideoListController extends BaseController { 47 | String videoId = Get.parameters["videoId"] ?? ""; 48 | RxInt selectIndex = (-1).obs; 49 | RxList dataList = [].obs; 50 | 51 | @override 52 | void onReady() { 53 | super.onReady(); 54 | loadNet(); 55 | } 56 | 57 | @override 58 | void loadNet() { 59 | queryVideoDetail(); 60 | } 61 | 62 | void queryVideoDetail() { 63 | httpRequest(api.queryVideoDetail(videoId), (value) { 64 | var itemList = value.itemList ?? []; 65 | var tempList = []; 66 | for (var element in itemList) { 67 | if ((element.type ?? "") == "videoSmallCard") { 68 | tempList.add(element); 69 | } 70 | } 71 | dataList.addAll(tempList); 72 | }); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/business/find_page/children_page/category_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:get/get.dart'; 4 | import 'package:open_eye/base/controller/base_controller.dart'; 5 | import 'package:open_eye/base/pageWidget/base_stateless_widget.dart'; 6 | import 'package:open_eye/business/find_page/model/Type_entity.dart'; 7 | import 'package:open_eye/business/find_page/widget/item_category_widget.dart'; 8 | import 'package:open_eye/http/apiservice/api_service.dart'; 9 | import 'package:open_eye/route/router_utils.dart'; 10 | import 'package:open_eye/route/routes.dart'; 11 | 12 | ///分类页面 13 | // ignore: must_be_immutable 14 | class CategoryPage extends BaseStatelessWidget { 15 | String tagType; 16 | 17 | CategoryPage({Key? key, required this.tagType}) : super(key: key); 18 | 19 | @override 20 | String? get tag { 21 | return tagType; 22 | } 23 | 24 | @override 25 | Widget buildContent(BuildContext context) { 26 | return Container( 27 | padding: EdgeInsets.only(left: 6.w, right: 6.w), 28 | child: GridView.builder( 29 | gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( 30 | crossAxisCount: 2, //每行三列 31 | childAspectRatio: 1.0, //显示区域宽高相等 32 | mainAxisSpacing: 3, 33 | crossAxisSpacing: 3, 34 | ), 35 | itemBuilder: (context, index) { 36 | return GestureDetector( 37 | child: ItemCategoryWidget(controller.dataList[index]), 38 | onTap: () { 39 | var itemData = controller.dataList[index]; 40 | Map map = {}; 41 | map["headerImg"] = itemData.headerImage ?? ""; 42 | map["typeName"] = itemData.name ?? ""; 43 | map["typeId"] = "${itemData.id}"; 44 | Get.toNamed(AppRoutes.typeDetailPage, parameters: map); 45 | }, 46 | ); 47 | }, 48 | itemCount: controller.dataList.length, 49 | ), 50 | ); 51 | } 52 | 53 | @override 54 | bool showTitleBar() { 55 | return tagType == "route"; 56 | } 57 | 58 | @override 59 | String titleString() { 60 | return "分类"; 61 | } 62 | 63 | ///搜索按钮 64 | @override 65 | List? appBarActionWidget(BuildContext context) { 66 | return [ 67 | IconButton( 68 | onPressed: () { 69 | RouterUtils.toSearchPage(); 70 | }, 71 | icon: const Icon(Icons.search)) 72 | ]; 73 | } 74 | } 75 | 76 | class CategoryController extends BaseController { 77 | RxList dataList = [].obs; 78 | 79 | @override 80 | void onReady() { 81 | super.onReady(); 82 | loadNet(); 83 | } 84 | 85 | @override 86 | void loadNet() { 87 | queryCategoryData(); 88 | } 89 | 90 | void queryCategoryData() { 91 | httpRequest>(api.queryCategoryData(), (value) { 92 | if (value.isNotEmpty) { 93 | dataList.addAll(value); 94 | } 95 | }); 96 | } 97 | } 98 | 99 | class CategoryBinding extends Bindings { 100 | @override 101 | void dependencies() { 102 | // Get.put(() => CategoryController(), tag: "type", permanent: true); 103 | Get.lazyPut(() => CategoryController(), tag: "route"); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/business/find_page/children_page/focus_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:get/get.dart'; 3 | import 'package:open_eye/base/controller/base_refresh_controller.dart'; 4 | import 'package:open_eye/base/pageWidget/base_stateless_widget.dart'; 5 | import 'package:open_eye/business/find_page/model/Focus_Entity.dart'; 6 | import 'package:open_eye/business/find_page/model/Focus_Item_Entity.dart'; 7 | import 'package:open_eye/business/find_page/widget/item_focus_outer_widget.dart'; 8 | import 'package:open_eye/http/apiservice/api_service.dart'; 9 | import 'package:open_eye/route/router_utils.dart'; 10 | import 'package:open_eye/widget/pull_smart_refresher.dart'; 11 | 12 | ///关注页面 13 | // ignore: must_be_immutable 14 | class FocusPage extends BaseStatelessWidget { 15 | String tagType; 16 | 17 | FocusPage({Key? key, required this.tagType}) : super(key: key); 18 | 19 | @override 20 | String? get tag { 21 | return tagType; 22 | } 23 | 24 | @override 25 | Widget buildContent(BuildContext context) { 26 | return RefreshWidget( 27 | controllerTag: tagType, 28 | refreshController: controller.refreshController, 29 | child: ListView.builder( 30 | itemBuilder: (context, index) { 31 | return ItemFocusOuterWidget(controller.dataList[index]); 32 | }, 33 | itemCount: controller.dataList.length, 34 | )); 35 | } 36 | 37 | @override 38 | bool showTitleBar() { 39 | return tagType == "route"; 40 | } 41 | 42 | @override 43 | String titleString() { 44 | return "关注"; 45 | } 46 | 47 | ///搜索按钮 48 | @override 49 | List? appBarActionWidget(BuildContext context) { 50 | return [ 51 | IconButton( 52 | onPressed: () { 53 | RouterUtils.toSearchPage(); 54 | }, 55 | icon: const Icon(Icons.search)) 56 | ]; 57 | } 58 | } 59 | 60 | class FocusController extends BaseRefreshController { 61 | RxList dataList = [].obs; 62 | 63 | @override 64 | void onReady() { 65 | super.onReady(); 66 | loadNet(); 67 | } 68 | 69 | @override 70 | void loadNet() { 71 | requestPageData(); 72 | } 73 | 74 | @override 75 | void requestPageData({Refresh refresh = Refresh.first}) { 76 | pageIndex++; 77 | httpRequest(api.queryFocusData(pageIndex), (value) { 78 | if (refresh == Refresh.first || refresh == Refresh.pull) { 79 | dataList.clear(); 80 | } 81 | dataList.addAll(value.itemList ?? []); 82 | hideRefresh(refreshController); 83 | }); 84 | } 85 | } 86 | 87 | class FocusBinding extends Bindings { 88 | @override 89 | void dependencies() { 90 | Get.lazyPut(() => FocusController(), tag: "route"); 91 | // Get.lazyPut(() => FocusController(), tag: "focus"); //支持 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Data.dart: -------------------------------------------------------------------------------- 1 | import 'Label.dart'; 2 | 3 | class Data { 4 | Data({ 5 | this.dataType, 6 | this.id, 7 | this.title, 8 | this.description, 9 | this.image, 10 | this.actionUrl, 11 | this.shade, 12 | this.label, 13 | this.autoPlay,}); 14 | 15 | Data.fromJson(dynamic json) { 16 | dataType = json['dataType']; 17 | id = json['id']; 18 | title = json['title']; 19 | description = json['description']; 20 | image = json['image']; 21 | actionUrl = json['actionUrl']; 22 | shade = json['shade']; 23 | label = json['label'] != null ? Label.fromJson(json['label']) : null; 24 | autoPlay = json['autoPlay']; 25 | } 26 | String? dataType; 27 | int? id; 28 | String? title; 29 | String? description; 30 | String? image; 31 | String? actionUrl; 32 | bool? shade; 33 | Label? label; 34 | bool? autoPlay; 35 | 36 | Map toJson() { 37 | final map = {}; 38 | map['dataType'] = dataType; 39 | map['id'] = id; 40 | map['title'] = title; 41 | map['description'] = description; 42 | map['image'] = image; 43 | map['actionUrl'] = actionUrl; 44 | map['shade'] = shade; 45 | if (label != null) { 46 | map['label'] = label?.toJson(); 47 | } 48 | map['autoPlay'] = autoPlay; 49 | return map; 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /lib/business/find_page/model/Focus_Data_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'package:open_eye/business/home_page/model/Author.dart'; 3 | import 'package:open_eye/business/home_page/model/Cover.dart'; 4 | import 'package:open_eye/business/home_page/model/ItemList.dart'; 5 | 6 | import 'Header_entity.dart'; 7 | 8 | part 'Focus_Data_entity.g.dart'; 9 | 10 | @JsonSerializable(explicitToJson: true) 11 | class FocusDataEntity { 12 | HeaderEntity? header; 13 | List? itemList; 14 | String? dataType; 15 | Cover? cover; 16 | Author? author; 17 | String? category; 18 | String? title; 19 | String? description; 20 | String? playUrl; 21 | int? id; 22 | ItemList? content; 23 | 24 | FocusDataEntity( 25 | this.header, 26 | this.itemList, 27 | this.dataType, 28 | this.cover, 29 | this.author, 30 | this.category, 31 | this.title, 32 | this.description, 33 | this.playUrl, 34 | this.id, 35 | this.content); 36 | 37 | factory FocusDataEntity.fromJson(Map json) => 38 | _$FocusDataEntityFromJson(json); 39 | 40 | Map toJson() => _$FocusDataEntityToJson(this); 41 | } 42 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Focus_Data_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Focus_Data_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | FocusDataEntity _$FocusDataEntityFromJson(Map json) => 10 | FocusDataEntity( 11 | json['header'] == null 12 | ? null 13 | : HeaderEntity.fromJson(json['header'] as Map), 14 | (json['itemList'] as List?) 15 | ?.map((e) => ItemList.fromJson(e as Map)) 16 | .toList(), 17 | json['dataType'] as String?, 18 | json['cover'] == null 19 | ? null 20 | : Cover.fromJson(json['cover'] as Map), 21 | json['author'] == null 22 | ? null 23 | : Author.fromJson(json['author'] as Map), 24 | json['category'] as String?, 25 | json['title'] as String?, 26 | json['description'] as String?, 27 | json['playUrl'] as String?, 28 | json['id'] as int?, 29 | json['content'] == null 30 | ? null 31 | : ItemList.fromJson(json['content'] as Map), 32 | ); 33 | 34 | Map _$FocusDataEntityToJson(FocusDataEntity instance) => 35 | { 36 | 'header': instance.header?.toJson(), 37 | 'itemList': instance.itemList?.map((e) => e.toJson()).toList(), 38 | 'dataType': instance.dataType, 39 | 'cover': instance.cover?.toJson(), 40 | 'author': instance.author?.toJson(), 41 | 'category': instance.category, 42 | 'title': instance.title, 43 | 'description': instance.description, 44 | 'playUrl': instance.playUrl, 45 | 'id': instance.id, 46 | 'content': instance.content?.toJson(), 47 | }; 48 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Focus_Entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'package:open_eye/business/find_page/model/Focus_Item_Entity.dart'; 3 | 4 | part 'Focus_Entity.g.dart'; 5 | @JsonSerializable(explicitToJson: true) 6 | class FocusEntity { 7 | List? itemList; 8 | String? nextPageUrl; 9 | int? total; 10 | int? count; 11 | 12 | FocusEntity(this.itemList, this.nextPageUrl, this.total, this.count); 13 | 14 | factory FocusEntity.fromJson(Map json) => _$FocusEntityFromJson(json); 15 | 16 | Map toJson() => _$FocusEntityToJson(this); 17 | } 18 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Focus_Entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Focus_Entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | FocusEntity _$FocusEntityFromJson(Map json) => FocusEntity( 10 | (json['itemList'] as List?) 11 | ?.map((e) => FocusItemEntity.fromJson(e as Map)) 12 | .toList(), 13 | json['nextPageUrl'] as String?, 14 | json['total'] as int?, 15 | json['count'] as int?, 16 | ); 17 | 18 | Map _$FocusEntityToJson(FocusEntity instance) => 19 | { 20 | 'itemList': instance.itemList?.map((e) => e.toJson()).toList(), 21 | 'nextPageUrl': instance.nextPageUrl, 22 | 'total': instance.total, 23 | 'count': instance.count, 24 | }; 25 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Focus_Item_Entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'package:open_eye/business/find_page/model/Focus_Data_entity.dart'; 3 | 4 | part 'Focus_Item_Entity.g.dart'; 5 | 6 | @JsonSerializable(explicitToJson: true) 7 | class FocusItemEntity { 8 | String? type; 9 | FocusDataEntity? data; 10 | int? id; 11 | 12 | 13 | FocusItemEntity(this.type, this.data, this.id); 14 | 15 | factory FocusItemEntity.fromJson(Map json) => 16 | _$FocusItemEntityFromJson(json); 17 | 18 | Map toJson() => _$FocusItemEntityToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Focus_Item_Entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Focus_Item_Entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | FocusItemEntity _$FocusItemEntityFromJson(Map json) => 10 | FocusItemEntity( 11 | json['type'] as String?, 12 | json['data'] == null 13 | ? null 14 | : FocusDataEntity.fromJson(json['data'] as Map), 15 | json['id'] as int?, 16 | ); 17 | 18 | Map _$FocusItemEntityToJson(FocusItemEntity instance) => 19 | { 20 | 'type': instance.type, 21 | 'data': instance.data?.toJson(), 22 | 'id': instance.id, 23 | }; 24 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Follow.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'Follow.g.dart'; 4 | 5 | @JsonSerializable() 6 | class Follow { 7 | Follow({ 8 | this.itemType, 9 | this.itemId, 10 | this.followed, 11 | }); 12 | 13 | String? itemType; 14 | int? itemId; 15 | bool? followed; 16 | 17 | factory Follow.fromJson(Map json) => _$FollowFromJson(json); 18 | 19 | Map toJson() => _$FollowToJson(this); 20 | } 21 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Follow.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Follow.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Follow _$FollowFromJson(Map json) => Follow( 10 | itemType: json['itemType'] as String?, 11 | itemId: json['itemId'] as int?, 12 | followed: json['followed'] as bool?, 13 | ); 14 | 15 | Map _$FollowToJson(Follow instance) => { 16 | 'itemType': instance.itemType, 17 | 'itemId': instance.itemId, 18 | 'followed': instance.followed, 19 | }; 20 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Header_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'package:open_eye/business/home_page/model/ItemList.dart'; 3 | 4 | import 'Follow.dart'; 5 | 6 | part 'Header_entity.g.dart'; 7 | @JsonSerializable(explicitToJson: true) 8 | class HeaderEntity { 9 | HeaderEntity({ 10 | this.id, 11 | this.icon, 12 | this.iconType, 13 | this.title, 14 | this.subTitle, 15 | this.description, 16 | this.actionUrl, 17 | this.adTrack, 18 | this.follow, 19 | this.ifPgc, 20 | this.uid, 21 | this.ifShowNotificationIcon, 22 | this.expert, 23 | this.itemList 24 | }); 25 | 26 | int? id; 27 | String? icon; 28 | String? iconType; 29 | String? title; 30 | dynamic subTitle; 31 | String? description; 32 | String? actionUrl; 33 | dynamic adTrack; 34 | Follow? follow; 35 | bool? ifPgc; 36 | int? uid; 37 | bool? ifShowNotificationIcon; 38 | bool? expert; 39 | List? itemList; 40 | 41 | factory HeaderEntity.fromJson(Map json) => _$HeaderEntityFromJson(json); 42 | 43 | Map toJson() => _$HeaderEntityToJson(this); 44 | } 45 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Header_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Header_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | HeaderEntity _$HeaderEntityFromJson(Map json) => HeaderEntity( 10 | id: json['id'] as int?, 11 | icon: json['icon'] as String?, 12 | iconType: json['iconType'] as String?, 13 | title: json['title'] as String?, 14 | subTitle: json['subTitle'], 15 | description: json['description'] as String?, 16 | actionUrl: json['actionUrl'] as String?, 17 | adTrack: json['adTrack'], 18 | follow: json['follow'] == null 19 | ? null 20 | : Follow.fromJson(json['follow'] as Map), 21 | ifPgc: json['ifPgc'] as bool?, 22 | uid: json['uid'] as int?, 23 | ifShowNotificationIcon: json['ifShowNotificationIcon'] as bool?, 24 | expert: json['expert'] as bool?, 25 | itemList: (json['itemList'] as List?) 26 | ?.map((e) => ItemList.fromJson(e as Map)) 27 | .toList(), 28 | ); 29 | 30 | Map _$HeaderEntityToJson(HeaderEntity instance) => 31 | { 32 | 'id': instance.id, 33 | 'icon': instance.icon, 34 | 'iconType': instance.iconType, 35 | 'title': instance.title, 36 | 'subTitle': instance.subTitle, 37 | 'description': instance.description, 38 | 'actionUrl': instance.actionUrl, 39 | 'adTrack': instance.adTrack, 40 | 'follow': instance.follow?.toJson(), 41 | 'ifPgc': instance.ifPgc, 42 | 'uid': instance.uid, 43 | 'ifShowNotificationIcon': instance.ifShowNotificationIcon, 44 | 'expert': instance.expert, 45 | 'itemList': instance.itemList?.map((e) => e.toJson()).toList(), 46 | }; 47 | -------------------------------------------------------------------------------- /lib/business/find_page/model/ItemList.dart: -------------------------------------------------------------------------------- 1 | import 'Data.dart'; 2 | 3 | class ItemList { 4 | ItemList({ 5 | this.type, 6 | this.data, 7 | this.trackingData, 8 | this.tag, 9 | this.id, 10 | this.adIndex,}); 11 | 12 | ItemList.fromJson(dynamic json) { 13 | type = json['type']; 14 | data = json['data'] != null ? Data.fromJson(json['data']) : null; 15 | trackingData = json['trackingData']; 16 | tag = json['tag']; 17 | id = json['id']; 18 | adIndex = json['adIndex']; 19 | } 20 | String? type; 21 | Data? data; 22 | dynamic trackingData; 23 | dynamic tag; 24 | int? id; 25 | int? adIndex; 26 | 27 | Map toJson() { 28 | final map = {}; 29 | map['type'] = type; 30 | if (data != null) { 31 | map['data'] = data?.toJson(); 32 | } 33 | map['trackingData'] = trackingData; 34 | map['tag'] = tag; 35 | map['id'] = id; 36 | map['adIndex'] = adIndex; 37 | return map; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /lib/business/find_page/model/Label.dart: -------------------------------------------------------------------------------- 1 | class Label { 2 | Label({ 3 | this.text, 4 | this.card, 5 | this.detail,}); 6 | 7 | Label.fromJson(dynamic json) { 8 | text = json['text']; 9 | card = json['card']; 10 | detail = json['detail']; 11 | } 12 | String? text; 13 | String? card; 14 | dynamic detail; 15 | 16 | Map toJson() { 17 | final map = {}; 18 | map['text'] = text; 19 | map['card'] = card; 20 | map['detail'] = detail; 21 | return map; 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /lib/business/find_page/model/Topic_data_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'package:open_eye/business/find_page/model/Topic_item_entity.dart'; 3 | 4 | part 'Topic_data_entity.g.dart'; 5 | @JsonSerializable(explicitToJson: true) 6 | class TopicDataEntity { 7 | TopicItemEntity? data; 8 | String? type; 9 | 10 | TopicDataEntity(this.data, this.type); 11 | 12 | factory TopicDataEntity.fromJson(Map json) => _$TopicDataEntityFromJson(json); 13 | 14 | Map toJson() => _$TopicDataEntityToJson(this); 15 | } -------------------------------------------------------------------------------- /lib/business/find_page/model/Topic_data_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Topic_data_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | TopicDataEntity _$TopicDataEntityFromJson(Map json) => 10 | TopicDataEntity( 11 | json['data'] == null 12 | ? null 13 | : TopicItemEntity.fromJson(json['data'] as Map), 14 | json['type'] as String?, 15 | ); 16 | 17 | Map _$TopicDataEntityToJson(TopicDataEntity instance) => 18 | { 19 | 'data': instance.data?.toJson(), 20 | 'type': instance.type, 21 | }; 22 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Topic_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'package:open_eye/business/find_page/model/Topic_data_entity.dart'; 3 | 4 | part 'Topic_entity.g.dart'; 5 | @JsonSerializable(explicitToJson: true) 6 | class TopicEntity { 7 | TopicEntity({ 8 | this.itemList, 9 | this.count, 10 | this.total, 11 | this.nextPageUrl, 12 | this.adExist,}); 13 | 14 | List? itemList; 15 | int? count; 16 | int? total; 17 | String? nextPageUrl; 18 | bool? adExist; 19 | 20 | factory TopicEntity.fromJson(Map json) => _$TopicEntityFromJson(json); 21 | 22 | Map toJson() => _$TopicEntityToJson(this); 23 | 24 | 25 | } -------------------------------------------------------------------------------- /lib/business/find_page/model/Topic_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Topic_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | TopicEntity _$TopicEntityFromJson(Map json) => TopicEntity( 10 | itemList: (json['itemList'] as List?) 11 | ?.map((e) => TopicDataEntity.fromJson(e as Map)) 12 | .toList(), 13 | count: json['count'] as int?, 14 | total: json['total'] as int?, 15 | nextPageUrl: json['nextPageUrl'] as String?, 16 | adExist: json['adExist'] as bool?, 17 | ); 18 | 19 | Map _$TopicEntityToJson(TopicEntity instance) => 20 | { 21 | 'itemList': instance.itemList?.map((e) => e.toJson()).toList(), 22 | 'count': instance.count, 23 | 'total': instance.total, 24 | 'nextPageUrl': instance.nextPageUrl, 25 | 'adExist': instance.adExist, 26 | }; 27 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Topic_item_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'Topic_item_entity.g.dart'; 4 | 5 | @JsonSerializable() 6 | class TopicItemEntity { 7 | String? title; 8 | int? id; 9 | String? image; 10 | 11 | TopicItemEntity(this.title, this.id, this.image); 12 | 13 | factory TopicItemEntity.fromJson(Map json) => 14 | _$TopicItemEntityFromJson(json); 15 | 16 | Map toJson() => _$TopicItemEntityToJson(this); 17 | } 18 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Topic_item_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Topic_item_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | TopicItemEntity _$TopicItemEntityFromJson(Map json) => 10 | TopicItemEntity( 11 | json['title'] as String?, 12 | json['id'] as int?, 13 | json['image'] as String?, 14 | ); 15 | 16 | Map _$TopicItemEntityToJson(TopicItemEntity instance) => 17 | { 18 | 'title': instance.title, 19 | 'id': instance.id, 20 | 'image': instance.image, 21 | }; 22 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Type_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'Type_entity.g.dart'; 4 | 5 | @JsonSerializable() 6 | class TypeEntity { 7 | TypeEntity({ 8 | this.id, 9 | this.name, 10 | this.alias, 11 | this.description, 12 | this.bgPicture, 13 | this.bgColor, 14 | this.headerImage, 15 | this.defaultAuthorId, 16 | this.tagId, 17 | }); 18 | 19 | int? id; 20 | String? name; 21 | dynamic alias; 22 | String? description; 23 | String? bgPicture; 24 | String? bgColor; 25 | String? headerImage; 26 | int? defaultAuthorId; 27 | int? tagId; 28 | 29 | factory TypeEntity.fromJson(Map json) => 30 | _$TypeEntityFromJson(json); 31 | 32 | Map toJson() => _$TypeEntityToJson(this); 33 | } 34 | -------------------------------------------------------------------------------- /lib/business/find_page/model/Type_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Type_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | TypeEntity _$TypeEntityFromJson(Map json) => TypeEntity( 10 | id: json['id'] as int?, 11 | name: json['name'] as String?, 12 | alias: json['alias'], 13 | description: json['description'] as String?, 14 | bgPicture: json['bgPicture'] as String?, 15 | bgColor: json['bgColor'] as String?, 16 | headerImage: json['headerImage'] as String?, 17 | defaultAuthorId: json['defaultAuthorId'] as int?, 18 | tagId: json['tagId'] as int?, 19 | ); 20 | 21 | Map _$TypeEntityToJson(TypeEntity instance) => 22 | { 23 | 'id': instance.id, 24 | 'name': instance.name, 25 | 'alias': instance.alias, 26 | 'description': instance.description, 27 | 'bgPicture': instance.bgPicture, 28 | 'bgColor': instance.bgColor, 29 | 'headerImage': instance.headerImage, 30 | 'defaultAuthorId': instance.defaultAuthorId, 31 | 'tagId': instance.tagId, 32 | }; 33 | -------------------------------------------------------------------------------- /lib/business/find_page/widget/item_category_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:open_eye/base/pageWidget/common_stateless_widget.dart'; 4 | import 'package:open_eye/business/find_page/model/Type_entity.dart'; 5 | import 'package:open_eye/res/colors.dart'; 6 | 7 | // ignore: must_be_immutable 8 | class ItemCategoryWidget extends CommonStatelessWidget { 9 | TypeEntity itemData; 10 | 11 | ItemCategoryWidget(this.itemData, {Key? key}) : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Container( 16 | alignment: Alignment.center, 17 | height: 350.w, 18 | decoration: BoxDecoration( 19 | image: 20 | DecorationImage(image: NetworkImage(itemData.bgPicture ?? ""))), 21 | child: Text( 22 | itemData.name ?? "", 23 | style: TextStyle( 24 | fontSize: 40.sp, 25 | fontWeight: FontWeight.bold, 26 | color: ColorStyle.color_white), 27 | ), 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/business/home_page/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:card_swiper/card_swiper.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:get/get.dart'; 4 | import 'package:keframe/size_cache_widget.dart'; 5 | import 'package:open_eye/base/controller/base_refresh_controller.dart'; 6 | import 'package:open_eye/base/pageWidget/base_stateful_widget.dart'; 7 | import 'package:open_eye/business/home_page/model/Feed_entity.dart'; 8 | import 'package:open_eye/business/home_page/model/ItemList.dart'; 9 | import 'package:open_eye/business/home_page/widget/item_home_widget.dart'; 10 | import 'package:open_eye/http/apiservice/api_service.dart'; 11 | import 'package:open_eye/route/router_utils.dart'; 12 | import 'package:open_eye/utils/log_utils.dart'; 13 | import 'package:open_eye/widget/pull_smart_refresher.dart'; 14 | 15 | class HomePage extends BaseStatefulWidget { 16 | const HomePage({Key? key}) : super(key: key); 17 | 18 | @override 19 | Widget buildContent(BuildContext context) { 20 | return SizedBox( 21 | child: SizeCacheWidget(child: RefreshWidget( 22 | child: ListView.builder( 23 | itemBuilder: (context, index) { 24 | return ItemHomeWidget( 25 | controller.dataList[index], index, controller.swiperController); 26 | }, 27 | itemCount: controller.dataList.length, 28 | )),), 29 | ); 30 | } 31 | 32 | @override 33 | String titleString() => "首页"; 34 | 35 | @override 36 | bool showBackButton() => false; 37 | 38 | ///搜索按钮 39 | @override 40 | List? appBarActionWidget(BuildContext context) { 41 | return [ 42 | IconButton( 43 | onPressed: () { 44 | RouterUtils.toSearchPage(); 45 | }, 46 | icon: const Icon(Icons.search)) 47 | ]; 48 | } 49 | } 50 | 51 | class HomeController extends BaseRefreshController { 52 | RxList dataList = [].obs; 53 | SwiperController swiperController = SwiperController(); 54 | String date = ""; 55 | 56 | @override 57 | void loadNet() { 58 | requestPageData(); 59 | } 60 | 61 | @override 62 | void onReady() { 63 | super.onReady(); 64 | LogD("Home初始化onResume"); 65 | loadNet(); 66 | } 67 | 68 | @override 69 | void requestPageData({Refresh refresh = Refresh.first}) { 70 | if (refresh == Refresh.first || refresh == Refresh.pull) { 71 | date = ""; 72 | } 73 | httpRequest(api.queryFeedData(date, 1), (value) { 74 | var nextPageUrl = value.nextPageUrl ?? ""; 75 | var split = nextPageUrl.split("?"); 76 | var split2 = split[1]; 77 | var split3 = split2.split("&"); 78 | var split4 = split3[0].split("="); 79 | date = split4[1]; 80 | if (refresh == Refresh.first || refresh == Refresh.pull) { 81 | dataList.clear(); 82 | } 83 | dataList.addAll(value.issueList![0].itemList ?? []); 84 | hideRefresh(refreshController); 85 | }); 86 | } 87 | } 88 | 89 | class HomeBinding extends Bindings { 90 | @override 91 | void dependencies() { 92 | Get.lazyPut(() => HomeController()); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/business/home_page/model/Author.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'Follow.dart'; 3 | import 'Shield.dart'; 4 | 5 | part 'Author.g.dart'; 6 | @JsonSerializable(explicitToJson: true) 7 | class Author { 8 | Author({ 9 | this.id, 10 | this.icon, 11 | this.name, 12 | this.description, 13 | this.link, 14 | this.latestReleaseTime, 15 | this.videoNum, 16 | this.follow, 17 | this.shield, 18 | this.approvedNotReadyVideoCount, 19 | this.ifPgc, 20 | this.recSort, 21 | this.expert,}); 22 | 23 | 24 | int? id; 25 | String? icon; 26 | String? name; 27 | String? description; 28 | String? link; 29 | int? latestReleaseTime; 30 | int? videoNum; 31 | Follow? follow; 32 | Shield? shield; 33 | int? approvedNotReadyVideoCount; 34 | bool? ifPgc; 35 | int? recSort; 36 | bool? expert; 37 | 38 | 39 | 40 | factory Author.fromJson(Map json) => _$AuthorFromJson(json); 41 | 42 | Map toJson() => _$AuthorToJson(this); 43 | 44 | } -------------------------------------------------------------------------------- /lib/business/home_page/model/Author.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Author.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Author _$AuthorFromJson(Map json) => Author( 10 | id: json['id'] as int?, 11 | icon: json['icon'] as String?, 12 | name: json['name'] as String?, 13 | description: json['description'] as String?, 14 | link: json['link'] as String?, 15 | latestReleaseTime: json['latestReleaseTime'] as int?, 16 | videoNum: json['videoNum'] as int?, 17 | follow: json['follow'] == null 18 | ? null 19 | : Follow.fromJson(json['follow'] as Map), 20 | shield: json['shield'] == null 21 | ? null 22 | : Shield.fromJson(json['shield'] as Map), 23 | approvedNotReadyVideoCount: json['approvedNotReadyVideoCount'] as int?, 24 | ifPgc: json['ifPgc'] as bool?, 25 | recSort: json['recSort'] as int?, 26 | expert: json['expert'] as bool?, 27 | ); 28 | 29 | Map _$AuthorToJson(Author instance) => { 30 | 'id': instance.id, 31 | 'icon': instance.icon, 32 | 'name': instance.name, 33 | 'description': instance.description, 34 | 'link': instance.link, 35 | 'latestReleaseTime': instance.latestReleaseTime, 36 | 'videoNum': instance.videoNum, 37 | 'follow': instance.follow?.toJson(), 38 | 'shield': instance.shield?.toJson(), 39 | 'approvedNotReadyVideoCount': instance.approvedNotReadyVideoCount, 40 | 'ifPgc': instance.ifPgc, 41 | 'recSort': instance.recSort, 42 | 'expert': instance.expert, 43 | }; 44 | -------------------------------------------------------------------------------- /lib/business/home_page/model/Consumption.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | part 'Consumption.g.dart'; 3 | @JsonSerializable() 4 | class Consumption { 5 | Consumption({ 6 | this.collectionCount, 7 | this.shareCount, 8 | this.replyCount, 9 | this.realCollectionCount,}); 10 | 11 | 12 | int? collectionCount; 13 | int? shareCount; 14 | int? replyCount; 15 | int? realCollectionCount; 16 | 17 | 18 | factory Consumption.fromJson(Map json) => _$ConsumptionFromJson(json); 19 | 20 | Map toJson() => _$ConsumptionToJson(this); 21 | 22 | } -------------------------------------------------------------------------------- /lib/business/home_page/model/Consumption.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Consumption.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Consumption _$ConsumptionFromJson(Map json) => Consumption( 10 | collectionCount: json['collectionCount'] as int?, 11 | shareCount: json['shareCount'] as int?, 12 | replyCount: json['replyCount'] as int?, 13 | realCollectionCount: json['realCollectionCount'] as int?, 14 | ); 15 | 16 | Map _$ConsumptionToJson(Consumption instance) => 17 | { 18 | 'collectionCount': instance.collectionCount, 19 | 'shareCount': instance.shareCount, 20 | 'replyCount': instance.replyCount, 21 | 'realCollectionCount': instance.realCollectionCount, 22 | }; 23 | -------------------------------------------------------------------------------- /lib/business/home_page/model/Cover.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | part 'Cover.g.dart'; 3 | @JsonSerializable() 4 | class Cover { 5 | Cover({ 6 | this.feed, 7 | this.detail, 8 | this.blurred, 9 | this.homepage,}); 10 | 11 | 12 | String? feed; 13 | String? detail; 14 | String? blurred; 15 | String? homepage; 16 | 17 | 18 | factory Cover.fromJson(Map json) => _$CoverFromJson(json); 19 | 20 | Map toJson() => _$CoverToJson(this); 21 | 22 | } -------------------------------------------------------------------------------- /lib/business/home_page/model/Cover.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Cover.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Cover _$CoverFromJson(Map json) => Cover( 10 | feed: json['feed'] as String?, 11 | detail: json['detail'] as String?, 12 | blurred: json['blurred'] as String?, 13 | homepage: json['homepage'] as String?, 14 | ); 15 | 16 | Map _$CoverToJson(Cover instance) => { 17 | 'feed': instance.feed, 18 | 'detail': instance.detail, 19 | 'blurred': instance.blurred, 20 | 'homepage': instance.homepage, 21 | }; 22 | -------------------------------------------------------------------------------- /lib/business/home_page/model/Data.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'Consumption.dart'; 3 | import 'Provider.dart'; 4 | import 'Author.dart'; 5 | import 'Cover.dart'; 6 | import 'WebUrl.dart'; 7 | 8 | part 'Data.g.dart'; 9 | 10 | @JsonSerializable(explicitToJson: true) 11 | class Data { 12 | Data( 13 | {this.dataType, 14 | this.id, 15 | this.title, 16 | this.description, 17 | this.library, 18 | this.consumption, 19 | this.resourceType, 20 | this.provider, 21 | this.category, 22 | this.author, 23 | this.cover, 24 | this.playUrl, 25 | this.duration, 26 | this.webUrl, 27 | this.releaseTime, 28 | this.ad, 29 | this.type, 30 | this.descriptionPgc, 31 | this.remark, 32 | this.ifLimitVideo, 33 | this.searchWeight, 34 | this.idx, 35 | this.date, 36 | this.descriptionEditor, 37 | this.collected, 38 | this.reallyCollected, 39 | this.played, 40 | this.image}); 41 | 42 | String? dataType; 43 | int? id; 44 | String? title; 45 | String? description; 46 | String? library; 47 | Consumption? consumption; 48 | String? resourceType; 49 | Provider? provider; 50 | String? category; 51 | Author? author; 52 | Cover? cover; 53 | String? playUrl; 54 | int? duration; 55 | WebUrl? webUrl; 56 | int? releaseTime; 57 | bool? ad; 58 | String? type; 59 | String? descriptionPgc; 60 | String? remark; 61 | bool? ifLimitVideo; 62 | int? searchWeight; 63 | int? idx; 64 | int? date; 65 | String? descriptionEditor; 66 | bool? collected; 67 | bool? reallyCollected; 68 | bool? played; 69 | String? image; 70 | 71 | factory Data.fromJson(Map json) => _$DataFromJson(json); 72 | 73 | Map toJson() => _$DataToJson(this); 74 | } 75 | -------------------------------------------------------------------------------- /lib/business/home_page/model/Feed_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'IssueList.dart'; 3 | 4 | part 'Feed_entity.g.dart'; 5 | 6 | @JsonSerializable(explicitToJson: true) 7 | class FeedEntity { 8 | FeedEntity( 9 | {this.issueList, 10 | this.nextPageUrl, 11 | this.nextPublishTime, 12 | this.newestIssueType, 13 | this.date}); 14 | 15 | List? issueList; 16 | String? nextPageUrl; 17 | int? nextPublishTime; 18 | String? newestIssueType; 19 | int? date; 20 | 21 | factory FeedEntity.fromJson(Map json) => 22 | _$FeedEntityFromJson(json); 23 | 24 | Map toJson() => _$FeedEntityToJson(this); 25 | } 26 | -------------------------------------------------------------------------------- /lib/business/home_page/model/Feed_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Feed_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | FeedEntity _$FeedEntityFromJson(Map json) => FeedEntity( 10 | issueList: (json['issueList'] as List?) 11 | ?.map((e) => IssueList.fromJson(e as Map)) 12 | .toList(), 13 | nextPageUrl: json['nextPageUrl'] as String?, 14 | nextPublishTime: json['nextPublishTime'] as int?, 15 | newestIssueType: json['newestIssueType'] as String?, 16 | date: json['date'] as int?, 17 | ); 18 | 19 | Map _$FeedEntityToJson(FeedEntity instance) => 20 | { 21 | 'issueList': instance.issueList?.map((e) => e.toJson()).toList(), 22 | 'nextPageUrl': instance.nextPageUrl, 23 | 'nextPublishTime': instance.nextPublishTime, 24 | 'newestIssueType': instance.newestIssueType, 25 | 'date': instance.date, 26 | }; 27 | -------------------------------------------------------------------------------- /lib/business/home_page/model/Follow.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | part 'Follow.g.dart'; 3 | @JsonSerializable() 4 | class Follow { 5 | Follow({ 6 | this.itemType, 7 | this.itemId, 8 | this.followed,}); 9 | 10 | String? itemType; 11 | int? itemId; 12 | bool? followed; 13 | 14 | 15 | factory Follow.fromJson(Map json) => _$FollowFromJson(json); 16 | 17 | Map toJson() => _$FollowToJson(this); 18 | 19 | } -------------------------------------------------------------------------------- /lib/business/home_page/model/Follow.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Follow.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Follow _$FollowFromJson(Map json) => Follow( 10 | itemType: json['itemType'] as String?, 11 | itemId: json['itemId'] as int?, 12 | followed: json['followed'] as bool?, 13 | ); 14 | 15 | Map _$FollowToJson(Follow instance) => { 16 | 'itemType': instance.itemType, 17 | 'itemId': instance.itemId, 18 | 'followed': instance.followed, 19 | }; 20 | -------------------------------------------------------------------------------- /lib/business/home_page/model/IssueList.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'ItemList.dart'; 3 | 4 | part 'IssueList.g.dart'; 5 | @JsonSerializable(explicitToJson: true) 6 | class IssueList { 7 | IssueList({ 8 | this.releaseTime, 9 | this.type, 10 | this.date, 11 | this.publishTime, 12 | this.itemList, 13 | this.count,}); 14 | 15 | int? releaseTime; 16 | String? type; 17 | int? date; 18 | int? publishTime; 19 | List? itemList; 20 | int? count; 21 | 22 | 23 | factory IssueList.fromJson(Map json) => _$IssueListFromJson(json); 24 | 25 | Map toJson() => _$IssueListToJson(this); 26 | 27 | } -------------------------------------------------------------------------------- /lib/business/home_page/model/IssueList.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'IssueList.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | IssueList _$IssueListFromJson(Map json) => IssueList( 10 | releaseTime: json['releaseTime'] as int?, 11 | type: json['type'] as String?, 12 | date: json['date'] as int?, 13 | publishTime: json['publishTime'] as int?, 14 | itemList: (json['itemList'] as List?) 15 | ?.map((e) => ItemList.fromJson(e as Map)) 16 | .toList(), 17 | count: json['count'] as int?, 18 | ); 19 | 20 | Map _$IssueListToJson(IssueList instance) => { 21 | 'releaseTime': instance.releaseTime, 22 | 'type': instance.type, 23 | 'date': instance.date, 24 | 'publishTime': instance.publishTime, 25 | 'itemList': instance.itemList?.map((e) => e.toJson()).toList(), 26 | 'count': instance.count, 27 | }; 28 | -------------------------------------------------------------------------------- /lib/business/home_page/model/ItemList.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'Data.dart'; 3 | 4 | part 'ItemList.g.dart'; 5 | @JsonSerializable(explicitToJson: true) 6 | class ItemList { 7 | ItemList({ 8 | this.type, 9 | this.data, 10 | this.id, 11 | this.adIndex,}); 12 | 13 | String? type; 14 | Data? data; 15 | int? id; 16 | int? adIndex; 17 | 18 | 19 | 20 | factory ItemList.fromJson(Map json) => _$ItemListFromJson(json); 21 | 22 | Map toJson() => _$ItemListToJson(this); 23 | 24 | } -------------------------------------------------------------------------------- /lib/business/home_page/model/ItemList.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'ItemList.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ItemList _$ItemListFromJson(Map json) => ItemList( 10 | type: json['type'] as String?, 11 | data: json['data'] == null 12 | ? null 13 | : Data.fromJson(json['data'] as Map), 14 | id: json['id'] as int?, 15 | adIndex: json['adIndex'] as int?, 16 | ); 17 | 18 | Map _$ItemListToJson(ItemList instance) => { 19 | 'type': instance.type, 20 | 'data': instance.data?.toJson(), 21 | 'id': instance.id, 22 | 'adIndex': instance.adIndex, 23 | }; 24 | -------------------------------------------------------------------------------- /lib/business/home_page/model/Provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | part 'Provider.g.dart'; 3 | @JsonSerializable() 4 | class Provider { 5 | Provider({ 6 | this.name, 7 | this.alias, 8 | this.icon,}); 9 | 10 | 11 | String? name; 12 | String? alias; 13 | String? icon; 14 | 15 | 16 | factory Provider.fromJson(Map json) => _$ProviderFromJson(json); 17 | 18 | Map toJson() => _$ProviderToJson(this); 19 | 20 | } -------------------------------------------------------------------------------- /lib/business/home_page/model/Provider.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Provider.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Provider _$ProviderFromJson(Map json) => Provider( 10 | name: json['name'] as String?, 11 | alias: json['alias'] as String?, 12 | icon: json['icon'] as String?, 13 | ); 14 | 15 | Map _$ProviderToJson(Provider instance) => { 16 | 'name': instance.name, 17 | 'alias': instance.alias, 18 | 'icon': instance.icon, 19 | }; 20 | -------------------------------------------------------------------------------- /lib/business/home_page/model/Shield.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | part 'Shield.g.dart'; 3 | @JsonSerializable() 4 | class Shield { 5 | Shield({ 6 | this.itemType, 7 | this.itemId, 8 | this.shielded,}); 9 | 10 | 11 | String? itemType; 12 | int? itemId; 13 | bool? shielded; 14 | 15 | 16 | 17 | factory Shield.fromJson(Map json) => _$ShieldFromJson(json); 18 | 19 | Map toJson() => _$ShieldToJson(this); 20 | 21 | } -------------------------------------------------------------------------------- /lib/business/home_page/model/Shield.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Shield.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Shield _$ShieldFromJson(Map json) => Shield( 10 | itemType: json['itemType'] as String?, 11 | itemId: json['itemId'] as int?, 12 | shielded: json['shielded'] as bool?, 13 | ); 14 | 15 | Map _$ShieldToJson(Shield instance) => { 16 | 'itemType': instance.itemType, 17 | 'itemId': instance.itemId, 18 | 'shielded': instance.shielded, 19 | }; 20 | -------------------------------------------------------------------------------- /lib/business/home_page/model/WebUrl.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | part 'WebUrl.g.dart'; 3 | @JsonSerializable() 4 | class WebUrl { 5 | WebUrl({ 6 | this.raw, 7 | this.forWeibo,}); 8 | 9 | 10 | String? raw; 11 | String? forWeibo; 12 | 13 | 14 | factory WebUrl.fromJson(Map json) => _$WebUrlFromJson(json); 15 | 16 | Map toJson() => _$WebUrlToJson(this); 17 | 18 | } -------------------------------------------------------------------------------- /lib/business/home_page/model/WebUrl.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'WebUrl.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | WebUrl _$WebUrlFromJson(Map json) => WebUrl( 10 | raw: json['raw'] as String?, 11 | forWeibo: json['forWeibo'] as String?, 12 | ); 13 | 14 | Map _$WebUrlToJson(WebUrl instance) => { 15 | 'raw': instance.raw, 16 | 'forWeibo': instance.forWeibo, 17 | }; 18 | -------------------------------------------------------------------------------- /lib/business/hot_page/children_page/rank_list_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:get/get.dart'; 3 | import 'package:open_eye/base/controller/base_refresh_controller.dart'; 4 | import 'package:open_eye/base/pageWidget/base_stateful_widget.dart'; 5 | import 'package:open_eye/business/find_page/model/Focus_Entity.dart'; 6 | import 'package:open_eye/business/find_page/model/Focus_Item_Entity.dart'; 7 | import 'package:open_eye/business/hot_page/widget/item_rank_widget.dart'; 8 | import 'package:open_eye/http/apiservice/api_service.dart'; 9 | import 'package:open_eye/widget/pull_smart_refresher.dart'; 10 | 11 | ///实际复用场景-热门-排行榜 12 | // ignore: must_be_immutable 13 | class RankListPage extends BaseStatefulWidget { 14 | String rankType; 15 | String tagType; 16 | 17 | RankListPage({Key? key, required this.rankType, required this.tagType}) 18 | : super(key: key); 19 | 20 | ///动态通过Tag查找Controller-重写tag方法 21 | @override 22 | String get tag { 23 | return tagType + "_" + rankType; 24 | } 25 | 26 | ///解决动态传参初始化Controller,导致PagerView懒加载失效 27 | @override 28 | Widget build(BuildContext context) { 29 | controller.rankType = rankType; 30 | return super.build(context); 31 | } 32 | 33 | @override 34 | Widget buildContent(BuildContext context) { 35 | return RefreshWidget( 36 | controllerTag: tag, 37 | refreshController: controller.refreshController, 38 | child: ListView.builder( 39 | itemBuilder: (context, index) { 40 | return ItemRankWidget(controller.dataList[index]); 41 | }, 42 | itemCount: controller.dataList.length)); 43 | } 44 | 45 | @override 46 | bool showTitleBar() { 47 | return false; 48 | } 49 | } 50 | 51 | class RankListController extends BaseRefreshController { 52 | String rankType = "weekly"; 53 | RxList dataList = [].obs; 54 | 55 | @override 56 | void onReady() { 57 | super.onReady(); 58 | loadNet(); 59 | } 60 | 61 | @override 62 | void loadNet() { 63 | requestPageData(); 64 | } 65 | 66 | @override 67 | void requestPageData({Refresh refresh = Refresh.first}) { 68 | httpRequest(api.queryRankingData(rankType), (value) { 69 | if (refresh == Refresh.first || refresh == Refresh.pull) { 70 | dataList.clear(); 71 | } 72 | var itemList = value.itemList; 73 | if (itemList != null && itemList.isNotEmpty) { 74 | dataList.addAll(itemList); 75 | } 76 | hideRefresh(refreshController, finishLoadMore: true); 77 | }); 78 | } 79 | } 80 | 81 | class RankListBinding extends Bindings { 82 | @override 83 | void dependencies() { 84 | ///放在首页Tab可不写,写时为了单独页面依赖能实现跳转绑定 85 | Get.lazyPut(() => RankListController(), tag: "route_weekly"); 86 | Get.lazyPut(() => RankListController(), tag: "route_monthly"); 87 | Get.lazyPut(() => RankListController(), tag: "route_historical"); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /lib/business/topic_detail/model/Topic_ItemList.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'package:open_eye/business/find_page/model/Focus_Data_entity.dart'; 3 | 4 | part 'Topic_ItemList.g.dart'; 5 | @JsonSerializable(explicitToJson: true) 6 | class TopicItemList { 7 | TopicItemList({ 8 | this.type, 9 | this.data, 10 | this.trackingData, 11 | this.tag, 12 | this.id, 13 | this.adIndex, 14 | }); 15 | 16 | String? type; 17 | FocusDataEntity? data; 18 | dynamic trackingData; 19 | dynamic tag; 20 | int? id; 21 | int? adIndex; 22 | 23 | factory TopicItemList.fromJson(Map json) => _$TopicItemListFromJson(json); 24 | 25 | Map toJson() => _$TopicItemListToJson(this); 26 | } 27 | -------------------------------------------------------------------------------- /lib/business/topic_detail/model/Topic_ItemList.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Topic_ItemList.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | TopicItemList _$TopicItemListFromJson(Map json) => 10 | TopicItemList( 11 | type: json['type'] as String?, 12 | data: json['data'] == null 13 | ? null 14 | : FocusDataEntity.fromJson(json['data'] as Map), 15 | trackingData: json['trackingData'], 16 | tag: json['tag'], 17 | id: json['id'] as int?, 18 | adIndex: json['adIndex'] as int?, 19 | ); 20 | 21 | Map _$TopicItemListToJson(TopicItemList instance) => 22 | { 23 | 'type': instance.type, 24 | 'data': instance.data?.toJson(), 25 | 'trackingData': instance.trackingData, 26 | 'tag': instance.tag, 27 | 'id': instance.id, 28 | 'adIndex': instance.adIndex, 29 | }; 30 | -------------------------------------------------------------------------------- /lib/business/topic_detail/model/Topic_detail_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'package:open_eye/business/topic_detail/model/Topic_ItemList.dart'; 3 | 4 | part 'Topic_detail_entity.g.dart'; 5 | 6 | @JsonSerializable(explicitToJson: true) 7 | class TopicDetailEntity { 8 | TopicDetailEntity( 9 | {this.id, 10 | this.headerImage, 11 | this.brief, 12 | this.text, 13 | this.shareLink, 14 | this.count, 15 | this.itemList}); 16 | 17 | int? id; 18 | String? headerImage; 19 | String? brief; 20 | String? text; 21 | String? shareLink; 22 | int? count; 23 | List? itemList; 24 | 25 | factory TopicDetailEntity.fromJson(Map json) => 26 | _$TopicDetailEntityFromJson(json); 27 | 28 | Map toJson() => _$TopicDetailEntityToJson(this); 29 | } 30 | -------------------------------------------------------------------------------- /lib/business/topic_detail/model/Topic_detail_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'Topic_detail_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | TopicDetailEntity _$TopicDetailEntityFromJson(Map json) => 10 | TopicDetailEntity( 11 | id: json['id'] as int?, 12 | headerImage: json['headerImage'] as String?, 13 | brief: json['brief'] as String?, 14 | text: json['text'] as String?, 15 | shareLink: json['shareLink'] as String?, 16 | count: json['count'] as int?, 17 | itemList: (json['itemList'] as List?) 18 | ?.map((e) => TopicItemList.fromJson(e as Map)) 19 | .toList(), 20 | ); 21 | 22 | Map _$TopicDetailEntityToJson(TopicDetailEntity instance) => 23 | { 24 | 'id': instance.id, 25 | 'headerImage': instance.headerImage, 26 | 'brief': instance.brief, 27 | 'text': instance.text, 28 | 'shareLink': instance.shareLink, 29 | 'count': instance.count, 30 | 'itemList': instance.itemList?.map((e) => e.toJson()).toList(), 31 | }; 32 | -------------------------------------------------------------------------------- /lib/business/type_detail/type_detail_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:get/get.dart'; 4 | import 'package:open_eye/base/controller/base_refresh_controller.dart'; 5 | import 'package:open_eye/base/pageWidget/base_stateless_widget.dart'; 6 | import 'package:open_eye/business/find_page/model/Focus_Entity.dart'; 7 | import 'package:open_eye/business/find_page/model/Focus_Item_Entity.dart'; 8 | import 'package:open_eye/business/hot_page/widget/item_rank_widget.dart'; 9 | import 'package:open_eye/http/apiservice/api_service.dart'; 10 | import 'package:open_eye/widget/base_network_image.dart'; 11 | import 'package:open_eye/widget/pull_smart_refresher.dart'; 12 | 13 | ///分类详情页面 14 | class TypeDetailPage extends BaseStatelessWidget { 15 | const TypeDetailPage({Key? key}) : super(key: key); 16 | 17 | @override 18 | Widget buildContent(BuildContext context) { 19 | return RefreshWidget( 20 | child: CustomScrollView( 21 | slivers: [_createSliverAppBar(), _createSliverList()], 22 | )); 23 | } 24 | 25 | ///顶部滚动AppBar 26 | Widget _createSliverAppBar() { 27 | return SliverAppBar( 28 | elevation: 8.0, 29 | title: Text(controller.typeName), 30 | pinned: true, 31 | expandedHeight: 400.w, 32 | flexibleSpace: FlexibleSpaceBar( 33 | background: BaseNetworkImage( 34 | controller.sliverBg, 35 | fit: BoxFit.fill, 36 | ), 37 | ), 38 | ); 39 | } 40 | 41 | Widget _createSliverList() { 42 | return SliverList( 43 | delegate: SliverChildBuilderDelegate((context, index) { 44 | return ItemRankWidget(controller.dataList[index]); 45 | }, childCount: controller.dataList.length)); 46 | } 47 | 48 | @override 49 | bool showTitleBar() => false; 50 | } 51 | 52 | class TypeDetailController extends BaseRefreshController { 53 | String typeName = Get.parameters["typeName"] ?? ""; 54 | String sliverBg = Get.parameters["headerImg"] ?? ""; 55 | String typeId = Get.parameters["typeId"] ?? ""; 56 | RxList dataList = [].obs; 57 | var pageSize = 10; 58 | 59 | @override 60 | void onReady() { 61 | super.onReady(); 62 | loadNet(); 63 | } 64 | 65 | @override 66 | void loadNet() { 67 | requestPageData(); 68 | } 69 | 70 | @override 71 | void requestPageData({Refresh refresh = Refresh.first}) { 72 | httpRequest(api.queryTypeDetail(typeId, pageIndex * pageSize), 73 | (value) { 74 | if (refresh == Refresh.first || refresh == Refresh.pull) { 75 | dataList.clear(); 76 | } 77 | var itemList = value.itemList; 78 | if (itemList != null && itemList.isNotEmpty) { 79 | dataList.addAll(itemList); 80 | } 81 | hideRefresh(refreshController); 82 | }); 83 | } 84 | } 85 | 86 | class TypeDetailBinding extends Bindings { 87 | @override 88 | void dependencies() { 89 | Get.lazyPut(() => TypeDetailController()); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /lib/constant/api_constant.dart: -------------------------------------------------------------------------------- 1 | class ApiConstant { 2 | static const PROXY_ENABLE = false; 3 | } 4 | -------------------------------------------------------------------------------- /lib/constant/common_constant.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | class CommonConstant { 4 | ///*************************MethodChannel变量****************************/// 5 | 6 | ///Method Channel交互方法 7 | static const METHOD_CHANNEL = "com.dyzt/method_channel"; 8 | 9 | ///*************************MethodChannel变量****************************/// 10 | /// 11 | /// 12 | /// 13 | /// 14 | ///*************************MethodChannel_方法变量****************************/// 15 | 16 | ///Channel获取用户信息方法名 17 | static const METHOD_GET_USER_INFO = "getUserInfo"; 18 | 19 | ///会退按钮原生交互方法名 20 | static const METHOD_ON_BACK_PRESSED = "onBackPressed"; 21 | 22 | ///*************************MethodChannel_方法变量****************************/// 23 | 24 | ///常用字段 25 | static const UUID = "3e7ee30c6fc0004a773dc33b0597b5732b145c04"; 26 | 27 | static const DEVICE_NUM = "ONEPLUS%20A6000"; 28 | 29 | 30 | 31 | 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /lib/constant/http_url.dart: -------------------------------------------------------------------------------- 1 | /// 2 | ///URL配置连接 3 | /// 4 | class HttpUrl { 5 | ///测试环境URL 6 | static const String BASE_URL = "http://baobab.kaiyanapp.com/"; 7 | 8 | static const String BAES_TZYK_URL = "https://test-tzyk.get88.cn/"; 9 | 10 | static const String BASE_GATEWAY_URL = "https://test-gateway.get88.cn/"; 11 | } 12 | -------------------------------------------------------------------------------- /lib/ext/get_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:get/get.dart'; 4 | import 'package:open_eye/res/strings.dart'; 5 | import 'package:open_eye/widget/dialog/dialog_common_style.dart'; 6 | import 'package:open_eye/widget/dialog/dialog_loading.dart'; 7 | 8 | /// @description :get 扩展函数 9 | extension GetExtension on GetInterface { 10 | ///隐藏dialog 11 | dismiss() { 12 | if (Get.isDialogOpen != null && Get.isDialogOpen!) { 13 | Get.back(); 14 | } 15 | } 16 | 17 | ///显示dialog 18 | showLoading({String text = ''}) { 19 | if (Get.isDialogOpen != null && Get.isDialogOpen!) { 20 | Get.back(); 21 | } 22 | Get.dialog(LoadingDialog(text: text.isEmpty ? "加载中" : text), 23 | transitionDuration: const Duration(milliseconds: 500), 24 | barrierDismissible: false); 25 | } 26 | 27 | ///显示公共弹窗 28 | showCommonDialog({ 29 | String title = '', 30 | String content = '', 31 | String negaText = '', 32 | String posiText = '', 33 | bool negaVisible = true, 34 | bool posiVisible = true, 35 | VoidCallback? negaTap, 36 | VoidCallback? posiTap, 37 | backKey = false, 38 | }) { 39 | if (Get.isDialogOpen != null && Get.isDialogOpen!) { 40 | Get.back(); 41 | } 42 | Get.dialog( 43 | CommonDialog( 44 | title: title, 45 | content: content, 46 | negaText: negaText.isEmpty ? StringStyles.quit : negaText, 47 | posiText: posiText.isEmpty ? StringStyles.enter : posiText, 48 | negaVisible: negaVisible, 49 | posiVisible: posiVisible, 50 | negaTap: negaTap, 51 | posiTap: posiTap, 52 | ), 53 | transitionDuration: const Duration(milliseconds: 500), 54 | barrierDismissible: backKey); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/http/apiservice/api_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:open_eye/business/topic_detail/model/Topic_detail_entity.dart'; 3 | import 'package:open_eye/business/find_page/model/Focus_Entity.dart'; 4 | import 'package:open_eye/business/find_page/model/Topic_entity.dart'; 5 | import 'package:open_eye/business/find_page/model/Type_entity.dart'; 6 | import 'package:open_eye/business/home_page/model/Feed_entity.dart'; 7 | import 'package:open_eye/constant/common_constant.dart'; 8 | import 'package:open_eye/constant/http_url.dart'; 9 | import 'package:retrofit/http.dart'; 10 | 11 | import '../dio_client.dart'; 12 | 13 | part 'api_service.g.dart'; 14 | 15 | @RestApi(baseUrl: HttpUrl.BASE_URL) 16 | abstract class ApiService { 17 | factory ApiService({Dio? dio, String? baseUrl}) { 18 | dio ??= DioClient().dio; 19 | return _ApiService(dio, baseUrl: baseUrl); 20 | } 21 | 22 | ///获取首页数据 23 | @GET("api/v2/feed") 24 | Future queryFeedData( 25 | @Query("date") String date, @Query("num") int pageIndex); 26 | 27 | ///获取分类数据 28 | @GET("api/v4/categories") 29 | Future> queryCategoryData(); 30 | 31 | ///获取关注数据 32 | @GET("api/v4/tabs/follow") 33 | Future queryFocusData(@Query("start") int startId); 34 | 35 | ///获取专题数据 36 | @GET("api/v3/specialTopics") 37 | Future queryTopicData(@Query("start") int startId); 38 | 39 | ///获取排行榜数据 weekly monthly historical 40 | @GET("api/v4/rankList/videos") 41 | Future queryRankingData(@Query("strategy") String strategy); 42 | 43 | ///搜索 44 | @GET("api/v1/search?&num=10&start=10") 45 | Future searchData(@Query("query") String query); 46 | 47 | ///获取视频详情 48 | @GET("api/v4/video/related") 49 | Future queryVideoDetail(@Query("id") String videoId); 50 | 51 | ///获取分类详情接口 52 | @GET("api/v4/categories/videoList") 53 | Future queryTypeDetail( 54 | @Query("id") String typeId, @Query("start") int startNum, 55 | {@Query("udid") String uuid = CommonConstant.UUID, 56 | @Query("deviceModel") String deviceModel = CommonConstant.DEVICE_NUM}); 57 | 58 | ///查询专题详情 59 | @GET("api/v3/lightTopics/internal/{id}") 60 | Future queryTopicDetail(@Path("id") String id); 61 | } 62 | -------------------------------------------------------------------------------- /lib/http/apiservice/common_api.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:open_eye/constant/http_url.dart'; 5 | import 'package:open_eye/http/result/base_result.dart'; 6 | import 'package:open_eye/model/upload_img_entity.dart'; 7 | import 'package:retrofit/http.dart'; 8 | 9 | import '../dio_client.dart'; 10 | 11 | part 'common_api.g.dart'; 12 | 13 | ///通用型API,不通过注解设定好BaseUrl,在接口请求上面path用户自定义 14 | @RestApi() 15 | abstract class CommonApi { 16 | ///图片上传接口 17 | factory CommonApi({Dio? dio, String? baseUrl}) { 18 | dio ??= DioClient().dio; 19 | return _CommonApi(dio, baseUrl: baseUrl); 20 | } 21 | 22 | @MultiPart() 23 | @POST("${HttpUrl.BAES_TZYK_URL}ams/uploadImage") 24 | Future> uploadImage( 25 | @Part(name: "image") File uploadMap); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /lib/http/apiservice/common_api.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'common_api.dart'; 4 | 5 | // ************************************************************************** 6 | // RetrofitGenerator 7 | // ************************************************************************** 8 | 9 | class _CommonApi implements CommonApi { 10 | _CommonApi(this._dio, {this.baseUrl}); 11 | 12 | final Dio _dio; 13 | 14 | String? baseUrl; 15 | 16 | @override 17 | Future> uploadImage(uploadMap) async { 18 | const _extra = {}; 19 | final queryParameters = {}; 20 | final _headers = {}; 21 | final _data = FormData(); 22 | _data.files.add(MapEntry( 23 | 'image', 24 | MultipartFile.fromFileSync(uploadMap.path, 25 | filename: uploadMap.path.split(Platform.pathSeparator).last))); 26 | final _result = await _dio.fetch>( 27 | _setStreamType>(Options( 28 | method: 'POST', 29 | headers: _headers, 30 | extra: _extra, 31 | contentType: 'multipart/form-data') 32 | .compose(_dio.options, 'https://test-tzyk.get88.cn/ams/uploadImage', 33 | queryParameters: queryParameters, data: _data) 34 | .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); 35 | final value = BaseResult.fromJson( 36 | _result.data!, 37 | (json) => UploadImgEntity.fromJson(json as Map), 38 | ); 39 | return value; 40 | } 41 | 42 | RequestOptions _setStreamType(RequestOptions requestOptions) { 43 | if (T != dynamic && 44 | !(requestOptions.responseType == ResponseType.bytes || 45 | requestOptions.responseType == ResponseType.stream)) { 46 | if (T == String) { 47 | requestOptions.responseType = ResponseType.plain; 48 | } else { 49 | requestOptions.responseType = ResponseType.json; 50 | } 51 | } 52 | return requestOptions; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/http/apiservice/gateway_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:open_eye/business/complain/model/Feedback_detail_list_entity.dart'; 3 | import 'package:open_eye/business/complain/model/my_feedback_entity.dart'; 4 | import 'package:open_eye/constant/http_url.dart'; 5 | import 'package:open_eye/http/result/base_result.dart'; 6 | import 'package:open_eye/constant/http_url.dart'; 7 | import 'package:open_eye/http/result/base_result.dart'; 8 | import 'package:retrofit/http.dart'; 9 | 10 | import '../dio_client.dart'; 11 | 12 | part 'gateway_api.g.dart'; 13 | 14 | @RestApi(baseUrl: HttpUrl.BASE_GATEWAY_URL) 15 | abstract class GatewayApi { 16 | factory GatewayApi({Dio? dio, String? baseUrl}) { 17 | dio ??= DioClient().dio; 18 | return _GatewayApi(dio, baseUrl: baseUrl); 19 | } 20 | 21 | ///添加反馈信息 22 | @POST("/api/feedback/insertQuestion") 23 | Future> addFeedBack(@Body() Map map); 24 | 25 | ///获取我的反馈列表 26 | @POST("/api/feedback/myQuestionList") 27 | Future>> queryMyFeedback(); 28 | 29 | ///添加反馈信息 30 | @GET("/api/feedback/details") 31 | Future> feedbackDetails( 32 | @Query("id") int id); 33 | 34 | ///回复消息接口 35 | @POST("/api/feedback/insertContent") 36 | Future insertAnswer(@Body() Map map); 37 | } 38 | -------------------------------------------------------------------------------- /lib/http/dio_client.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dio/adapter.dart'; 4 | import 'package:dio/dio.dart'; 5 | import 'package:open_eye/constant/api_constant.dart'; 6 | import 'package:pretty_dio_logger/pretty_dio_logger.dart'; 7 | 8 | import 'interceptor/error_interceptor.dart'; 9 | import 'interceptor/http_params_interceptor.dart'; 10 | 11 | ////Dio客户端 12 | class DioClient { 13 | static void initClient({ 14 | required String baseUrl, 15 | int connectTimeout = CONNECT_TIMEOUT, 16 | int receiveTimeout = RECEIVE_TIMEOUT, 17 | List? interceptors, 18 | }) { 19 | DioClient().init( 20 | baseUrl: baseUrl, 21 | connectTimeout: connectTimeout, 22 | receiveTimeout: receiveTimeout, 23 | interceptors: interceptors, 24 | ); 25 | } 26 | 27 | ///超时时间 28 | static const int CONNECT_TIMEOUT = 15000; 29 | static const int RECEIVE_TIMEOUT = 15000; 30 | 31 | static final DioClient _instance = DioClient._internal(); 32 | 33 | factory DioClient() => _instance; 34 | 35 | late Dio dio; 36 | 37 | DioClient._internal() { 38 | // BaseOptions、Options、RequestOptions 都可以配置参数,优先级别依次递增,且可以根据优先级别覆盖参数 39 | BaseOptions options = BaseOptions( 40 | connectTimeout: CONNECT_TIMEOUT, 41 | // 响应流上前后两次接受到数据的间隔,单位为毫秒。 42 | receiveTimeout: RECEIVE_TIMEOUT, 43 | 44 | // Http请求头. 45 | headers: {}, 46 | ); 47 | 48 | dio = Dio(options); 49 | 50 | // 添加error拦截器 51 | dio.interceptors.add(ErrorInterceptor()); 52 | dio.interceptors.add(HttpParamsInterceptor()); 53 | dio.interceptors.add(PrettyDioLogger( 54 | // 添加日志格式化工具类 55 | requestHeader: true, 56 | requestBody: true, 57 | responseBody: true, 58 | responseHeader: false, 59 | compact: false, 60 | )); 61 | 62 | // 在调试模式下需要抓包调试,所以我们使用代理,并禁用HTTPS证书校验 63 | if (ApiConstant.PROXY_ENABLE) { 64 | (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = 65 | (client) { 66 | client.findProxy = (uri) { 67 | // return "PROXY $PROXY_IP:$PROXY_PORT"; 68 | return "proxy"; 69 | }; 70 | //代理工具会提供一个抓包的自签名证书,会通不过证书校验,所以我们禁用证书校验 71 | client.badCertificateCallback = 72 | (X509Certificate cert, String host, int port) => true; 73 | }; 74 | } 75 | } 76 | 77 | ///初始化公共属性 78 | /// 79 | /// [baseUrl] 地址前缀 80 | /// [connectTimeout] 连接超时赶时间 81 | /// [receiveTimeout] 接收超时赶时间 82 | /// [interceptors] 基础拦截器 83 | void init({ 84 | String? baseUrl, 85 | int connectTimeout = CONNECT_TIMEOUT, 86 | int receiveTimeout = RECEIVE_TIMEOUT, 87 | Map? headers, 88 | List? interceptors, 89 | }) { 90 | dio.options = dio.options.copyWith( 91 | baseUrl: baseUrl, 92 | connectTimeout: connectTimeout, 93 | receiveTimeout: receiveTimeout, 94 | headers: headers ?? const {}, 95 | ); 96 | if (interceptors != null && interceptors.isNotEmpty) { 97 | dio.interceptors.addAll(interceptors); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /lib/http/interceptor/error_interceptor.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:open_eye/utils/log_utils.dart'; 3 | 4 | import '../app_except.dart'; 5 | 6 | ///错误处理拦截器 7 | class ErrorInterceptor extends Interceptor { 8 | @override 9 | void onError(DioError err, ErrorInterceptorHandler handler) { 10 | // error统一处理 11 | AppException appException = AppException.create(err); 12 | // 错误提示 13 | LogE('DioError===: ${appException.toString()}'); 14 | err.error = appException; 15 | super.onError(err, handler); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/http/interceptor/http_params_interceptor.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | 3 | ///请求参数拦截器 4 | class HttpParamsInterceptor extends Interceptor { 5 | static const VERSION = "version"; 6 | static const TOKEN = "token"; 7 | static const DEVICE_NO = "deviceNo"; 8 | static const APP_TYPE_KEY = "appType"; 9 | static const APP_TYPE_VALUE = "Android"; 10 | static const APP_ID_KEY = "appId"; 11 | static const JSON_BODY = "jsonBody"; 12 | static const SIGN = "sign"; 13 | static const TIMESTAMP = "timestamp"; 14 | static const UTF_8 = "UTF-8"; 15 | static const APP_ID = "test_android"; 16 | 17 | @override 18 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) { 19 | var headers = options.headers; 20 | headers["token"] = "MHRYOVRHbEZBL1M0anlXRTdrYWY3Z2hpL1hzWFNZTTh4dWI1NXdKdjRFTG1obUhrN1hjbnJieDlZUnUwT1ArWkRkbmp0ajdIR3dpU1dSdGJRTFRnNnZUZEtwV1dIQWpxSWFORjNUU3JsRzA9"; 21 | super.onRequest(options, handler); 22 | } 23 | 24 | @override 25 | void onResponse(Response response, ResponseInterceptorHandler handler) { 26 | super.onResponse(response, handler); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/http/request_params.dart: -------------------------------------------------------------------------------- 1 | /// 通用请求参数封装 2 | class RequestParams { 3 | RequestParams(); 4 | 5 | final Map _params = {}; 6 | 7 | RequestParams put(String key, dynamic value) { 8 | if (value != null) { 9 | _params[key] = value; 10 | } 11 | return this; 12 | } 13 | 14 | void remove(String key) { 15 | _params.remove(key); 16 | } 17 | 18 | Map getRequestBody() { 19 | return _params; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/http/result/base_page_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'base_page_result.g.dart'; 4 | 5 | ///wanAndroid基本列表数据基类 6 | ///带有范型的基类必须genericArgumentFactories: true 和 JsonKey 7 | @JsonSerializable(genericArgumentFactories: true) 8 | class BasePageRusult { 9 | @JsonKey(name: "offse") 10 | int? offset; 11 | @JsonKey(name: "size") 12 | int? size; 13 | @JsonKey(name: "pageCount") 14 | int? pageCount; 15 | @JsonKey(name: "total") 16 | int? total; 17 | @JsonKey(name: "datas") 18 | List? datas; 19 | 20 | BasePageRusult( 21 | this.offset, this.size, this.pageCount, this.total, this.datas); 22 | 23 | factory BasePageRusult.fromJson( 24 | Map json, T Function(Object? json) fromJsonT) => 25 | _$BasePageRusultFromJson(json, fromJsonT); 26 | 27 | Map toJson(Object Function(T value) toJsonT) => 28 | _$BasePageRusultToJson(this, toJsonT); 29 | } 30 | -------------------------------------------------------------------------------- /lib/http/result/base_page_result.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'base_page_result.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | BasePageRusult _$BasePageRusultFromJson( 10 | Map json, 11 | T Function(Object? json) fromJsonT, 12 | ) => 13 | BasePageRusult( 14 | json['offse'] as int?, 15 | json['size'] as int?, 16 | json['pageCount'] as int?, 17 | json['total'] as int?, 18 | (json['datas'] as List?)?.map(fromJsonT).toList(), 19 | ); 20 | 21 | Map _$BasePageRusultToJson( 22 | BasePageRusult instance, 23 | Object? Function(T value) toJsonT, 24 | ) => 25 | { 26 | 'offse': instance.offset, 27 | 'size': instance.size, 28 | 'pageCount': instance.pageCount, 29 | 'total': instance.total, 30 | 'datas': instance.datas?.map(toJsonT).toList(), 31 | }; 32 | -------------------------------------------------------------------------------- /lib/http/result/base_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | /** 4 | * 大阳智投数据基类 5 | */ 6 | 7 | part 'base_result.g.dart'; 8 | 9 | @JsonSerializable(genericArgumentFactories: true) 10 | class BaseResult { 11 | @JsonKey(name: "resCode") 12 | String? resCode; 13 | @JsonKey(name: "resMessage") 14 | String? resMessage; 15 | @JsonKey(name: "resObject") 16 | T? resObject; 17 | 18 | BaseResult({this.resCode, this.resMessage, this.resObject}); 19 | 20 | factory BaseResult.fromJson( 21 | Map json, T Function(Object? json) fromJsonT) => 22 | _$BaseResultFromJson(json, fromJsonT); 23 | 24 | 25 | Map toJson(Object Function(T value) toJsonT) => 26 | _$BaseResultToJson(this, toJsonT); 27 | 28 | } 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /lib/http/result/base_result.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'base_result.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | BaseResult _$BaseResultFromJson( 10 | Map json, 11 | T Function(Object? json) fromJsonT, 12 | ) => 13 | BaseResult( 14 | resCode: json['resCode'] as String?, 15 | resMessage: json['resMessage'] as String?, 16 | resObject: _$nullableGenericFromJson(json['resObject'], fromJsonT), 17 | ); 18 | 19 | Map _$BaseResultToJson( 20 | BaseResult instance, 21 | Object? Function(T value) toJsonT, 22 | ) => 23 | { 24 | 'resCode': instance.resCode, 25 | 'resMessage': instance.resMessage, 26 | 'resObject': _$nullableGenericToJson(instance.resObject, toJsonT), 27 | }; 28 | 29 | T? _$nullableGenericFromJson( 30 | Object? input, 31 | T Function(Object? json) fromJson, 32 | ) => 33 | input == null ? null : fromJson(input); 34 | 35 | Object? _$nullableGenericToJson( 36 | T? input, 37 | Object? Function(T value) toJson, 38 | ) => 39 | input == null ? null : toJson(input); 40 | -------------------------------------------------------------------------------- /lib/http/result/base_wan_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | /** 4 | * wanAndroid数据基类 5 | */ 6 | part 'base_wan_result.g.dart'; 7 | 8 | @JsonSerializable(genericArgumentFactories: true) 9 | class BaseWanResult { 10 | @JsonKey(name: "errorCode") 11 | int? errorCode; 12 | @JsonKey(name: "errorMsg") 13 | String? errorMsg; 14 | @JsonKey(name: "data") 15 | T? data; 16 | 17 | BaseWanResult(this.errorCode, this.errorMsg, this.data); 18 | 19 | factory BaseWanResult.fromJson( 20 | Map json, T Function(Object? json) fromJsonT) => 21 | _$BaseWanResultFromJson(json, fromJsonT); 22 | 23 | Map toJson(Object Function(T value) toJsonT) => 24 | _$BaseWanResultToJson(this, toJsonT); 25 | } 26 | -------------------------------------------------------------------------------- /lib/http/result/base_wan_result.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'base_wan_result.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | BaseWanResult _$BaseWanResultFromJson( 10 | Map json, 11 | T Function(Object? json) fromJsonT, 12 | ) => 13 | BaseWanResult( 14 | json['errorCode'] as int?, 15 | json['errorMsg'] as String?, 16 | _$nullableGenericFromJson(json['data'], fromJsonT), 17 | ); 18 | 19 | Map _$BaseWanResultToJson( 20 | BaseWanResult instance, 21 | Object? Function(T value) toJsonT, 22 | ) => 23 | { 24 | 'errorCode': instance.errorCode, 25 | 'errorMsg': instance.errorMsg, 26 | 'data': _$nullableGenericToJson(instance.data, toJsonT), 27 | }; 28 | 29 | T? _$nullableGenericFromJson( 30 | Object? input, 31 | T Function(Object? json) fromJson, 32 | ) => 33 | input == null ? null : fromJson(input); 34 | 35 | Object? _$nullableGenericToJson( 36 | T? input, 37 | Object? Function(T value) toJson, 38 | ) => 39 | input == null ? null : toJson(input); 40 | -------------------------------------------------------------------------------- /lib/mixin/dialog/dialog_mixin.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:get/get.dart'; 4 | 5 | mixin DialogMixin { 6 | ///展示加载DialogLoading 7 | void showLoadingDialog() { 8 | Get.dialog(Center( 9 | child: Image.asset( 10 | "assets/images/loading/common_loading.png", 11 | height: 100.w, 12 | width: 100.w, 13 | ), 14 | )); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/mixin/toast/toast_mixin.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluttertoast/fluttertoast.dart'; 2 | 3 | mixin ToastMixin { 4 | void showToast(String? msg, 5 | {Toast toastLength = Toast.LENGTH_SHORT, 6 | ToastGravity gravity = ToastGravity.BOTTOM, 7 | int timeInSecForIos = 1}) { 8 | Fluttertoast.showToast( 9 | msg: msg ?? "", 10 | toastLength: toastLength, 11 | gravity: gravity, 12 | timeInSecForIosWeb: timeInSecForIos, 13 | ); 14 | } 15 | 16 | void showShortToast(String? msg) { 17 | showToast(msg, toastLength: Toast.LENGTH_SHORT); 18 | } 19 | 20 | void showLongToast(String? msg) { 21 | showToast(msg, toastLength: Toast.LENGTH_LONG); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/model/upload_img_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | part 'upload_img_entity.g.dart'; 3 | @JsonSerializable() 4 | class UploadImgEntity { 5 | 6 | String? imgUrl; 7 | 8 | UploadImgEntity(this.imgUrl); 9 | 10 | factory UploadImgEntity.fromJson(Map json) => _$UploadImgEntityFromJson(json); 11 | 12 | Map toJson() => _$UploadImgEntityToJson(this); 13 | } 14 | -------------------------------------------------------------------------------- /lib/model/upload_img_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'upload_img_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | UploadImgEntity _$UploadImgEntityFromJson(Map json) => 10 | UploadImgEntity( 11 | json['imgUrl'] as String?, 12 | ); 13 | 14 | Map _$UploadImgEntityToJson(UploadImgEntity instance) => 15 | { 16 | 'imgUrl': instance.imgUrl, 17 | }; 18 | -------------------------------------------------------------------------------- /lib/res/button_style.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | 4 | import 'colors.dart'; 5 | 6 | 7 | 8 | /// @class : ButtonStyles 9 | 10 | /// @description :ButtonStyles样式 11 | class ButtonStyles{ 12 | 13 | /// Button公共样式,默认点击效果 14 | /// [ButtonStyle] 15 | static ButtonStyle getButtonStyle(){ 16 | return ButtonStyle( 17 | overlayColor: MaterialStateProperty.all(ColorStyle.color_E2E3E8_33), 18 | animationDuration:const Duration(milliseconds: 200), 19 | padding: MaterialStateProperty.all(const EdgeInsets.all(0)), 20 | shape: MaterialStateProperty.all(const StadiumBorder()), 21 | ); 22 | } 23 | 24 | /// Button公共样式,无点击效果 25 | /// [ButtonStyle] 26 | static ButtonStyle getTransparentStyle(){ 27 | return ButtonStyle( 28 | overlayColor: MaterialStateProperty.all(Colors.transparent), 29 | ); 30 | } 31 | 32 | 33 | /// Button公共样式,无圆角 34 | /// [ButtonStyle] 35 | static ButtonStyle getNoShapeStyle(){ 36 | return ButtonStyle( 37 | shadowColor: MaterialStateProperty.all( ColorStyle.colorShadow), 38 | animationDuration:const Duration(milliseconds: 200), 39 | padding: MaterialStateProperty.all(const EdgeInsets.all(0)), 40 | ); 41 | } 42 | } -------------------------------------------------------------------------------- /lib/res/colors.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | 3 | /// @description :颜色样式存储 4 | class ColorStyle { 5 | static const color_white = Color(0xFFFFFFFF); 6 | static const color_black = Color(0xFF000000); 7 | 8 | static const color_B8C0D4 = Color(0xFFB8C0D4); 9 | static const color_1A2F51 = Color(0xFF1A2F51); 10 | static const color_3A65E6 = Color(0xFF3A65E6); 11 | static const color_503A65E6 = Color(0x323A65E6); 12 | static const color_DEE5FC = Color(0xFFDEE5FC); 13 | static const color_E8EDFD = Color(0xFFE8EDFD); 14 | static const color_F3F6FE = Color(0xFFF3F6FE); 15 | static const color_D9E1FB = Color(0xFFD9E1FB); 16 | static const color_89A3F0 = Color(0xFF89A3F0); 17 | 18 | 19 | 20 | 21 | static const color_24CF5F = Color(0xFF24CF5F); 22 | static const color_FBE240 = Color(0xFFFBE240); 23 | static const color_FFAE2E = Color(0xFFFFAE2E); 24 | static const color_FE8C28 = Color(0xFFFE8C28); 25 | static const color_EA4C43 = Color(0xFFEA4C43); 26 | 27 | static const color_24CF5F_20 = Color(0xFF4C8D66); 28 | static const color_6A6969 = Color(0xFF6A6969); 29 | static const color_E2E3E8_33 = Color(0x33E2E3E8); 30 | static const color_E2E3E8_4D = Color(0x4DE2E3E8); 31 | static const color_E2E3E8_66 = Color(0x66E2E3E8); 32 | 33 | static const colorShadow = Color(0x66E0E6FD); 34 | static const colorShadow2 = Color(0x41747575); 35 | 36 | static const color_474747 = Color(0xff474747); 37 | static const color_d5d5d5 = Color(0xffe5e5e5); 38 | static const color_000000 = Color(0xff000000); 39 | static const color_111111 = Color(0xff111111); 40 | static const color_222222 = Color(0xff222222); 41 | static const color_333333 = Color(0xff333333); 42 | static const color_444444 = Color(0xff444444); 43 | static const color_555555 = Color(0xff555555); 44 | static const color_666666 = Color(0xff666666); 45 | static const color_777777 = Color(0xff777777); 46 | static const color_888888 = Color(0xff888888); 47 | static const color_999999 = Color(0xff999999); 48 | static const color_CCCCCC = Color(0xffCCCCCC); 49 | 50 | static const color_FFFFFF = Color(0xFFFFFFFF); 51 | static const color_F9F9F9 = Color(0xFFF9F9F9); 52 | static const color_F3F3F3 = Color(0xFFF3F3F3); 53 | static const color_F0F0F0 = Color(0xFFF0F0F0); 54 | static const color_F5F5F5 = Color(0xFFF5F5F5); 55 | static const color_F8F9FC = Color(0xFFFCFCFC); 56 | static const color_EFF1F8 = Color(0xFFE7EBFA); 57 | static const color_FAFAFB = Color(0xFFFAFAFB); 58 | } 59 | -------------------------------------------------------------------------------- /lib/res/strings.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | ///字符串常量管理 4 | class StringStyles { 5 | static const String appName = 'appName'; 6 | static const String loading = '加载中'; 7 | static const String enter = "确认"; 8 | static const String quit = "取消"; 9 | 10 | static const Map complainAQMap = { 11 | "我无法适应老师的操作风格?": "您好,每位老师有不同的风格特色,针对于咱们的情况,建议平时可以多和服务人员沟通一下,选择合适自己的操作模式。", 12 | "如何反馈相关诉求?": "您好,您对我司服务有更好的建议或想提供宝贵的意见,欢迎随时与我们线上留言或我司热线,我们将尽快与您联系,竭诚为您服务。", 13 | "如何更换课程?": "您好,您对我司服务有更好的建议或想提供宝贵的意见,欢迎随时与我们线上留言或我司热线,我们将尽快与您联系,竭诚为您服务。", 14 | "如何更换手机号?": "您好,更换事宜详情请咨询服务人员协助处理。", 15 | "为什么我经常收不到推送消息?": "您可以在工作日时间联系您的专属服务人员/助理申请修改。" 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /lib/route/router_auth_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:get/get_navigation/src/routes/route_middleware.dart'; 3 | import 'package:open_eye/route/routes.dart'; 4 | 5 | ///登陆拦截中间件 6 | class RouteAuthMiddleware extends GetMiddleware { 7 | @override 8 | int? priority = 0; 9 | 10 | RouteAuthMiddleware({required this.priority}); 11 | 12 | @override 13 | RouteSettings? redirect(String? route) { 14 | // Future.delayed( 15 | // const Duration(seconds: 1), () => Get.snackbar("提示", "请先登录APP")); 16 | // return const RouteSettings(name: AppRoutes.TEST_PAGE); 17 | return const RouteSettings(name: AppRoutes.mainPage); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/route/router_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get.dart'; 2 | import 'package:open_eye/route/routes.dart'; 3 | 4 | class RouterUtils { 5 | ///跳转图片预览 6 | static void toPreviewPhotoView(String? imageUrl) { 7 | imageUrl = imageUrl ?? ""; 8 | if (imageUrl.isNotEmpty) { 9 | Get.toNamed(AppRoutes.photoPreviewPage, arguments: imageUrl); 10 | } 11 | } 12 | 13 | ///搜索页面 14 | static void toSearchPage() { 15 | Get.toNamed(AppRoutes.searchPage); 16 | } 17 | 18 | ///跳转投诉详情列表页面 19 | static void toComplainRecordPage(int? id) { 20 | Get.toNamed( 21 | AppRoutes.complainHomePage + AppRoutes.complainMyRecordPage, 22 | arguments: id); 23 | } 24 | 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /lib/utils/injection.dart: -------------------------------------------------------------------------------- 1 | import 'package:event_bus/event_bus.dart'; 2 | import 'package:get/get.dart'; 3 | import 'package:open_eye/http/apiservice/api_service.dart'; 4 | import 'package:open_eye/http/apiservice/common_api.dart'; 5 | import 'package:open_eye/http/apiservice/gateway_api.dart'; 6 | import 'package:shared_preferences/shared_preferences.dart'; 7 | 8 | ///初始化注入对象 9 | class Injection extends GetxService { 10 | Future init() async { 11 | await Get.putAsync(() => SharedPreferences.getInstance()); 12 | Get.lazyPut(() => ApiService(), fenix: true); 13 | Get.lazyPut(() => GatewayApi(), fenix: true); 14 | Get.lazyPut(() => CommonApi(), fenix: true); 15 | Get.lazyPut(() => EventBus(), fenix: true); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/utils/keyboard_util.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | 5 | /// @description :软键盘相关工具类 6 | class KeyboardUtils{ 7 | 8 | 9 | ///隐藏软键盘 10 | ///[context] 上下文 11 | static hideKeyboard(BuildContext context) { 12 | FocusScopeNode currentFocus = FocusScope.of(context); 13 | if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) { 14 | FocusManager.instance.primaryFocus?.unfocus(); 15 | } 16 | } 17 | 18 | } 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /lib/utils/log_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:logger/logger.dart'; 2 | 3 | var _logger = Logger( 4 | // printer: PrettyPrinter( 5 | // methodCount: 0, 6 | // ), 7 | ); 8 | 9 | LogV(String msg) { 10 | _logger.v(msg); 11 | } 12 | 13 | LogD(String msg) { 14 | _logger.d(msg); 15 | } 16 | 17 | LogI(String msg) { 18 | _logger.i(msg); 19 | } 20 | 21 | LogW(String msg) { 22 | _logger.w(msg); 23 | } 24 | 25 | LogE(String msg) { 26 | _logger.e(msg); 27 | } 28 | 29 | LogWTF(String msg) { 30 | _logger.wtf(msg); 31 | } 32 | -------------------------------------------------------------------------------- /lib/utils/method_channel.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:open_eye/constant/common_constant.dart'; 3 | 4 | import 'log_utils.dart'; 5 | 6 | var channel = const MethodChannel(CommonConstant.METHOD_CHANNEL); 7 | 8 | ///获取用户信息原生交互 9 | // Future getUserInfo() async { 10 | // var result = await channel.invokeMethod(CommonConstant.METHOD_GET_USER_INFO); 11 | // LogD("用户信息$result"); 12 | // UserInfo userInfo = UserInfo.fromJson(Map.from(result)); 13 | // return userInfo; 14 | // } 15 | 16 | ///点击顶部会退按钮操作 17 | Future onBackPressed() async { 18 | await channel.invokeMethod(CommonConstant.METHOD_ON_BACK_PRESSED); 19 | } 20 | -------------------------------------------------------------------------------- /lib/utils/preference_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get_core/src/get_main.dart'; 2 | import 'package:get/get_instance/src/extension_instance.dart'; 3 | import 'package:shared_preferences/shared_preferences.dart'; 4 | 5 | /// shared_preferences 管理类 6 | class PreferenceUtils { 7 | static PreferenceUtils? _instance; 8 | 9 | static PreferenceUtils get instance => PreferenceUtils(); 10 | 11 | PreferenceUtils._internal(); 12 | 13 | factory PreferenceUtils() { 14 | _instance ??= PreferenceUtils._internal(); 15 | return _instance!; 16 | } 17 | 18 | putInteger(String key, int value) => 19 | Get.find().setInt(key, value); 20 | 21 | putString(String key, String value) => 22 | Get.find().setString(key, value); 23 | 24 | putBool(String key, bool value) => 25 | Get.find().setBool(key, value); 26 | 27 | putDouble(String key, double value) => 28 | Get.find().setDouble(key, value); 29 | 30 | putStringList(String key, List value) => 31 | Get.find().setStringList(key, value); 32 | 33 | int getInteger(String key, [int defaultValue = 0]) { 34 | var value = Get.find().getInt(key); 35 | return value ?? defaultValue; 36 | } 37 | 38 | String getString(String key, [String defaultValue = '']) { 39 | var value = Get.find().getString(key); 40 | return value ?? defaultValue; 41 | } 42 | 43 | bool getBool(String key, [bool defaultValue = false]) { 44 | var value = Get.find().getBool(key); 45 | return value ?? defaultValue; 46 | } 47 | 48 | double getDouble(String key, [double defaultValue = 0.0]) { 49 | var value = Get.find().getDouble(key); 50 | return value ?? defaultValue; 51 | } 52 | 53 | List getStringList(String key, 54 | [List defaultValue = const []]) { 55 | var value = Get.find().getStringList(key); 56 | return value ?? defaultValue; 57 | } 58 | 59 | void clear() { 60 | Get.find().clear(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/utils/sp_utils.dart: -------------------------------------------------------------------------------- 1 | class SPUtils {} 2 | -------------------------------------------------------------------------------- /lib/widget/base_network_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:get/get_utils/src/extensions/context_extensions.dart'; 5 | import 'package:open_eye/res/colors.dart'; 6 | import 'package:open_eye/utils/log_utils.dart'; 7 | 8 | // ignore: must_be_immutable 9 | class BaseNetworkImage extends CachedNetworkImage { 10 | String imgUrl; 11 | 12 | BaseNetworkImage( 13 | this.imgUrl, { 14 | width, 15 | fit, 16 | height, 17 | Key? key, 18 | }) : super( 19 | key: key, 20 | imageUrl: imgUrl, 21 | height: height, 22 | width: width, 23 | fit: fit, 24 | placeholder: (context, url) { 25 | // var height2 = context.height; 26 | // var width2 = context.width; 27 | // LogWTF("链接、宽高>>>>>>>>>>>>>>$height2>>>>>>>>$width2>>>>>>$url"); 28 | double size = 50; 29 | if (width != null && width != double.infinity) { 30 | size = width * 0.5; 31 | } else if (height != null) { 32 | size = height * 0.5; 33 | } 34 | return Icon( 35 | Icons.image, 36 | size: size, 37 | color: ColorStyle.color_999999, 38 | ); 39 | return Image.asset( 40 | "assets/images/back_placeholder.png", width: width, 41 | height: height, 42 | // centerSlice: const Rect.fromLTRB(24, 26, 95, 93), //.9图的效果(有问题,待处理) 43 | ); 44 | }, 45 | errorWidget: (context, url, error) { 46 | double size = 50; 47 | if (width != null && width != double.infinity) { 48 | size = width * 0.5; 49 | } else if (height != null) { 50 | size = height * 0.5; 51 | } 52 | return Icon( 53 | Icons.image, 54 | size: size, 55 | color: ColorStyle.color_666666, 56 | ); 57 | return Image.asset( 58 | "assets/images/back_placeholder.png", width: width, 59 | height: height, 60 | // centerSlice: const Rect.fromLTRB(24, 26, 95, 93), //.9图的效果(有问题,待处理) 61 | ); 62 | }, 63 | fadeInDuration: const Duration(milliseconds: 0), 64 | fadeOutDuration: const Duration(milliseconds: 0), 65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /lib/widget/behavior/over_scroll_behavior.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class OverScrollBehavior extends ScrollBehavior { 7 | @override 8 | Widget buildViewportChrome(BuildContext context, Widget child, AxisDirection axisDirection) { 9 | if (getPlatform(context) == TargetPlatform.android || getPlatform(context) == TargetPlatform.fuchsia) { 10 | return GlowingOverscrollIndicator( 11 | child: child, 12 | showLeading: false, 13 | showTrailing: false, 14 | axisDirection: axisDirection, 15 | color: Theme.of(context).accentColor, 16 | ); 17 | } else { 18 | return child; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /lib/widget/dialog/dialog_loading.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:open_eye/res/style.dart'; 4 | 5 | /// @description :公共加载弹窗 6 | class LoadingDialog extends StatefulWidget { 7 | String text = ''; 8 | 9 | LoadingDialog({ 10 | Key? key, 11 | this.text = "加载中...", 12 | }) : super(key: key); 13 | 14 | @override 15 | State createState() => LoadingDialogState(); 16 | } 17 | 18 | class LoadingDialogState extends State 19 | with SingleTickerProviderStateMixin { 20 | late AnimationController _animController; 21 | 22 | @override 23 | void initState() { 24 | super.initState(); 25 | _animController = 26 | AnimationController(vsync: this, duration: const Duration(seconds: 1)); 27 | _animController.forward(); 28 | } 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return Material( 33 | //创建透明层 34 | type: MaterialType.transparency, //透明类型 35 | child: Center( 36 | //保证控件居中效果 37 | child: SizedBox( 38 | width: 100, 39 | height: 100, 40 | child: Container( 41 | decoration: const ShapeDecoration( 42 | color: Colors.black45, 43 | shape: RoundedRectangleBorder( 44 | borderRadius: BorderRadius.all( 45 | Radius.circular(8.0), 46 | ), 47 | ), 48 | ), 49 | child: Column( 50 | mainAxisAlignment: MainAxisAlignment.center, 51 | crossAxisAlignment: CrossAxisAlignment.center, 52 | children: [ 53 | Center( 54 | child: RotationTransition( 55 | child: Image.asset( 56 | "assets/images/loading/common_loading.png", 57 | height: 100.w, 58 | width: 100.w, 59 | ), 60 | turns: _animController 61 | ..addStatusListener((status) { 62 | if (status == AnimationStatus.completed) { 63 | _animController.reset(); 64 | _animController.forward(); 65 | } 66 | }), 67 | ), 68 | ), 69 | Text(widget.text, style: Styles.style_white_24), 70 | ], 71 | ), 72 | ), 73 | ), 74 | )); 75 | } 76 | 77 | @override 78 | void dispose() { 79 | _animController.dispose(); //解决内存泄漏 80 | super.dispose(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/widget/fijkplayer_skin/video_config.dart: -------------------------------------------------------------------------------- 1 | // 定制UI配置项 2 | import 'fijkplayer_skin.dart'; 3 | 4 | class PlayerShowConfig implements ShowConfigAbs { 5 | @override 6 | bool drawerBtn = true; 7 | @override 8 | bool nextBtn = true; 9 | @override 10 | bool speedBtn = true; 11 | @override 12 | bool topBar = true; 13 | @override 14 | bool lockBtn = true; 15 | @override 16 | bool autoNext = true; 17 | @override 18 | bool bottomPro = true; 19 | @override 20 | bool stateAuto = true; 21 | @override 22 | bool isAutoPlay = false; 23 | } -------------------------------------------------------------------------------- /lib/widget/frame_animate_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | ////逐帧动画展示Widget 4 | class FrameAnimateWidget extends StatefulWidget { 5 | late Map imageCaches; 6 | late double width; 7 | late double height; 8 | late Color backColor; 9 | 10 | FrameAnimateWidget(this.imageCaches, this.width, this.height, this.backColor, 11 | {Key? key}) 12 | : super(key: key); 13 | 14 | @override 15 | State createState() { 16 | return FrameAnimateState(); 17 | } 18 | } 19 | 20 | class FrameAnimateState extends State { 21 | late bool _disposed; 22 | late Duration _duration; 23 | late int _imageIndex; 24 | late Container _container; 25 | 26 | @override 27 | void initState() { 28 | super.initState(); 29 | _disposed = false; 30 | _duration = const Duration(milliseconds: 50); 31 | _imageIndex = 0; 32 | _container = Container(height: widget.height, width: widget.width,color: widget.backColor); 33 | _updateImage(); 34 | } 35 | 36 | void _updateImage() { 37 | if (_disposed || widget.imageCaches.isEmpty) { 38 | return; 39 | } 40 | 41 | setState(() { 42 | if (_imageIndex >= widget.imageCaches.length) { 43 | _imageIndex = 0; 44 | } 45 | _container = Container( 46 | color: widget.backColor, 47 | child: widget.imageCaches[_imageIndex], 48 | height: widget.height, 49 | width: widget.width); 50 | _imageIndex++; 51 | }); 52 | Future.delayed(_duration, () { 53 | _updateImage(); 54 | }); 55 | } 56 | 57 | @override 58 | void dispose() { 59 | super.dispose(); 60 | _disposed = true; 61 | // widget.imageCaches.clear(); 62 | } 63 | 64 | @override 65 | Widget build(BuildContext context) { 66 | return _container; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/widget/image_extends.dart: -------------------------------------------------------------------------------- 1 | import 'package:extended_image/extended_image.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class ImageExends extends StatelessWidget { 5 | final String imgUrl; 6 | int? width; 7 | int? height; 8 | 9 | ImageExends({ 10 | Key? key, 11 | required this.imgUrl, 12 | this.width, 13 | this.height, 14 | }) : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return ExtendedImage.network( 19 | imgUrl, 20 | compressionRatio: 0.5, 21 | width: MediaQuery.of(context).size.width, 22 | // height: MediaQuery.of(context).size.height, 23 | cache: true, 24 | loadStateChanged: (ExtendedImageState state) { 25 | if (state.extendedImageLoadState == LoadState.loading) { 26 | return Image.asset( 27 | "assets/images/movie-lazy.gif", 28 | fit: BoxFit.fill, 29 | ); 30 | } else if (state.extendedImageLoadState == LoadState.failed) { 31 | return Image.asset( 32 | "assets/images/movie-lazy.gif", 33 | fit: BoxFit.fill, 34 | ); 35 | } else { 36 | return null; 37 | } 38 | }, 39 | fit: BoxFit.fitWidth, 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/widget/keep_alive_wrapper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | 4 | ///参照Flutter实战·第二版实现 5 | ///https://book.flutterchina.club/chapter6/keepalive.html#_6-8-2-keepalivewrapper 6 | class KeepAliveWrapper extends StatefulWidget { 7 | const KeepAliveWrapper({ 8 | Key? key, 9 | this.keepAlive = true, 10 | required this.child, 11 | }) : super(key: key); 12 | final bool keepAlive; 13 | final Widget child; 14 | 15 | @override 16 | _KeepAliveWrapperState createState() => _KeepAliveWrapperState(); 17 | } 18 | 19 | class _KeepAliveWrapperState extends State 20 | with AutomaticKeepAliveClientMixin { 21 | @override 22 | Widget build(BuildContext context) { 23 | super.build(context); 24 | return widget.child; 25 | } 26 | 27 | @override 28 | void didUpdateWidget(covariant KeepAliveWrapper oldWidget) { 29 | if(oldWidget.keepAlive != widget.keepAlive) { 30 | // keepAlive 状态需要更新,实现在 AutomaticKeepAliveClientMixin 中 31 | updateKeepAlive(); 32 | } 33 | super.didUpdateWidget(oldWidget); 34 | } 35 | 36 | @override 37 | bool get wantKeepAlive => widget.keepAlive; 38 | } -------------------------------------------------------------------------------- /lib/widget/loading_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | 4 | import 'frame_animate_widget.dart'; 5 | 6 | ////页面加载Loading动画 7 | class LoadingWidget extends StatelessWidget { 8 | ///gaplessPlayback属性是解决加载帧动画闪烁,根本原因是图片解析速度跟不上帧动画加载速度,导致刚开始加载闪烁 9 | var imageCache = { 10 | 0: Image.asset( 11 | "assets/images/loading/loding_00000.webp", 12 | gaplessPlayback: true, 13 | ), 14 | 1: Image.asset("assets/images/loading/loding_00001.webp", 15 | gaplessPlayback: true), 16 | 2: Image.asset("assets/images/loading/loding_00002.webp", 17 | gaplessPlayback: true), 18 | 3: Image.asset("assets/images/loading/loding_00003.webp", 19 | gaplessPlayback: true), 20 | 4: Image.asset("assets/images/loading/loding_00004.webp", 21 | gaplessPlayback: true), 22 | 5: Image.asset("assets/images/loading/loding_00005.webp", 23 | gaplessPlayback: true), 24 | 6: Image.asset("assets/images/loading/loding_00006.webp", 25 | gaplessPlayback: true), 26 | 7: Image.asset("assets/images/loading/loding_00007.webp", 27 | gaplessPlayback: true), 28 | 8: Image.asset("assets/images/loading/loding_00008.webp", 29 | gaplessPlayback: true), 30 | 9: Image.asset("assets/images/loading/loding_00009.webp", 31 | gaplessPlayback: true), 32 | 10: Image.asset("assets/images/loading/loding_00010.webp", 33 | gaplessPlayback: true), 34 | 11: Image.asset("assets/images/loading/loding_00011.webp", 35 | gaplessPlayback: true), 36 | 12: Image.asset("assets/images/loading/loding_00012.webp", 37 | gaplessPlayback: true), 38 | 13: Image.asset("assets/images/loading/loding_00013.webp", 39 | gaplessPlayback: true), 40 | 14: Image.asset("assets/images/loading/loding_00014.webp", 41 | gaplessPlayback: true), 42 | 15: Image.asset("assets/images/loading/loding_00015.webp", 43 | gaplessPlayback: true), 44 | 16: Image.asset("assets/images/loading/loding_00016.webp", 45 | gaplessPlayback: true), 46 | 17: Image.asset("assets/images/loading/loding_00017.webp", 47 | gaplessPlayback: true), 48 | 18: Image.asset("assets/images/loading/loding_00018.webp", 49 | gaplessPlayback: true), 50 | 19: Image.asset("assets/images/loading/loding_00019.webp", 51 | gaplessPlayback: true), 52 | 20: Image.asset("assets/images/loading/loding_00020.webp", 53 | gaplessPlayback: true), 54 | 21: Image.asset("assets/images/loading/loding_00021.webp", 55 | gaplessPlayback: true), 56 | 22: Image.asset("assets/images/loading/loding_00022.webp", 57 | gaplessPlayback: true), 58 | 23: Image.asset("assets/images/loading/loding_00023.webp", 59 | gaplessPlayback: true) 60 | }; 61 | 62 | LoadingWidget({Key? key}) : super(key: key); 63 | 64 | @override 65 | Widget build(BuildContext context) { 66 | return FrameAnimateWidget(imageCache, 200.w, 200.w, Colors.transparent); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/widget/pull_smart_refresher.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:get/get.dart'; 3 | import 'package:open_eye/base/controller/base_refresh_controller.dart'; 4 | import 'package:open_eye/res/colors.dart'; 5 | import 'package:pull_to_refresh/pull_to_refresh.dart'; 6 | 7 | import 'behavior/over_scroll_behavior.dart'; 8 | 9 | ///刷新状态 10 | enum Refresh { 11 | ///初次进入页面加载 12 | first, 13 | 14 | ///上拉加载 15 | pull, 16 | 17 | ///下拉加载 18 | down, 19 | } 20 | 21 | // ignore: must_be_immutable 22 | class RefreshWidget 23 | extends GetView { 24 | RefreshWidget({ 25 | Key? key, 26 | this.enablePullUp = true, 27 | this.enablePullDown = true, 28 | this.onRefresh, 29 | this.onLoadMore, 30 | this.refreshController, 31 | this.controllerTag, 32 | required this.child, 33 | }) : super(key: key); 34 | 35 | @override 36 | String? get tag => controllerTag ?? ""; 37 | 38 | ///解决PageView下Controller查找问题 39 | String? controllerTag; 40 | 41 | ///是否启用上拉 42 | bool enablePullUp = true; 43 | 44 | ///是否启用下拉 45 | bool enablePullDown = true; 46 | 47 | ///下拉刷新回调 48 | VoidCallback? onRefresh; 49 | 50 | ///上拉加载回调 51 | VoidCallback? onLoadMore; 52 | 53 | ///外部传参RefreshController 54 | RefreshController? refreshController; 55 | 56 | ///子类,必须是ListView-ScrolleView等 57 | Widget? child; 58 | 59 | @override 60 | Widget build(BuildContext context) { 61 | return ScrollConfiguration( 62 | behavior: OverScrollBehavior(), 63 | child: SmartRefresher( 64 | key: key, 65 | controller: refreshController ?? controller.refreshController, 66 | enablePullDown: enablePullDown, 67 | enablePullUp: enablePullUp, 68 | onRefresh: () => controller.onLoadRefresh(), 69 | onLoading: () => controller.onLoadMore(), 70 | header: const ClassicHeader( 71 | releaseText: "释放立即刷新", 72 | refreshingText: "正在刷新...", 73 | completeText: "刷新完成", 74 | idleText: "下拉可以刷新", 75 | textStyle: TextStyle(color: ColorStyle.color_000000), 76 | ), 77 | // header: WaterDropHeader(), 78 | footer: const ClassicFooter( 79 | loadingText: "正在加载中...", 80 | idleText: "上拉加载更多", 81 | canLoadingText: "松手加载更多", 82 | textStyle: TextStyle(color: ColorStyle.color_000000), 83 | noDataText: "—— 我是有底线的 ——", 84 | ), 85 | child: child)); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /screenshot/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/1.png -------------------------------------------------------------------------------- /screenshot/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/10.png -------------------------------------------------------------------------------- /screenshot/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/11.png -------------------------------------------------------------------------------- /screenshot/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/12.png -------------------------------------------------------------------------------- /screenshot/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/13.png -------------------------------------------------------------------------------- /screenshot/14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/14.jpg -------------------------------------------------------------------------------- /screenshot/15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/15.jpg -------------------------------------------------------------------------------- /screenshot/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/2.png -------------------------------------------------------------------------------- /screenshot/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/3.png -------------------------------------------------------------------------------- /screenshot/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/4.png -------------------------------------------------------------------------------- /screenshot/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/5.png -------------------------------------------------------------------------------- /screenshot/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/6.png -------------------------------------------------------------------------------- /screenshot/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/7.png -------------------------------------------------------------------------------- /screenshot/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/8.png -------------------------------------------------------------------------------- /screenshot/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/9.png -------------------------------------------------------------------------------- /screenshot/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/demo.gif -------------------------------------------------------------------------------- /screenshot/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WinWang/open_eye/c7fe7c0d4ff5b44d66b3b1d2527d2d93917183c5/screenshot/download.png -------------------------------------------------------------------------------- /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:open_eye/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(const 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 | --------------------------------------------------------------------------------