├── .gitignore
├── .metadata
├── README.md
├── README
├── 2021-07-24-13-54-17.png
├── 2021-07-24-14-47-42.png
├── 2021-09-18-22-26-23.png
├── 2021-09-18-22-52-54.png
├── architecture.png
├── catalog.png
├── one-way-data-flow-04fe46332c1ccb3497ecb04b94e55b97.png
└── scheme.gif
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── flutter_ducafecat_news_getx
│ │ │ │ └── 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
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
├── fonts
│ ├── Avenir-Book.ttf
│ ├── Montserrat-Medium.ttf
│ ├── Montserrat-SemiBold.ttf
│ ├── demo_index.html
│ └── iconfont.ttf
├── icons
│ └── logo-1024.png
└── images
│ ├── 2.0x
│ ├── account_header.png
│ ├── channel-bbc.png
│ ├── channel-bloomberg.png
│ ├── channel-cnn.png
│ ├── channel-fox.png
│ ├── channel-nbc.png
│ ├── channel-rt.png
│ ├── feature-1.png
│ ├── feature-2.png
│ ├── feature-3.png
│ ├── icons-facebook.png
│ ├── icons-google.png
│ ├── icons-twitter.png
│ └── logo.png
│ ├── 3.0x
│ ├── account_header.png
│ ├── channel-bbc.png
│ ├── channel-bloomberg.png
│ ├── channel-cnn.png
│ ├── channel-fox.png
│ ├── channel-nbc.png
│ ├── channel-rt.png
│ ├── feature-1.png
│ ├── feature-2.png
│ ├── feature-3.png
│ ├── icons-facebook.png
│ ├── icons-google.png
│ ├── icons-twitter.png
│ └── logo.png
│ ├── account_header.png
│ ├── channel-bbc.png
│ ├── channel-bloomberg.png
│ ├── channel-cnn.png
│ ├── channel-fox.png
│ ├── channel-nbc.png
│ ├── channel-rt.png
│ ├── feature-1.png
│ ├── feature-2.png
│ ├── feature-3.png
│ ├── icons-facebook.png
│ ├── icons-google.png
│ ├── icons-twitter.png
│ └── logo.png
├── doc
├── scheme
│ └── index.html
├── 新闻客户端api.apifox.json
└── 目录结构.mindnode
│ ├── QuickLook
│ └── Preview.jpg
│ ├── contents.xml
│ ├── style.mindnodestyle
│ ├── contents.xml
│ └── metadata.plist
│ └── viewState.plist
├── 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
├── common
│ ├── apis
│ │ ├── apis.dart
│ │ ├── news.dart
│ │ └── user.dart
│ ├── entities
│ │ ├── app.dart
│ │ ├── categories.dart
│ │ ├── channels.dart
│ │ ├── entities.dart
│ │ ├── news.dart
│ │ ├── tags.dart
│ │ └── user.dart
│ ├── langs
│ │ ├── en_US.dart
│ │ ├── translation_service.dart
│ │ ├── zh_HK.dart
│ │ └── zh_Hans.dart
│ ├── middlewares
│ │ ├── middlewares.dart
│ │ ├── router_auth.dart
│ │ └── router_welcome.dart
│ ├── routers
│ │ ├── names.dart
│ │ ├── names.txt
│ │ ├── observers.dart
│ │ ├── pages.dart
│ │ ├── pages.txt
│ │ └── routes.dart
│ ├── services
│ │ ├── services.dart
│ │ └── storage.dart
│ ├── store
│ │ ├── config.dart
│ │ ├── store.dart
│ │ └── user.dart
│ ├── style
│ │ ├── color.dart
│ │ ├── style.dart
│ │ └── theme.dart
│ ├── utils
│ │ ├── date.dart
│ │ ├── http.dart
│ │ ├── iconfont.dart
│ │ ├── loading.dart
│ │ ├── logger.dart
│ │ ├── security.dart
│ │ ├── utils.dart
│ │ └── validator.dart
│ ├── values
│ │ ├── borders.dart
│ │ ├── cache.dart
│ │ ├── colors.dart
│ │ ├── proxy.dart
│ │ ├── radii.dart
│ │ ├── server.dart
│ │ ├── shadows.dart
│ │ ├── storage.dart
│ │ └── values.dart
│ └── widgets
│ │ ├── app.dart
│ │ ├── button.dart
│ │ ├── image.dart
│ │ ├── input.dart
│ │ ├── skeleton.dart
│ │ ├── toast.dart
│ │ └── widgets.dart
├── global.dart
├── main.dart
└── pages
│ ├── application
│ ├── bindings.dart
│ ├── controller.dart
│ ├── index.dart
│ ├── state.dart
│ └── view.dart
│ ├── category
│ ├── bindings.dart
│ ├── controller.dart
│ ├── index.dart
│ ├── state.dart
│ ├── view.dart
│ └── widgets
│ │ ├── news_item.dart
│ │ ├── news_page_list.dart
│ │ └── widgets.dart
│ ├── frame
│ ├── notfound
│ │ ├── bindings.dart
│ │ ├── controller.dart
│ │ ├── index.dart
│ │ ├── state.dart
│ │ ├── view.dart
│ │ └── widgets
│ │ │ ├── helloword.dart
│ │ │ └── widgets.dart
│ ├── sign_in
│ │ ├── bindings.dart
│ │ ├── controller.dart
│ │ ├── index.dart
│ │ ├── state.dart
│ │ └── view.dart
│ ├── sign_up
│ │ ├── bindings.dart
│ │ ├── controller.dart
│ │ ├── index.dart
│ │ ├── state.dart
│ │ └── view.dart
│ └── welcome
│ │ ├── bindings.dart
│ │ ├── controller.dart
│ │ ├── index.dart
│ │ ├── state.dart
│ │ └── view.dart
│ ├── index.txt
│ └── main
│ ├── bindings.dart
│ ├── controller.dart
│ ├── index.dart
│ ├── state.dart
│ ├── view.dart
│ └── widgets
│ ├── ad.dart
│ ├── categories.dart
│ ├── channels.dart
│ ├── news_list.dart
│ ├── newsletter.dart
│ ├── recommend.dart
│ └── widgets.dart
├── linux
├── .gitignore
├── CMakeLists.txt
├── flutter
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
├── main.cc
├── my_application.cc
└── my_application.h
├── macos
├── .gitignore
├── Flutter
│ ├── Flutter-Debug.xcconfig
│ ├── Flutter-Release.xcconfig
│ └── GeneratedPluginRegistrant.swift
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── app_icon_1024.png
│ │ ├── app_icon_128.png
│ │ ├── app_icon_16.png
│ │ ├── app_icon_256.png
│ │ ├── app_icon_32.png
│ │ ├── app_icon_512.png
│ │ └── app_icon_64.png
│ ├── Base.lproj
│ └── MainMenu.xib
│ ├── Configs
│ ├── AppInfo.xcconfig
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── Warnings.xcconfig
│ ├── DebugProfile.entitlements
│ ├── Info.plist
│ ├── MainFlutterWindow.swift
│ └── Release.entitlements
├── pubspec.lock
├── pubspec.yaml
├── test
└── widget_test.dart
├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ └── Icon-512.png
├── index.html
└── manifest.json
└── windows
├── .gitignore
├── CMakeLists.txt
├── flutter
├── CMakeLists.txt
├── generated_plugin_registrant.cc
├── generated_plugin_registrant.h
└── generated_plugins.cmake
└── runner
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── resources
└── app_icon.ico
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
/.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 | ios/build
--------------------------------------------------------------------------------
/.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: d97f41caed971d4668ffe56699367ec3978db8f6
8 | channel: dev
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/README/2021-07-24-13-54-17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/README/2021-07-24-13-54-17.png
--------------------------------------------------------------------------------
/README/2021-07-24-14-47-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/README/2021-07-24-14-47-42.png
--------------------------------------------------------------------------------
/README/2021-09-18-22-26-23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/README/2021-09-18-22-26-23.png
--------------------------------------------------------------------------------
/README/2021-09-18-22-52-54.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/README/2021-09-18-22-52-54.png
--------------------------------------------------------------------------------
/README/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/README/architecture.png
--------------------------------------------------------------------------------
/README/catalog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/README/catalog.png
--------------------------------------------------------------------------------
/README/one-way-data-flow-04fe46332c1ccb3497ecb04b94e55b97.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/README/one-way-data-flow-04fe46332c1ccb3497ecb04b94e55b97.png
--------------------------------------------------------------------------------
/README/scheme.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/README/scheme.gif
--------------------------------------------------------------------------------
/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 30
30 |
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_1_8
33 | targetCompatibility JavaVersion.VERSION_1_8
34 | }
35 |
36 | kotlinOptions {
37 | jvmTarget = '1.8'
38 | }
39 |
40 | sourceSets {
41 | main.java.srcDirs += 'src/main/kotlin'
42 | }
43 |
44 | defaultConfig {
45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
46 | applicationId "com.example.flutter_ducafecat_news_getx"
47 | minSdkVersion 16
48 | targetSdkVersion 30
49 | versionCode flutterVersionCode.toInteger()
50 | versionName flutterVersionName
51 | }
52 |
53 | buildTypes {
54 | release {
55 | // TODO: Add your own signing config for the release build.
56 | // Signing with the debug keys for now, so `flutter run --release` works.
57 | signingConfig signingConfigs.debug
58 | }
59 | }
60 | }
61 |
62 | flutter {
63 | source '../..'
64 | }
65 |
66 | dependencies {
67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
68 | }
69 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
13 |
17 |
21 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
43 |
45 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/flutter_ducafecat_news_getx/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.flutter_ducafecat_news_getx
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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
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 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/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/fonts/Avenir-Book.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/fonts/Avenir-Book.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/fonts/Montserrat-Medium.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/fonts/Montserrat-SemiBold.ttf
--------------------------------------------------------------------------------
/assets/fonts/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/fonts/iconfont.ttf
--------------------------------------------------------------------------------
/assets/icons/logo-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/icons/logo-1024.png
--------------------------------------------------------------------------------
/assets/images/2.0x/account_header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/account_header.png
--------------------------------------------------------------------------------
/assets/images/2.0x/channel-bbc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/channel-bbc.png
--------------------------------------------------------------------------------
/assets/images/2.0x/channel-bloomberg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/channel-bloomberg.png
--------------------------------------------------------------------------------
/assets/images/2.0x/channel-cnn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/channel-cnn.png
--------------------------------------------------------------------------------
/assets/images/2.0x/channel-fox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/channel-fox.png
--------------------------------------------------------------------------------
/assets/images/2.0x/channel-nbc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/channel-nbc.png
--------------------------------------------------------------------------------
/assets/images/2.0x/channel-rt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/channel-rt.png
--------------------------------------------------------------------------------
/assets/images/2.0x/feature-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/feature-1.png
--------------------------------------------------------------------------------
/assets/images/2.0x/feature-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/feature-2.png
--------------------------------------------------------------------------------
/assets/images/2.0x/feature-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/feature-3.png
--------------------------------------------------------------------------------
/assets/images/2.0x/icons-facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/icons-facebook.png
--------------------------------------------------------------------------------
/assets/images/2.0x/icons-google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/icons-google.png
--------------------------------------------------------------------------------
/assets/images/2.0x/icons-twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/icons-twitter.png
--------------------------------------------------------------------------------
/assets/images/2.0x/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/2.0x/logo.png
--------------------------------------------------------------------------------
/assets/images/3.0x/account_header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/account_header.png
--------------------------------------------------------------------------------
/assets/images/3.0x/channel-bbc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/channel-bbc.png
--------------------------------------------------------------------------------
/assets/images/3.0x/channel-bloomberg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/channel-bloomberg.png
--------------------------------------------------------------------------------
/assets/images/3.0x/channel-cnn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/channel-cnn.png
--------------------------------------------------------------------------------
/assets/images/3.0x/channel-fox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/channel-fox.png
--------------------------------------------------------------------------------
/assets/images/3.0x/channel-nbc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/channel-nbc.png
--------------------------------------------------------------------------------
/assets/images/3.0x/channel-rt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/channel-rt.png
--------------------------------------------------------------------------------
/assets/images/3.0x/feature-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/feature-1.png
--------------------------------------------------------------------------------
/assets/images/3.0x/feature-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/feature-2.png
--------------------------------------------------------------------------------
/assets/images/3.0x/feature-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/feature-3.png
--------------------------------------------------------------------------------
/assets/images/3.0x/icons-facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/icons-facebook.png
--------------------------------------------------------------------------------
/assets/images/3.0x/icons-google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/icons-google.png
--------------------------------------------------------------------------------
/assets/images/3.0x/icons-twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/icons-twitter.png
--------------------------------------------------------------------------------
/assets/images/3.0x/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/3.0x/logo.png
--------------------------------------------------------------------------------
/assets/images/account_header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/account_header.png
--------------------------------------------------------------------------------
/assets/images/channel-bbc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/channel-bbc.png
--------------------------------------------------------------------------------
/assets/images/channel-bloomberg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/channel-bloomberg.png
--------------------------------------------------------------------------------
/assets/images/channel-cnn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/channel-cnn.png
--------------------------------------------------------------------------------
/assets/images/channel-fox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/channel-fox.png
--------------------------------------------------------------------------------
/assets/images/channel-nbc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/channel-nbc.png
--------------------------------------------------------------------------------
/assets/images/channel-rt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/channel-rt.png
--------------------------------------------------------------------------------
/assets/images/feature-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/feature-1.png
--------------------------------------------------------------------------------
/assets/images/feature-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/feature-2.png
--------------------------------------------------------------------------------
/assets/images/feature-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/feature-3.png
--------------------------------------------------------------------------------
/assets/images/icons-facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/icons-facebook.png
--------------------------------------------------------------------------------
/assets/images/icons-google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/icons-google.png
--------------------------------------------------------------------------------
/assets/images/icons-twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/icons-twitter.png
--------------------------------------------------------------------------------
/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/assets/images/logo.png
--------------------------------------------------------------------------------
/doc/scheme/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Document
9 |
10 |
11 |
12 | newsgetx://com.tpns.push/notify/category
13 |
14 |
15 |
16 |
17 | newsgetx://com.tpns.push/notify/message/123
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/doc/目录结构.mindnode/QuickLook/Preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/doc/目录结构.mindnode/QuickLook/Preview.jpg
--------------------------------------------------------------------------------
/doc/目录结构.mindnode/contents.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/doc/目录结构.mindnode/contents.xml
--------------------------------------------------------------------------------
/doc/目录结构.mindnode/style.mindnodestyle/metadata.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | author
6 | MindNode
7 | id
8 | 514DD5D6-7C79-481B-8CB1-A08FA9F5D3DF
9 | title
10 | Tropical
11 | version
12 | 3
13 |
14 |
15 |
--------------------------------------------------------------------------------
/doc/目录结构.mindnode/viewState.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/doc/目录结构.mindnode/viewState.plist
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/ephemeral/
22 | Flutter/app.flx
23 | Flutter/app.zip
24 | Flutter/flutter_assets/
25 | Flutter/flutter_export_environment.sh
26 | ServiceDefinitions.json
27 | Runner/GeneratedPluginRegistrant.*
28 | build/
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/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - device_info (0.0.1):
3 | - Flutter
4 | - Flutter (1.0.0)
5 | - fluttertoast (0.0.2):
6 | - Flutter
7 | - Toast
8 | - FMDB (2.7.5):
9 | - FMDB/standard (= 2.7.5)
10 | - FMDB/standard (2.7.5)
11 | - package_info (0.0.1):
12 | - Flutter
13 | - path_provider_ios (0.0.1):
14 | - Flutter
15 | - "permission_handler (5.1.0+2)":
16 | - Flutter
17 | - share (0.0.1):
18 | - Flutter
19 | - shared_preferences_ios (0.0.1):
20 | - Flutter
21 | - sqflite (0.0.2):
22 | - Flutter
23 | - FMDB (>= 2.7.5)
24 | - Toast (4.0.0)
25 | - uni_links (0.0.1):
26 | - Flutter
27 | - webview_flutter_wkwebview (0.0.1):
28 | - Flutter
29 |
30 | DEPENDENCIES:
31 | - device_info (from `.symlinks/plugins/device_info/ios`)
32 | - Flutter (from `Flutter`)
33 | - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
34 | - package_info (from `.symlinks/plugins/package_info/ios`)
35 | - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
36 | - permission_handler (from `.symlinks/plugins/permission_handler/ios`)
37 | - share (from `.symlinks/plugins/share/ios`)
38 | - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
39 | - sqflite (from `.symlinks/plugins/sqflite/ios`)
40 | - uni_links (from `.symlinks/plugins/uni_links/ios`)
41 | - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`)
42 |
43 | SPEC REPOS:
44 | trunk:
45 | - FMDB
46 | - Toast
47 |
48 | EXTERNAL SOURCES:
49 | device_info:
50 | :path: ".symlinks/plugins/device_info/ios"
51 | Flutter:
52 | :path: Flutter
53 | fluttertoast:
54 | :path: ".symlinks/plugins/fluttertoast/ios"
55 | package_info:
56 | :path: ".symlinks/plugins/package_info/ios"
57 | path_provider_ios:
58 | :path: ".symlinks/plugins/path_provider_ios/ios"
59 | permission_handler:
60 | :path: ".symlinks/plugins/permission_handler/ios"
61 | share:
62 | :path: ".symlinks/plugins/share/ios"
63 | shared_preferences_ios:
64 | :path: ".symlinks/plugins/shared_preferences_ios/ios"
65 | sqflite:
66 | :path: ".symlinks/plugins/sqflite/ios"
67 | uni_links:
68 | :path: ".symlinks/plugins/uni_links/ios"
69 | webview_flutter_wkwebview:
70 | :path: ".symlinks/plugins/webview_flutter_wkwebview/ios"
71 |
72 | SPEC CHECKSUMS:
73 | device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
74 | Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
75 | fluttertoast: 6122fa75143e992b1d3470f61000f591a798cc58
76 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
77 | package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
78 | path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
79 | permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0
80 | share: 0b2c3e82132f5888bccca3351c504d0003b3b410
81 | shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
82 | sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
83 | Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
84 | uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
85 | webview_flutter_wkwebview: 005fbd90c888a42c5690919a1527ecc6649e1162
86 |
87 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
88 |
89 | COCOAPODS: 1.11.2
90 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/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/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | flutter_ducafecat_news_getx
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleURLTypes
22 |
23 |
24 | CFBundleTypeRole
25 | Viewer
26 | CFBundleURLSchemes
27 |
28 | newsgetx
29 |
30 |
31 |
32 | CFBundleVersion
33 | $(FLUTTER_BUILD_NUMBER)
34 | LSRequiresIPhoneOS
35 |
36 | UILaunchStoryboardName
37 | LaunchScreen
38 | UIMainStoryboardFile
39 | Main
40 | UISupportedInterfaceOrientations
41 |
42 | UIInterfaceOrientationPortrait
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 | UISupportedInterfaceOrientations~ipad
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationPortraitUpsideDown
50 | UIInterfaceOrientationLandscapeLeft
51 | UIInterfaceOrientationLandscapeRight
52 |
53 | UIViewControllerBasedStatusBarAppearance
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/lib/common/apis/apis.dart:
--------------------------------------------------------------------------------
1 | library apis;
2 |
3 | export 'user.dart';
4 | export 'news.dart';
5 |
--------------------------------------------------------------------------------
/lib/common/apis/news.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_ducafecat_news_getx/common/entities/entities.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/utils/utils.dart';
3 | import 'package:flutter_ducafecat_news_getx/common/values/values.dart';
4 |
5 | /// 新闻
6 | class NewsAPI {
7 | /// 翻页
8 | /// refresh 是否刷新
9 | static Future newsPageList({
10 | NewsPageListRequestEntity? params,
11 | bool refresh = false,
12 | bool cacheDisk = false,
13 | }) async {
14 | var response = await HttpUtil().get(
15 | '/news',
16 | queryParameters: params?.toJson(),
17 | refresh: refresh,
18 | cacheDisk: cacheDisk,
19 | cacheKey: STORAGE_INDEX_NEWS_CACHE_KEY,
20 | );
21 | return NewsPageListResponseEntity.fromJson(response);
22 | }
23 |
24 | /// 推荐
25 | static Future newsRecommend({
26 | NewsRecommendRequestEntity? params,
27 | bool refresh = false,
28 | bool cacheDisk = false,
29 | }) async {
30 | var response = await HttpUtil().get(
31 | '/news/recommend',
32 | queryParameters: params?.toJson(),
33 | refresh: refresh,
34 | cacheDisk: cacheDisk,
35 | );
36 | return NewsItem.fromJson(response);
37 | }
38 |
39 | /// 分类
40 | static Future> categories({
41 | bool cacheDisk = false,
42 | }) async {
43 | var response = await HttpUtil().get(
44 | '/categories',
45 | cacheDisk: cacheDisk,
46 | );
47 | return response
48 | .map(
49 | (item) => CategoryResponseEntity.fromJson(item))
50 | .toList();
51 | }
52 |
53 | /// 频道
54 | static Future> channels({
55 | bool cacheDisk = false,
56 | }) async {
57 | var response = await HttpUtil().get(
58 | '/channels',
59 | cacheDisk: cacheDisk,
60 | );
61 | return response
62 | .map(
63 | (item) => ChannelResponseEntity.fromJson(item))
64 | .toList();
65 | }
66 |
67 | /// 标签列表
68 | static Future> tags({
69 | TagRequestEntity? params,
70 | bool cacheDisk = false,
71 | }) async {
72 | var response = await HttpUtil().get(
73 | '/tags',
74 | queryParameters: params?.toJson(),
75 | cacheDisk: cacheDisk,
76 | );
77 | return response
78 | .map((item) => TagResponseEntity.fromJson(item))
79 | .toList();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/common/apis/user.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_ducafecat_news_getx/common/entities/entities.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/utils/utils.dart';
3 |
4 | /// 用户
5 | class UserAPI {
6 | /// 登录
7 | static Future login({
8 | UserLoginRequestEntity? params,
9 | }) async {
10 | var response = await HttpUtil().post(
11 | '/user/login',
12 | data: params?.toJson(),
13 | );
14 | return UserLoginResponseEntity.fromJson(response);
15 | }
16 |
17 | /// 注册
18 | static Future register({
19 | UserRegisterRequestEntity? params,
20 | }) async {
21 | var response = await HttpUtil().post(
22 | '/user/register',
23 | data: params?.toJson(),
24 | );
25 | return UserRegisterRequestEntity.fromJson(response);
26 | }
27 |
28 | /// Profile
29 | static Future profile() async {
30 | var response = await HttpUtil().post(
31 | '/user/profile',
32 | );
33 | return UserLoginResponseEntity.fromJson(response);
34 | }
35 |
36 | /// Logout
37 | static Future logout() async {
38 | return await HttpUtil().post(
39 | '/user/logout',
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/common/entities/app.dart:
--------------------------------------------------------------------------------
1 | /*
2 | app 升级
3 | */
4 |
5 | class AppUpdateRequestEntity {
6 | String? device;
7 | String? channel;
8 | String? architecture;
9 | String? model;
10 |
11 | AppUpdateRequestEntity({
12 | this.device,
13 | this.channel,
14 | this.architecture,
15 | this.model,
16 | });
17 |
18 | factory AppUpdateRequestEntity.fromJson(Map json) =>
19 | AppUpdateRequestEntity(
20 | device: json["device"],
21 | channel: json["channel"],
22 | architecture: json["architecture"],
23 | model: json["model"],
24 | );
25 |
26 | Map toJson() => {
27 | "device": device,
28 | "channel": channel,
29 | "architecture": architecture,
30 | "model": model,
31 | };
32 | }
33 |
34 | class AppUpdateResponseEntity {
35 | String? shopUrl;
36 | String? fileUrl;
37 | String? latestVersion;
38 | String? latestDescription;
39 |
40 | AppUpdateResponseEntity({
41 | this.shopUrl,
42 | this.fileUrl,
43 | this.latestVersion,
44 | this.latestDescription,
45 | });
46 |
47 | factory AppUpdateResponseEntity.fromJson(Map json) =>
48 | AppUpdateResponseEntity(
49 | shopUrl: json["shopUrl"],
50 | fileUrl: json["fileUrl"],
51 | latestVersion: json["latestVersion"],
52 | latestDescription: json["latestDescription"],
53 | );
54 |
55 | Map toJson() => {
56 | "shopUrl": shopUrl,
57 | "fileUrl": fileUrl,
58 | "latestVersion": latestVersion,
59 | "latestDescription": latestDescription,
60 | };
61 | }
62 |
--------------------------------------------------------------------------------
/lib/common/entities/categories.dart:
--------------------------------------------------------------------------------
1 | /// 新闻分类 response
2 | class CategoryResponseEntity {
3 | String code;
4 | String title;
5 |
6 | CategoryResponseEntity({
7 | required this.code,
8 | required this.title,
9 | });
10 |
11 | factory CategoryResponseEntity.fromJson(Map json) =>
12 | CategoryResponseEntity(
13 | code: json["code"],
14 | title: json["title"],
15 | );
16 |
17 | Map toJson() => {
18 | "code": code,
19 | "title": title,
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/lib/common/entities/channels.dart:
--------------------------------------------------------------------------------
1 | /// 频道列表 response
2 | class ChannelResponseEntity {
3 | String code;
4 | String title;
5 |
6 | ChannelResponseEntity({
7 | required this.code,
8 | required this.title,
9 | });
10 |
11 | factory ChannelResponseEntity.fromJson(Map json) =>
12 | ChannelResponseEntity(
13 | code: json["code"],
14 | title: json["title"],
15 | );
16 |
17 | Map toJson() => {
18 | "code": code,
19 | "title": title,
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/lib/common/entities/entities.dart:
--------------------------------------------------------------------------------
1 | library entities;
2 |
3 | export 'user.dart';
4 | export 'news.dart';
5 | export 'categories.dart';
6 | export 'channels.dart';
7 | export 'tags.dart';
8 | export 'app.dart';
9 |
--------------------------------------------------------------------------------
/lib/common/entities/news.dart:
--------------------------------------------------------------------------------
1 | /// 新闻分页 request
2 | class NewsPageListRequestEntity {
3 | String? categoryCode;
4 | String? channelCode;
5 | String? tag;
6 | String? keyword;
7 | int? pageNum;
8 | int? pageSize;
9 |
10 | NewsPageListRequestEntity({
11 | this.categoryCode,
12 | this.channelCode,
13 | this.tag,
14 | this.keyword,
15 | this.pageNum,
16 | this.pageSize,
17 | });
18 |
19 | Map toJson() => {
20 | "categoryCode": categoryCode,
21 | "channelCode": channelCode,
22 | "tag": tag,
23 | "keyword": keyword,
24 | "pageNum": pageNum,
25 | "pageSize": pageSize,
26 | };
27 | }
28 |
29 | /// 新闻分页 response
30 | class NewsPageListResponseEntity {
31 | int? counts;
32 | int? pagesize;
33 | int? pages;
34 | int? page;
35 | List? items;
36 |
37 | NewsPageListResponseEntity({
38 | this.counts,
39 | this.pagesize,
40 | this.pages,
41 | this.page,
42 | this.items,
43 | });
44 |
45 | factory NewsPageListResponseEntity.fromJson(Map json) =>
46 | NewsPageListResponseEntity(
47 | counts: json["counts"],
48 | pagesize: json["pagesize"],
49 | pages: json["pages"],
50 | page: json["page"],
51 | items: json["items"] == null
52 | ? []
53 | : List.from(
54 | json["items"].map((x) => NewsItem.fromJson(x))),
55 | );
56 |
57 | Map toJson() => {
58 | "counts": counts ?? 0,
59 | "pagesize": pagesize ?? 0,
60 | "pages": pages ?? 0,
61 | "page": page ?? 0,
62 | "items": items == null
63 | ? []
64 | : List.from(items!.map((x) => x.toJson())),
65 | };
66 | }
67 |
68 | class NewsItem {
69 | String? id;
70 | String? title;
71 | String? category;
72 | String? thumbnail;
73 | String? author;
74 | DateTime? addtime;
75 | String? url;
76 |
77 | NewsItem({
78 | this.id,
79 | this.title,
80 | this.category,
81 | this.thumbnail,
82 | this.author,
83 | this.addtime,
84 | this.url,
85 | });
86 |
87 | factory NewsItem.fromJson(Map json) => NewsItem(
88 | id: json["id"],
89 | title: json["title"],
90 | category: json["category"],
91 | thumbnail: json["thumbnail"],
92 | author: json["author"],
93 | addtime: DateTime.parse(json["addtime"]),
94 | url: json["url"],
95 | );
96 |
97 | Map toJson() => {
98 | "id": id,
99 | "title": title,
100 | "category": category,
101 | "thumbnail": thumbnail,
102 | "author": author,
103 | "addtime": addtime?.toIso8601String(),
104 | "url": url,
105 | };
106 | }
107 |
108 | /// 新闻推荐 request
109 | class NewsRecommendRequestEntity {
110 | String? categoryCode;
111 | String? channelCode;
112 | String? tag;
113 | String? keyword;
114 |
115 | NewsRecommendRequestEntity({
116 | this.categoryCode,
117 | this.channelCode,
118 | this.tag,
119 | this.keyword,
120 | });
121 |
122 | Map toJson() => {
123 | "categoryCode": categoryCode,
124 | "channelCode": channelCode,
125 | "tag": tag,
126 | "keyword": keyword,
127 | };
128 | }
129 |
--------------------------------------------------------------------------------
/lib/common/entities/tags.dart:
--------------------------------------------------------------------------------
1 | /// 标签列表 Request
2 | class TagRequestEntity {
3 | String categoryCode;
4 | String channelCode;
5 | String tag;
6 | String keyword;
7 | String newsID;
8 |
9 | TagRequestEntity({
10 | required this.categoryCode,
11 | required this.channelCode,
12 | required this.tag,
13 | required this.keyword,
14 | required this.newsID,
15 | });
16 |
17 | Map toJson() => {
18 | "categoryCode": categoryCode,
19 | "channelCode": channelCode,
20 | "tag": tag,
21 | "keyword": keyword,
22 | "newsID": newsID,
23 | };
24 | }
25 |
26 | /// 标签列表 Response
27 | class TagResponseEntity {
28 | String? tag;
29 |
30 | TagResponseEntity({
31 | this.tag,
32 | });
33 |
34 | factory TagResponseEntity.fromJson(Map json) =>
35 | TagResponseEntity(
36 | tag: json["tag"],
37 | );
38 |
39 | Map toJson() => {
40 | "tag": tag,
41 | };
42 | }
43 |
--------------------------------------------------------------------------------
/lib/common/entities/user.dart:
--------------------------------------------------------------------------------
1 | // 注册请求
2 | class UserRegisterRequestEntity {
3 | String email;
4 | String password;
5 |
6 | UserRegisterRequestEntity({
7 | required this.email,
8 | required this.password,
9 | });
10 |
11 | factory UserRegisterRequestEntity.fromJson(Map json) =>
12 | UserRegisterRequestEntity(
13 | email: json["email"],
14 | password: json["password"],
15 | );
16 |
17 | Map toJson() => {
18 | "email": email,
19 | "password": password,
20 | };
21 | }
22 |
23 | // 登录请求
24 | class UserLoginRequestEntity {
25 | String email;
26 | String password;
27 |
28 | UserLoginRequestEntity({
29 | required this.email,
30 | required this.password,
31 | });
32 |
33 | factory UserLoginRequestEntity.fromJson(Map json) =>
34 | UserLoginRequestEntity(
35 | email: json["email"],
36 | password: json["password"],
37 | );
38 |
39 | Map toJson() => {
40 | "email": email,
41 | "password": password,
42 | };
43 | }
44 |
45 | // 登录返回
46 | class UserLoginResponseEntity {
47 | String? accessToken;
48 | String? displayName;
49 | List? channels;
50 |
51 | UserLoginResponseEntity({
52 | this.accessToken,
53 | this.displayName,
54 | this.channels,
55 | });
56 |
57 | factory UserLoginResponseEntity.fromJson(Map json) =>
58 | UserLoginResponseEntity(
59 | accessToken: json["access_token"],
60 | displayName: json["display_name"],
61 | channels: List.from(json["channels"].map((x) => x)),
62 | );
63 |
64 | Map toJson() => {
65 | "access_token": accessToken,
66 | "display_name": displayName,
67 | "channels":
68 | channels == null ? [] : List.from(channels!.map((x) => x)),
69 | };
70 | }
71 |
--------------------------------------------------------------------------------
/lib/common/langs/en_US.dart:
--------------------------------------------------------------------------------
1 | const Map en_US = {
2 | 'title': 'This is Title!',
3 | 'login': 'logged in as @name with email @email',
4 | };
5 |
--------------------------------------------------------------------------------
/lib/common/langs/translation_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'package:get/get.dart';
4 |
5 | import 'en_US.dart';
6 | import 'zh_Hans.dart';
7 | import 'zh_HK.dart';
8 |
9 | /*
10 |
11 | https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html
12 | https://www.ibabbleon.com/iOS-Language-Codes-ISO-639.html
13 |
14 | */
15 |
16 | class TranslationService extends Translations {
17 | static Locale? get locale => Get.deviceLocale;
18 | static final fallbackLocale = Locale('en', 'US');
19 | @override
20 | Map> get keys => {
21 | 'en_US': en_US,
22 | 'zh_Hans': zh_Hans,
23 | 'zh_HK': zh_HK,
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/lib/common/langs/zh_HK.dart:
--------------------------------------------------------------------------------
1 | const Map zh_HK = {
2 | 'title': '這是標題',
3 | 'login': '登錄用戶 @name,郵箱賬號 @email',
4 | };
5 |
--------------------------------------------------------------------------------
/lib/common/langs/zh_Hans.dart:
--------------------------------------------------------------------------------
1 | const Map zh_Hans = {
2 | 'title': '这是标题',
3 | 'login': '登录用户 @name,邮箱账号 @email',
4 | };
5 |
--------------------------------------------------------------------------------
/lib/common/middlewares/middlewares.dart:
--------------------------------------------------------------------------------
1 | library middlewares;
2 |
3 | export './router_auth.dart';
4 | export './router_welcome.dart';
5 |
--------------------------------------------------------------------------------
/lib/common/middlewares/router_auth.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/routers/routes.dart';
3 | import 'package:flutter_ducafecat_news_getx/common/store/store.dart';
4 |
5 | import 'package:get/get.dart';
6 |
7 | /// 检查是否登录
8 | class RouteAuthMiddleware extends GetMiddleware {
9 | // priority 数字小优先级高
10 | @override
11 | int? priority = 0;
12 |
13 | RouteAuthMiddleware({required this.priority});
14 |
15 | @override
16 | RouteSettings? redirect(String? route) {
17 | if (UserStore.to.isLogin ||
18 | route == AppRoutes.SIGN_IN ||
19 | route == AppRoutes.SIGN_UP ||
20 | route == AppRoutes.INITIAL) {
21 | return null;
22 | } else {
23 | Future.delayed(
24 | Duration(seconds: 1), () => Get.snackbar("提示", "登录过期,请重新登录"));
25 | return RouteSettings(name: AppRoutes.SIGN_IN);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/common/middlewares/router_welcome.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/routers/routes.dart';
3 | import 'package:flutter_ducafecat_news_getx/common/store/store.dart';
4 |
5 | import 'package:get/get.dart';
6 |
7 | /// 第一次欢迎页面
8 | class RouteWelcomeMiddleware extends GetMiddleware {
9 | // priority 数字小优先级高
10 | @override
11 | int? priority = 0;
12 |
13 | RouteWelcomeMiddleware({required this.priority});
14 |
15 | @override
16 | RouteSettings? redirect(String? route) {
17 | if (ConfigStore.to.isFirstOpen == true) {
18 | return null;
19 | } else if (UserStore.to.isLogin == true) {
20 | return RouteSettings(name: AppRoutes.Application);
21 | } else {
22 | return RouteSettings(name: AppRoutes.SIGN_IN);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/common/routers/names.dart:
--------------------------------------------------------------------------------
1 | class AppRoutes {
2 | static const INITIAL = '/';
3 | static const SIGN_IN = '/sign_in';
4 | static const SIGN_UP = '/sign_up';
5 | static const NotFound = '/not_found';
6 |
7 | static const Application = '/application';
8 | static const Category = '/category';
9 | }
10 |
--------------------------------------------------------------------------------
/lib/common/routers/names.txt:
--------------------------------------------------------------------------------
1 | static const application = '/application';
2 | static const category = '/category';
3 | static const frameNotfound = '/frame_notfound';
4 | static const frameSignIn = '/frame_sign_in';
5 | static const frameSignUp = '/frame_sign_up';
6 | static const frameWelcome = '/frame_welcome';
7 | static const main = '/main';
8 |
--------------------------------------------------------------------------------
/lib/common/routers/observers.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'routes.dart';
3 |
4 | class RouteObservers> extends RouteObserver {
5 | @override
6 | void didPush(Route route, Route? previousRoute) {
7 | super.didPush(route, previousRoute);
8 | var name = route.settings.name ?? '';
9 | if (name.isNotEmpty) AppPages.history.add(name);
10 | print('didPush');
11 | print(AppPages.history);
12 | }
13 |
14 | @override
15 | void didPop(Route route, Route? previousRoute) {
16 | super.didPop(route, previousRoute);
17 | AppPages.history.remove(route.settings.name);
18 | print('didPop');
19 | print(AppPages.history);
20 | }
21 |
22 | @override
23 | void didReplace({Route? newRoute, Route? oldRoute}) {
24 | super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
25 | if (newRoute != null) {
26 | var index = AppPages.history.indexWhere((element) {
27 | return element == oldRoute?.settings.name;
28 | });
29 | var name = newRoute.settings.name ?? '';
30 | if (name.isNotEmpty) {
31 | if (index > 0) {
32 | AppPages.history[index] = name;
33 | } else {
34 | AppPages.history.add(name);
35 | }
36 | }
37 | }
38 | print('didReplace');
39 | print(AppPages.history);
40 | }
41 |
42 | @override
43 | void didRemove(Route route, Route? previousRoute) {
44 | super.didRemove(route, previousRoute);
45 | AppPages.history.remove(route.settings.name);
46 | print('didRemove');
47 | print(AppPages.history);
48 | }
49 |
50 | @override
51 | void didStartUserGesture(
52 | Route route, Route? previousRoute) {
53 | super.didStartUserGesture(route, previousRoute);
54 | }
55 |
56 | @override
57 | void didStopUserGesture() {
58 | super.didStopUserGesture();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/common/routers/pages.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/middlewares/middlewares.dart';
3 | import 'package:flutter_ducafecat_news_getx/pages/application/index.dart';
4 | import 'package:flutter_ducafecat_news_getx/pages/category/index.dart';
5 | import 'package:flutter_ducafecat_news_getx/pages/frame/sign_in/index.dart';
6 | import 'package:flutter_ducafecat_news_getx/pages/frame/sign_up/index.dart';
7 | import 'package:flutter_ducafecat_news_getx/pages/frame/welcome/index.dart';
8 | import 'package:get/get.dart';
9 |
10 | import 'routes.dart';
11 |
12 | class AppPages {
13 | static const INITIAL = AppRoutes.INITIAL;
14 | static final RouteObserver observer = RouteObservers();
15 | static List history = [];
16 |
17 | static final List routes = [
18 | // 免登陆
19 | GetPage(
20 | name: AppRoutes.INITIAL,
21 | page: () => WelcomePage(),
22 | binding: WelcomeBinding(),
23 | middlewares: [
24 | RouteWelcomeMiddleware(priority: 1),
25 | ],
26 | ),
27 | GetPage(
28 | name: AppRoutes.SIGN_IN,
29 | page: () => SignInPage(),
30 | binding: SignInBinding(),
31 | ),
32 | GetPage(
33 | name: AppRoutes.SIGN_UP,
34 | page: () => SignUpPage(),
35 | binding: SignUpBinding(),
36 | ),
37 |
38 | // 需要登录
39 | GetPage(
40 | name: AppRoutes.Application,
41 | page: () => ApplicationPage(),
42 | binding: ApplicationBinding(),
43 | middlewares: [
44 | RouteAuthMiddleware(priority: 1),
45 | ],
46 | ),
47 |
48 | // 分类列表
49 | GetPage(
50 | name: AppRoutes.Category,
51 | page: () => CategoryPage(),
52 | binding: CategoryBinding(),
53 | ),
54 | ];
55 |
56 | // static final unknownRoute = GetPage(
57 | // name: AppRoutes.NotFound,
58 | // page: () => NotfoundView(),
59 | // );
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/lib/common/routers/pages.txt:
--------------------------------------------------------------------------------
1 |
2 | GetPage(
3 | name: RouteNames.application,
4 | page: () => const ApplicationPage(),
5 | ),
6 | GetPage(
7 | name: RouteNames.category,
8 | page: () => const CategoryPage(),
9 | ),
10 | GetPage(
11 | name: RouteNames.frameNotfound,
12 | page: () => const NotfoundPage(),
13 | ),
14 | GetPage(
15 | name: RouteNames.frameSignIn,
16 | page: () => const SignInPage(),
17 | ),
18 | GetPage(
19 | name: RouteNames.frameSignUp,
20 | page: () => const SignUpPage(),
21 | ),
22 | GetPage(
23 | name: RouteNames.frameWelcome,
24 | page: () => const WelcomePage(),
25 | ),
26 | GetPage(
27 | name: RouteNames.main,
28 | page: () => const MainPage(),
29 | ),
--------------------------------------------------------------------------------
/lib/common/routers/routes.dart:
--------------------------------------------------------------------------------
1 | library routes;
2 |
3 | export 'names.dart';
4 | export 'pages.dart';
5 | export './observers.dart';
6 |
--------------------------------------------------------------------------------
/lib/common/services/services.dart:
--------------------------------------------------------------------------------
1 | library services;
2 |
3 | export './storage.dart';
4 |
--------------------------------------------------------------------------------
/lib/common/services/storage.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 | import 'package:shared_preferences/shared_preferences.dart';
3 |
4 | class StorageService extends GetxService {
5 | static StorageService get to => Get.find();
6 | late final SharedPreferences _prefs;
7 |
8 | Future init() async {
9 | _prefs = await SharedPreferences.getInstance();
10 | return this;
11 | }
12 |
13 | Future setString(String key, String value) async {
14 | return await _prefs.setString(key, value);
15 | }
16 |
17 | Future setBool(String key, bool value) async {
18 | return await _prefs.setBool(key, value);
19 | }
20 |
21 | Future setList(String key, List value) async {
22 | return await _prefs.setStringList(key, value);
23 | }
24 |
25 | String getString(String key) {
26 | return _prefs.getString(key) ?? '';
27 | }
28 |
29 | bool getBool(String key) {
30 | return _prefs.getBool(key) ?? false;
31 | }
32 |
33 | List getList(String key) {
34 | return _prefs.getStringList(key) ?? [];
35 | }
36 |
37 | Future remove(String key) async {
38 | return await _prefs.remove(key);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/common/store/config.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/services/services.dart';
3 | import 'package:flutter_ducafecat_news_getx/common/values/values.dart';
4 | import 'package:get/get.dart';
5 | import 'package:package_info/package_info.dart';
6 |
7 | class ConfigStore extends GetxController {
8 | static ConfigStore get to => Get.find();
9 |
10 | bool isFirstOpen = false;
11 | PackageInfo? _platform;
12 | String get version => _platform?.version ?? '-';
13 | bool get isRelease => bool.fromEnvironment("dart.vm.product");
14 | Locale locale = Locale('en', 'US');
15 | List languages = [
16 | Locale('en', 'US'),
17 | Locale('zh', 'CN'),
18 | ];
19 |
20 | @override
21 | void onInit() {
22 | super.onInit();
23 | isFirstOpen = StorageService.to.getBool(STORAGE_DEVICE_FIRST_OPEN_KEY);
24 | }
25 |
26 | Future getPlatform() async {
27 | _platform = await PackageInfo.fromPlatform();
28 | }
29 |
30 | // 标记用户已打开APP
31 | Future saveAlreadyOpen() {
32 | return StorageService.to.setBool(STORAGE_DEVICE_FIRST_OPEN_KEY, false);
33 | }
34 |
35 | void onInitLocale() {
36 | var langCode = StorageService.to.getString(STORAGE_LANGUAGE_CODE);
37 | if (langCode.isEmpty) return;
38 | var index = languages.indexWhere((element) {
39 | return element.languageCode == langCode;
40 | });
41 | if (index < 0) return;
42 | locale = languages[index];
43 | }
44 |
45 | void onLocaleUpdate(Locale value) {
46 | locale = value;
47 | Get.updateLocale(value);
48 | StorageService.to.setString(STORAGE_LANGUAGE_CODE, value.languageCode);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/common/store/store.dart:
--------------------------------------------------------------------------------
1 | library store;
2 |
3 | export './user.dart';
4 | export './config.dart';
5 |
--------------------------------------------------------------------------------
/lib/common/store/user.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:flutter_ducafecat_news_getx/common/apis/apis.dart';
4 | import 'package:flutter_ducafecat_news_getx/common/entities/entities.dart';
5 | import 'package:flutter_ducafecat_news_getx/common/services/services.dart';
6 | import 'package:flutter_ducafecat_news_getx/common/values/values.dart';
7 | import 'package:get/get.dart';
8 |
9 | class UserStore extends GetxController {
10 | static UserStore get to => Get.find();
11 |
12 | // 是否登录
13 | final _isLogin = false.obs;
14 | // 令牌 token
15 | String token = '';
16 | // 用户 profile
17 | final _profile = UserLoginResponseEntity().obs;
18 |
19 | bool get isLogin => _isLogin.value;
20 | UserLoginResponseEntity get profile => _profile.value;
21 | bool get hasToken => token.isNotEmpty;
22 |
23 | @override
24 | void onInit() {
25 | super.onInit();
26 | token = StorageService.to.getString(STORAGE_USER_TOKEN_KEY);
27 | var profileOffline = StorageService.to.getString(STORAGE_USER_PROFILE_KEY);
28 | if (profileOffline.isNotEmpty) {
29 | _profile(UserLoginResponseEntity.fromJson(jsonDecode(profileOffline)));
30 | }
31 | }
32 |
33 | // 保存 token
34 | Future setToken(String value) async {
35 | await StorageService.to.setString(STORAGE_USER_TOKEN_KEY, value);
36 | token = value;
37 | }
38 |
39 | // 获取 profile
40 | Future getProfile() async {
41 | if (token.isEmpty) return;
42 | var result = await UserAPI.profile();
43 | _profile(result);
44 | _isLogin.value = true;
45 | StorageService.to.setString(STORAGE_USER_PROFILE_KEY, jsonEncode(result));
46 | }
47 |
48 | // 保存 profile
49 | Future saveProfile(UserLoginResponseEntity profile) async {
50 | _isLogin.value = true;
51 | StorageService.to.setString(STORAGE_USER_PROFILE_KEY, jsonEncode(profile));
52 | }
53 |
54 | // 注销
55 | Future onLogout() async {
56 | if (_isLogin.value) await UserAPI.logout();
57 | await StorageService.to.remove(STORAGE_USER_TOKEN_KEY);
58 | _isLogin.value = false;
59 | token = '';
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/common/style/color.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AppColor {
4 | /// 页面背景颜色
5 | static const Color scaffoldBackground = Color(0xFFFFFFFF);
6 |
7 | /// 主要背景颜色
8 | // static const Color primaryBackground = Color(0xFF5C78FF);
9 |
10 | /// 主要文本颜色
11 | static const Color primaryText = Color(0xFF333333);
12 |
13 | /// 次要文本颜色
14 | static const Color secondaryText = Color(0xFF74788D);
15 |
16 | /// 高亮颜色
17 | static const Color accentColor = Color(0xFF5C78FF);
18 |
19 | /// 次要颜色
20 | static const Color secondaryColor = Color(0xFFDEE3FF);
21 |
22 | /// 警告颜色
23 | static const Color warnColor = Color(0xFFFFB822);
24 |
25 | /// 边框颜色
26 | static const Color borderColor = Color(0xFFDEE3FF);
27 |
28 | static const Color pinkColor = Color(0xFFF77866);
29 |
30 | static const Color yellowColor = Color(0xFFFFB822);
31 | }
32 |
--------------------------------------------------------------------------------
/lib/common/style/style.dart:
--------------------------------------------------------------------------------
1 | library style;
2 |
3 | export './color.dart';
4 | export './theme.dart';
5 |
--------------------------------------------------------------------------------
/lib/common/style/theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'color.dart';
4 |
5 | class AppTheme {
6 | static const horizontalMargin = 16.0;
7 | static const radius = 10.0;
8 |
9 | static ThemeData light = ThemeData(
10 | brightness: Brightness.light,
11 | scaffoldBackgroundColor: AppColor.scaffoldBackground,
12 | splashColor: Colors.transparent,
13 | highlightColor: Colors.transparent,
14 | primaryColor: AppColor.accentColor,
15 | colorScheme: ColorScheme.fromSwatch().copyWith(
16 | secondary: AppColor.accentColor,
17 | ),
18 | appBarTheme: AppBarTheme(
19 | elevation: 0,
20 | centerTitle: true,
21 | backgroundColor: Colors.white,
22 | iconTheme: IconThemeData(
23 | color: AppColor.primaryText,
24 | ),
25 | titleTextStyle: TextStyle(
26 | color: AppColor.primaryText,
27 | fontSize: 20,
28 | fontWeight: FontWeight.w500,
29 | ),
30 | toolbarTextStyle: TextStyle(
31 | color: AppColor.primaryText,
32 | fontSize: 20,
33 | fontWeight: FontWeight.w500,
34 | ),
35 | ),
36 | bottomNavigationBarTheme: BottomNavigationBarThemeData(
37 | backgroundColor: AppColor.scaffoldBackground,
38 | unselectedLabelStyle: TextStyle(fontSize: 12),
39 | selectedLabelStyle: TextStyle(fontSize: 12),
40 | unselectedItemColor: Color(0xffA2A5B9),
41 | selectedItemColor: AppColor.accentColor,
42 | ),
43 | tabBarTheme: TabBarTheme(
44 | indicatorSize: TabBarIndicatorSize.label,
45 | labelColor: AppColor.accentColor,
46 | unselectedLabelColor: AppColor.secondaryText,
47 | ),
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/lib/common/utils/date.dart:
--------------------------------------------------------------------------------
1 | import 'package:intl/intl.dart';
2 |
3 | /// 格式化时间
4 | String duTimeLineFormat(DateTime dt) {
5 | var now = DateTime.now();
6 | var difference = now.difference(dt);
7 |
8 | // 1天内
9 | if (difference.inHours < 24) {
10 | return "${difference.inHours} hours ago";
11 | }
12 | // 30天内
13 | else if (difference.inDays < 30) {
14 | return "${difference.inDays} days ago";
15 | }
16 | // MM-dd
17 | else if (difference.inDays < 365) {
18 | final dtFormat = new DateFormat('MM-dd');
19 | return dtFormat.format(dt);
20 | }
21 | // yyyy-MM-dd
22 | else {
23 | final dtFormat = new DateFormat('yyyy-MM-dd');
24 | var str = dtFormat.format(dt);
25 | return str;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/common/utils/iconfont.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class Iconfont {
4 | // iconName: share
5 | static const share = IconData(
6 | 0xe60d,
7 | fontFamily: 'Iconfont',
8 | matchTextDirection: true,
9 | );
10 |
11 | // iconName: fav
12 | static const fav = IconData(
13 | 0xe60c,
14 | fontFamily: 'Iconfont',
15 | matchTextDirection: true,
16 | );
17 |
18 | // iconName: social-linkedin
19 | static const sociallinkedin = IconData(
20 | 0xe605,
21 | fontFamily: 'Iconfont',
22 | matchTextDirection: true,
23 | );
24 |
25 | // iconName: social-apple
26 | static const socialapple = IconData(
27 | 0xe606,
28 | fontFamily: 'Iconfont',
29 | matchTextDirection: true,
30 | );
31 |
32 | // iconName: social-octocat
33 | static const socialoctocat = IconData(
34 | 0xe607,
35 | fontFamily: 'Iconfont',
36 | matchTextDirection: true,
37 | );
38 |
39 | // iconName: social-reddit
40 | static const socialreddit = IconData(
41 | 0xe608,
42 | fontFamily: 'Iconfont',
43 | matchTextDirection: true,
44 | );
45 |
46 | // iconName: social-snapchat
47 | static const socialsnapchat = IconData(
48 | 0xe609,
49 | fontFamily: 'Iconfont',
50 | matchTextDirection: true,
51 | );
52 |
53 | // iconName: social-skype
54 | static const socialskype = IconData(
55 | 0xe60a,
56 | fontFamily: 'Iconfont',
57 | matchTextDirection: true,
58 | );
59 |
60 | // iconName: social-twitter
61 | static const socialtwitter = IconData(
62 | 0xe60b,
63 | fontFamily: 'Iconfont',
64 | matchTextDirection: true,
65 | );
66 |
67 | // iconName: me
68 | static const me = IconData(
69 | 0xe604,
70 | fontFamily: 'Iconfont',
71 | matchTextDirection: true,
72 | );
73 |
74 | // iconName: tag
75 | static const tag = IconData(
76 | 0xe603,
77 | fontFamily: 'Iconfont',
78 | matchTextDirection: true,
79 | );
80 |
81 | // iconName: grid
82 | static const grid = IconData(
83 | 0xe602,
84 | fontFamily: 'Iconfont',
85 | matchTextDirection: true,
86 | );
87 |
88 | // iconName: home
89 | static const home = IconData(
90 | 0xe601,
91 | fontFamily: 'Iconfont',
92 | matchTextDirection: true,
93 | );
94 |
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/lib/common/utils/loading.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_easyloading/flutter_easyloading.dart';
3 |
4 | class Loading {
5 | Loading() {
6 | EasyLoading.instance
7 | ..displayDuration = const Duration(milliseconds: 2000)
8 | ..indicatorType = EasyLoadingIndicatorType.ring
9 | ..loadingStyle = EasyLoadingStyle.custom
10 | ..indicatorSize = 35.0
11 | ..lineWidth = 2
12 | ..radius = 10.0
13 | ..progressColor = Colors.white
14 | ..backgroundColor = Colors.black.withOpacity(0.7)
15 | ..indicatorColor = Colors.white
16 | ..textColor = Colors.white
17 | ..maskColor = Colors.black.withOpacity(0.6)
18 | ..userInteractions = true
19 | ..dismissOnTap = false
20 | ..maskType = EasyLoadingMaskType.custom;
21 | }
22 |
23 | static void show([String? text]) {
24 | EasyLoading.instance.userInteractions = false;
25 | EasyLoading.show(status: text ?? 'Loading...');
26 | }
27 |
28 | static void toast(String text) {
29 | EasyLoading.showToast(text);
30 | }
31 |
32 | static void dismiss() {
33 | EasyLoading.instance.userInteractions = true;
34 | EasyLoading.dismiss();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/common/utils/logger.dart:
--------------------------------------------------------------------------------
1 | class Logger {
2 | // Sample of abstract logging function
3 | static void write(String text, {bool isError = false}) {
4 | Future.microtask(() => print('** $text. isError: [$isError]'));
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/lib/common/utils/security.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 | import 'package:crypto/crypto.dart';
3 |
4 | /// SHA256
5 | String duSHA256(String input) {
6 | String salt = 'EIpWsyfiy@R@X#qn17!StJNdZK1fFF8iV6ffN!goZkqt#JxO'; // 加盐
7 | var bytes = utf8.encode(input + salt);
8 | var digest = sha256.convert(bytes);
9 |
10 | return digest.toString();
11 | }
12 |
--------------------------------------------------------------------------------
/lib/common/utils/utils.dart:
--------------------------------------------------------------------------------
1 | library utils;
2 |
3 | export 'validator.dart';
4 | export 'http.dart';
5 | export 'security.dart';
6 | export 'iconfont.dart';
7 | export 'date.dart';
8 | export 'logger.dart';
9 | export 'loading.dart';
10 |
--------------------------------------------------------------------------------
/lib/common/utils/validator.dart:
--------------------------------------------------------------------------------
1 | /// 检查邮箱格式
2 | bool duIsEmail(String? input) {
3 | if (input == null || input.isEmpty) return false;
4 | // 邮箱正则
5 | String regexEmail = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*\$";
6 | return RegExp(regexEmail).hasMatch(input);
7 | }
8 |
9 | /// 检查字符长度
10 | bool duCheckStringLength(String? input, int length) {
11 | if (input == null || input.isEmpty) return false;
12 | return input.length >= length;
13 | }
14 |
--------------------------------------------------------------------------------
/lib/common/values/borders.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/rendering.dart';
2 |
3 | class Borders {
4 | static const BorderSide primaryBorder = BorderSide(
5 | color: Color.fromARGB(255, 230, 230, 231),
6 | width: 1,
7 | style: BorderStyle.solid,
8 | );
9 | }
--------------------------------------------------------------------------------
/lib/common/values/cache.dart:
--------------------------------------------------------------------------------
1 | // 是否启用缓存
2 | const CACHE_ENABLE = false;
3 |
4 | // 缓存的最长时间,单位(秒)
5 | const CACHE_MAXAGE = 1000;
6 |
7 | // 最大缓存数
8 | const CACHE_MAXCOUNT = 100;
9 |
--------------------------------------------------------------------------------
/lib/common/values/colors.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | class AppColors {
4 | /// 主背景 白色
5 | static const Color primaryBackground = Color.fromARGB(255, 255, 255, 255);
6 |
7 | /// 主文本 灰色
8 | static const Color primaryText = Color.fromARGB(255, 45, 45, 47);
9 |
10 | /// 主控件-背景 蓝色
11 | static const Color primaryElement = Color.fromARGB(255, 41, 103, 255);
12 |
13 | /// 主控件-文本 白色
14 | static const Color primaryElementText = Color.fromARGB(255, 255, 255, 255);
15 |
16 | // *****************************************
17 |
18 | /// 第二种控件-背景色 淡灰色
19 | static const Color secondaryElement = Color.fromARGB(255, 246, 246, 246);
20 |
21 | /// 第二种控件-文本 浅蓝色
22 | static const Color secondaryElementText = Color.fromARGB(255, 41, 103, 255);
23 |
24 | // *****************************************
25 |
26 | /// 第三种控件-背景色 石墨色
27 | static const Color thirdElement = Color.fromARGB(255, 45, 45, 47);
28 |
29 | /// 第三种控件-文本 浅灰色2
30 | static const Color thirdElementText = Color.fromARGB(255, 141, 141, 142);
31 |
32 | // *****************************************
33 |
34 | /// tabBar 默认颜色 灰色
35 | static const Color tabBarElement = Color.fromARGB(255, 208, 208, 208);
36 |
37 | /// tabCellSeparator 单元格底部分隔条 颜色
38 | static const Color tabCellSeparator = Color.fromARGB(255, 230, 230, 231);
39 | }
40 |
--------------------------------------------------------------------------------
/lib/common/values/proxy.dart:
--------------------------------------------------------------------------------
1 | // 是否启用代理
2 | const PROXY_ENABLE = false;
3 |
4 | /// 代理服务IP
5 | // const PROXY_IP = '192.168.1.105';
6 | const PROXY_IP = '172.16.43.74';
7 |
8 | /// 代理服务端口
9 | const PROXY_PORT = 8866;
10 |
--------------------------------------------------------------------------------
/lib/common/values/radii.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/rendering.dart';
2 |
3 | class Radii {
4 | static const BorderRadiusGeometry k6pxRadius =
5 | BorderRadius.all(Radius.circular(6));
6 | static const BorderRadiusGeometry k54pxRadius =
7 | BorderRadius.all(Radius.circular(54));
8 | }
9 |
--------------------------------------------------------------------------------
/lib/common/values/server.dart:
--------------------------------------------------------------------------------
1 | // baidu yapi
2 | // const SERVER_API_URL = 'https://yapi.baidu.com/mock/41008';
3 | // const SERVER_API_URL = 'https://yapi.ducafecat.tech/mock/11';
4 | const SERVER_API_URL = 'https://mock.apifox.cn/m1/1124717-0-default';
5 |
6 | // 本地搭建 yapi
7 | // const SERVER_API_URL = 'http://yapi.ducafecat.tech/mock/11';
8 |
--------------------------------------------------------------------------------
/lib/common/values/shadows.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/rendering.dart';
2 |
3 | class Shadows {
4 | static const BoxShadow primaryShadow = BoxShadow(
5 | color: Color.fromARGB(38, 27, 27, 29),
6 | offset: Offset(0, 5),
7 | blurRadius: 10,
8 | );
9 | }
--------------------------------------------------------------------------------
/lib/common/values/storage.dart:
--------------------------------------------------------------------------------
1 | /// 用户 - 配置信息
2 | const String STORAGE_USER_PROFILE_KEY = 'user_profile';
3 |
4 | /// 用户 - 配置信息
5 | const String STORAGE_USER_TOKEN_KEY = 'user_token';
6 |
7 | /// 设备是否第一次打开
8 | const String STORAGE_DEVICE_FIRST_OPEN_KEY = 'device_first_open';
9 |
10 | /// 首页新闻cacheKey
11 | const String STORAGE_INDEX_NEWS_CACHE_KEY = 'cache_index_news';
12 |
13 | /// 多语言
14 | const String STORAGE_LANGUAGE_CODE = 'language_code';
15 |
--------------------------------------------------------------------------------
/lib/common/values/values.dart:
--------------------------------------------------------------------------------
1 | library values;
2 |
3 | export 'colors.dart';
4 | export 'borders.dart';
5 | export 'radii.dart';
6 | export 'shadows.dart';
7 | export 'server.dart';
8 | export 'storage.dart';
9 | export 'cache.dart';
10 | export 'proxy.dart';
11 |
--------------------------------------------------------------------------------
/lib/common/widgets/app.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:flutter_ducafecat_news_getx/common/values/values.dart';
4 |
5 | /// 透明背景 AppBar
6 | AppBar transparentAppBar({
7 | Widget? title,
8 | Widget? leading,
9 | List? actions,
10 | }) {
11 | return AppBar(
12 | backgroundColor: Colors.transparent,
13 | elevation: 0,
14 | title: title != null
15 | ? Center(
16 | child: title,
17 | )
18 | : null,
19 | leading: leading,
20 | actions: actions,
21 | );
22 | }
23 |
24 | /// 10像素 Divider
25 | Widget divider10Px({Color bgColor = AppColors.secondaryElement}) {
26 | return Container(
27 | height: 10.w,
28 | decoration: BoxDecoration(
29 | color: bgColor,
30 | ),
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/lib/common/widgets/button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/values/values.dart';
3 | import 'package:flutter_screenutil/flutter_screenutil.dart';
4 |
5 | /// 扁平圆角按钮
6 | Widget btnFlatButtonWidget({
7 | required VoidCallback onPressed,
8 | double width = 140,
9 | double height = 44,
10 | Color gbColor = AppColors.primaryElement,
11 | String title = "button",
12 | Color fontColor = AppColors.primaryElementText,
13 | double fontSize = 18,
14 | String fontName = "Montserrat",
15 | FontWeight fontWeight = FontWeight.w400,
16 | }) {
17 | return Container(
18 | width: width.w,
19 | height: height.h,
20 | child: TextButton(
21 | style: ButtonStyle(
22 | textStyle: MaterialStateProperty.all(TextStyle(
23 | fontSize: 16.sp,
24 | )),
25 | foregroundColor: MaterialStateProperty.resolveWith(
26 | (states) {
27 | if (states.contains(MaterialState.focused) &&
28 | !states.contains(MaterialState.pressed)) {
29 | return Colors.blue;
30 | } else if (states.contains(MaterialState.pressed)) {
31 | return Colors.deepPurple;
32 | }
33 | return fontColor;
34 | },
35 | ),
36 | backgroundColor: MaterialStateProperty.resolveWith((states) {
37 | if (states.contains(MaterialState.pressed)) {
38 | return Colors.blue[200];
39 | }
40 | return gbColor;
41 | }),
42 | shape: MaterialStateProperty.all(RoundedRectangleBorder(
43 | borderRadius: Radii.k6pxRadius,
44 | )),
45 | ),
46 | child: Text(
47 | title,
48 | textAlign: TextAlign.center,
49 | style: TextStyle(
50 | color: fontColor,
51 | fontFamily: fontName,
52 | fontWeight: fontWeight,
53 | fontSize: fontSize.sp,
54 | height: 1,
55 | ),
56 | ),
57 | onPressed: onPressed,
58 | ),
59 | );
60 | }
61 |
62 | /// 第三方按钮
63 | Widget btnFlatButtonBorderOnlyWidget({
64 | required VoidCallback onPressed,
65 | double width = 88,
66 | double height = 44,
67 | required String iconFileName,
68 | }) {
69 | return Container(
70 | width: width.w,
71 | height: height.h,
72 | child: TextButton(
73 | style: ButtonStyle(
74 | // textStyle: MaterialStateProperty.all(TextStyle(
75 | // fontSize: 16.sp,
76 | // )),
77 | // foregroundColor: MaterialStateProperty.resolveWith(
78 | // (states) {
79 | // if (states.contains(MaterialState.focused) &&
80 | // !states.contains(MaterialState.pressed)) {
81 | // return Colors.blue;
82 | // } else if (states.contains(MaterialState.pressed)) {
83 | // return Colors.deepPurple;
84 | // }
85 | // return AppColors.primaryElementText;
86 | // },
87 | // ),
88 | // backgroundColor: MaterialStateProperty.resolveWith((states) {
89 | // if (states.contains(MaterialState.pressed)) {
90 | // return Colors.blue[200];
91 | // }
92 | // return AppColors.primaryElement;
93 | // }),
94 | shape: MaterialStateProperty.all(RoundedRectangleBorder(
95 | borderRadius: Radii.k6pxRadius,
96 | )),
97 | ),
98 | child: Image.asset(
99 | "assets/images/icons-$iconFileName.png",
100 | ),
101 | onPressed: onPressed,
102 | ),
103 | );
104 | }
105 |
--------------------------------------------------------------------------------
/lib/common/widgets/image.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:cached_network_image/cached_network_image.dart';
3 | import 'package:flutter_ducafecat_news_getx/common/values/values.dart';
4 | import 'package:flutter_screenutil/flutter_screenutil.dart';
5 |
6 | /// 缓存图片
7 | Widget netImageCached(
8 | String url, {
9 | double width = 48,
10 | double height = 48,
11 | EdgeInsetsGeometry? margin,
12 | }) {
13 | return CachedNetworkImage(
14 | imageUrl: url,
15 | imageBuilder: (context, imageProvider) => Container(
16 | height: height.h,
17 | width: width.w,
18 | margin: margin,
19 | decoration: BoxDecoration(
20 | borderRadius: Radii.k6pxRadius,
21 | image: DecorationImage(
22 | image: imageProvider,
23 | fit: BoxFit.cover,
24 | // colorFilter: ColorFilter.mode(Colors.red, BlendMode.colorBurn),
25 | ),
26 | ),
27 | ),
28 | placeholder: (context, url) {
29 | return Container(
30 | alignment: Alignment.center,
31 | child: CircularProgressIndicator(),
32 | );
33 | },
34 | errorWidget: (context, url, error) => Icon(Icons.error),
35 | );
36 | }
37 |
--------------------------------------------------------------------------------
/lib/common/widgets/input.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/values/values.dart';
3 | import 'package:flutter_screenutil/flutter_screenutil.dart';
4 |
5 | /// 输入框
6 | Widget inputTextEdit({
7 | TextEditingController? controller,
8 | TextInputType keyboardType = TextInputType.text,
9 | String? hintText,
10 | bool isPassword = false,
11 | double marginTop = 15,
12 | bool autofocus = false,
13 | }) {
14 | return Container(
15 | height: 44.h,
16 | margin: EdgeInsets.only(top: marginTop.h),
17 | decoration: BoxDecoration(
18 | color: AppColors.secondaryElement,
19 | borderRadius: Radii.k6pxRadius,
20 | ),
21 | child: TextField(
22 | autofocus: autofocus,
23 | controller: controller,
24 | keyboardType: keyboardType,
25 | decoration: InputDecoration(
26 | hintText: hintText,
27 | contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 9),
28 | border: InputBorder.none,
29 | ),
30 | style: TextStyle(
31 | color: AppColors.primaryText,
32 | fontFamily: "Avenir",
33 | fontWeight: FontWeight.w400,
34 | fontSize: 18.sp,
35 | ),
36 | maxLines: 1,
37 | autocorrect: false, // 自动纠正
38 | obscureText: isPassword, // 隐藏输入内容, 密码框
39 | ),
40 | );
41 | }
42 |
43 | /// email 输入框
44 | /// 背景白色,文字黑色,带阴影
45 | Widget inputEmailEdit({
46 | TextEditingController? controller,
47 | TextInputType keyboardType = TextInputType.text,
48 | String? hintText,
49 | bool isPassword = false,
50 | double marginTop = 15,
51 | bool autofocus = false,
52 | }) {
53 | return Container(
54 | height: 44.h,
55 | margin: EdgeInsets.only(top: marginTop.h),
56 | decoration: BoxDecoration(
57 | color: AppColors.primaryBackground,
58 | borderRadius: Radii.k6pxRadius,
59 | boxShadow: [
60 | BoxShadow(
61 | color: Color.fromARGB(41, 0, 0, 0),
62 | offset: Offset(0, 1),
63 | blurRadius: 0,
64 | ),
65 | ],
66 | ),
67 | child: TextField(
68 | autofocus: autofocus,
69 | controller: controller,
70 | keyboardType: keyboardType,
71 | decoration: InputDecoration(
72 | hintText: hintText,
73 | contentPadding: EdgeInsets.fromLTRB(20, 10, 0, 9),
74 | border: InputBorder.none,
75 | hintStyle: TextStyle(
76 | color: AppColors.primaryText,
77 | ),
78 | ),
79 | style: TextStyle(
80 | color: AppColors.primaryText,
81 | fontFamily: "Avenir",
82 | fontWeight: FontWeight.w400,
83 | fontSize: 18.sp,
84 | ),
85 | maxLines: 1,
86 | autocorrect: false, // 自动纠正
87 | obscureText: isPassword, // 隐藏输入内容, 密码框
88 | ),
89 | );
90 | }
91 |
--------------------------------------------------------------------------------
/lib/common/widgets/skeleton.dart:
--------------------------------------------------------------------------------
1 |
2 | // /// 骨架屏-卡片
3 | // Widget cardListSkeleton() {
4 | // return PKCardListSkeleton(
5 | // isCircularImage: true,
6 | // isBottomLinesActive: false,
7 | // length: 10,
8 | // );
9 | // }
10 |
11 | // /// 页面骨架屏
12 | // Widget pageSkeleton() {
13 | // return PKCardPageSkeleton(
14 | // totalLines: 5,
15 | // );
16 | // }
17 |
--------------------------------------------------------------------------------
/lib/common/widgets/toast.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:fluttertoast/fluttertoast.dart';
3 | import 'package:flutter_screenutil/flutter_screenutil.dart';
4 |
5 | Future toastInfo({
6 | required String msg,
7 | Color backgroundColor = Colors.black,
8 | Color textColor = Colors.white,
9 | }) {
10 | return Fluttertoast.showToast(
11 | msg: msg,
12 | toastLength: Toast.LENGTH_SHORT,
13 | gravity: ToastGravity.TOP,
14 | timeInSecForIosWeb: 1,
15 | backgroundColor: backgroundColor,
16 | textColor: textColor,
17 | fontSize: 16.sp,
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/lib/common/widgets/widgets.dart:
--------------------------------------------------------------------------------
1 | library widgets;
2 |
3 | export 'button.dart';
4 | export 'toast.dart';
5 | export 'app.dart';
6 | export 'input.dart';
7 | export 'image.dart';
8 | export 'skeleton.dart';
9 |
--------------------------------------------------------------------------------
/lib/global.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:flutter_ducafecat_news_getx/common/services/services.dart';
4 | import 'package:flutter_ducafecat_news_getx/common/store/store.dart';
5 | import 'package:flutter_ducafecat_news_getx/common/utils/utils.dart';
6 | import 'package:get/get.dart';
7 |
8 | /// 全局静态数据
9 | class Global {
10 | /// 初始化
11 | static Future init() async {
12 | WidgetsFlutterBinding.ensureInitialized();
13 | await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
14 |
15 | setSystemUi();
16 | Loading();
17 |
18 | await Get.putAsync(() => StorageService().init());
19 |
20 | Get.put(ConfigStore());
21 | Get.put(UserStore());
22 | }
23 |
24 | static void setSystemUi() {
25 | if (GetPlatform.isAndroid) {
26 | SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(
27 | statusBarColor: Colors.transparent,
28 | statusBarBrightness: Brightness.light,
29 | statusBarIconBrightness: Brightness.dark,
30 | systemNavigationBarDividerColor: Colors.transparent,
31 | systemNavigationBarColor: Colors.white,
32 | systemNavigationBarIconBrightness: Brightness.dark,
33 | );
34 | SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/langs/translation_service.dart';
3 | import 'package:flutter_ducafecat_news_getx/common/routers/pages.dart';
4 | import 'package:flutter_ducafecat_news_getx/common/store/store.dart';
5 | import 'package:flutter_ducafecat_news_getx/common/style/style.dart';
6 | import 'package:flutter_ducafecat_news_getx/common/utils/utils.dart';
7 | import 'package:flutter_ducafecat_news_getx/global.dart';
8 | import 'package:flutter_easyloading/flutter_easyloading.dart';
9 | import 'package:flutter_localizations/flutter_localizations.dart';
10 | import 'package:flutter_screenutil/flutter_screenutil.dart';
11 | import 'package:get/get.dart';
12 | import 'package:pull_to_refresh/pull_to_refresh.dart';
13 |
14 | Future main() async {
15 | await Global.init();
16 | runApp(MyApp());
17 | }
18 |
19 | class MyApp extends StatelessWidget {
20 | @override
21 | Widget build(BuildContext context) {
22 | return ScreenUtilInit(
23 | designSize: Size(375, 812),
24 | builder: () => RefreshConfiguration(
25 | headerBuilder: () => ClassicHeader(),
26 | footerBuilder: () => ClassicFooter(),
27 | hideFooterWhenNotFull: true,
28 | headerTriggerDistance: 80,
29 | maxOverScrollExtent: 100,
30 | footerTriggerDistance: 150,
31 | child: GetMaterialApp(
32 | title: 'News',
33 | theme: AppTheme.light,
34 | debugShowCheckedModeBanner: false,
35 | initialRoute: AppPages.INITIAL,
36 | getPages: AppPages.routes,
37 | builder: EasyLoading.init(),
38 | translations: TranslationService(),
39 | navigatorObservers: [AppPages.observer],
40 | localizationsDelegates: [
41 | GlobalMaterialLocalizations.delegate,
42 | GlobalWidgetsLocalizations.delegate,
43 | GlobalCupertinoLocalizations.delegate,
44 | ],
45 | supportedLocales: ConfigStore.to.languages,
46 | locale: ConfigStore.to.locale,
47 | fallbackLocale: Locale('en', 'US'),
48 | enableLog: true,
49 | logWriterCallback: Logger.write,
50 | ),
51 | ),
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/pages/application/bindings.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_ducafecat_news_getx/pages/category/index.dart';
2 | import 'package:flutter_ducafecat_news_getx/pages/main/index.dart';
3 | import 'package:get/get.dart';
4 |
5 | import 'controller.dart';
6 |
7 | class ApplicationBinding implements Bindings {
8 | @override
9 | void dependencies() {
10 | Get.lazyPut(() => ApplicationController());
11 | Get.lazyPut(() => MainController());
12 | Get.lazyPut(() => CategoryController());
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/pages/application/index.dart:
--------------------------------------------------------------------------------
1 | library application;
2 |
3 | export './state.dart';
4 | export './controller.dart';
5 | export './bindings.dart';
6 | export './view.dart';
7 |
--------------------------------------------------------------------------------
/lib/pages/application/state.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | class ApplicationState {
4 | // 当前 tab 页码
5 | final _page = 0.obs;
6 | set page(value) => this._page.value = value;
7 | get page => this._page.value;
8 | }
9 |
--------------------------------------------------------------------------------
/lib/pages/application/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/values/values.dart';
3 | import 'package:flutter_ducafecat_news_getx/common/widgets/widgets.dart';
4 | import 'package:flutter_ducafecat_news_getx/pages/category/index.dart';
5 | import 'package:flutter_ducafecat_news_getx/pages/main/index.dart';
6 | import 'package:flutter_screenutil/flutter_screenutil.dart';
7 | import 'package:get/get.dart';
8 |
9 | import 'index.dart';
10 |
11 | class ApplicationPage extends GetView {
12 | // 顶部导航
13 | AppBar _buildAppBar() {
14 | return transparentAppBar(
15 | title: Obx(() => Text(
16 | controller.tabTitles[controller.state.page],
17 | style: TextStyle(
18 | color: AppColors.primaryText,
19 | fontFamily: 'Montserrat',
20 | fontSize: 18.sp,
21 | fontWeight: FontWeight.w600,
22 | ),
23 | )),
24 | actions: [
25 | IconButton(
26 | icon: Icon(
27 | Icons.search,
28 | color: AppColors.primaryText,
29 | ),
30 | onPressed: () {},
31 | )
32 | ]);
33 | }
34 |
35 | // 内容页
36 | Widget _buildPageView() {
37 | return PageView(
38 | physics: NeverScrollableScrollPhysics(),
39 | children: [
40 | MainPage(),
41 | CategoryPage(),
42 | Text('BookmarksPage'),
43 | Text('AccountPage'),
44 | ],
45 | controller: controller.pageController,
46 | onPageChanged: controller.handlePageChanged,
47 | );
48 | }
49 |
50 | // 底部导航
51 | Widget _buildBottomNavigationBar() {
52 | return Obx(() => BottomNavigationBar(
53 | items: controller.bottomTabs,
54 | currentIndex: controller.state.page,
55 | // fixedColor: AppColors.primaryElement,
56 | type: BottomNavigationBarType.fixed,
57 | onTap: controller.handleNavBarTap,
58 | showSelectedLabels: false,
59 | showUnselectedLabels: false,
60 | ));
61 | }
62 |
63 | @override
64 | Widget build(BuildContext context) {
65 | return Scaffold(
66 | appBar: _buildAppBar(),
67 | body: _buildPageView(),
68 | bottomNavigationBar: _buildBottomNavigationBar(),
69 | );
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/pages/category/bindings.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'controller.dart';
4 |
5 | class CategoryBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(() => CategoryController());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/pages/category/controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_ducafecat_news_getx/common/apis/apis.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/entities/entities.dart';
3 | import 'package:get/get.dart';
4 | import 'package:pull_to_refresh/pull_to_refresh.dart';
5 |
6 | import 'index.dart';
7 |
8 | class CategoryController extends GetxController {
9 | CategoryController();
10 |
11 | /// UI 组件
12 | final RefreshController refreshController = RefreshController(
13 | initialRefresh: true,
14 | );
15 |
16 | /// 响应式成员变量
17 | final state = CategoryState();
18 |
19 | /// 成员变量
20 | String categoryCode = '';
21 | int curPage = 1;
22 | int pageSize = 20;
23 | int total = 20;
24 |
25 | /// 事件
26 |
27 | void onRefresh() {
28 | fetchNewsList(isRefresh: true).then((_) {
29 | refreshController.refreshCompleted(resetFooterState: true);
30 | }).catchError((_) {
31 | refreshController.refreshFailed();
32 | });
33 | }
34 |
35 | void onLoading() {
36 | if (state.newsList.length < total) {
37 | fetchNewsList().then((_) {
38 | refreshController.loadComplete();
39 | }).catchError((_) {
40 | refreshController.loadFailed();
41 | });
42 | } else {
43 | refreshController.loadNoData();
44 | }
45 | }
46 |
47 | // 方法
48 |
49 | // 拉取数据
50 | Future fetchNewsList({bool isRefresh = false}) async {
51 | var result = await NewsAPI.newsPageList(
52 | params: NewsPageListRequestEntity(
53 | categoryCode: categoryCode,
54 | pageNum: curPage + 1,
55 | pageSize: pageSize,
56 | ),
57 | );
58 |
59 | if (isRefresh == true) {
60 | curPage = 1;
61 | total = result.counts!;
62 | state.newsList.clear();
63 | } else {
64 | curPage++;
65 | }
66 |
67 | state.newsList.addAll(result.items!);
68 | }
69 |
70 | /// 生命周期
71 |
72 | ///dispose 释放内存
73 | @override
74 | void dispose() {
75 | super.dispose();
76 | // dispose 释放对象
77 | refreshController.dispose();
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/lib/pages/category/index.dart:
--------------------------------------------------------------------------------
1 | library category;
2 |
3 | export './state.dart';
4 | export './controller.dart';
5 | export './bindings.dart';
6 | export './view.dart';
7 |
--------------------------------------------------------------------------------
/lib/pages/category/state.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_ducafecat_news_getx/common/entities/entities.dart';
2 | import 'package:get/get.dart';
3 |
4 | class CategoryState {
5 | // 新闻翻页
6 | RxList newsList = [].obs;
7 | }
8 |
--------------------------------------------------------------------------------
/lib/pages/category/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import 'index.dart';
5 | import 'widgets/widgets.dart';
6 |
7 | class CategoryPage extends GetView {
8 | @override
9 | Widget build(BuildContext context) {
10 | return Scaffold(
11 | body: NewsPageList(),
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/pages/category/widgets/news_page_list.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 | import 'package:pull_to_refresh/pull_to_refresh.dart';
4 | import 'package:flutter_screenutil/flutter_screenutil.dart';
5 |
6 | import '../index.dart';
7 | import 'widgets.dart';
8 |
9 | class NewsPageList extends StatefulWidget {
10 | NewsPageList({Key? key}) : super(key: key);
11 |
12 | @override
13 | _NewsPageListState createState() => _NewsPageListState();
14 | }
15 |
16 | class _NewsPageListState extends State
17 | with AutomaticKeepAliveClientMixin {
18 | @override
19 | bool get wantKeepAlive => true;
20 |
21 | final controller = Get.find();
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | super.build(context);
26 | return GetX(
27 | init: controller,
28 | builder: (controller) => SmartRefresher(
29 | enablePullUp: true,
30 | controller: controller.refreshController,
31 | onRefresh: controller.onRefresh,
32 | onLoading: controller.onLoading,
33 | child: CustomScrollView(
34 | slivers: [
35 | SliverPadding(
36 | padding: EdgeInsets.symmetric(
37 | vertical: 0.w,
38 | horizontal: 0.w,
39 | ),
40 | sliver: SliverList(
41 | delegate: SliverChildBuilderDelegate(
42 | (content, index) {
43 | var item = controller.state.newsList[index];
44 | return newsListItem(item);
45 | },
46 | childCount: controller.state.newsList.length,
47 | ),
48 | ),
49 | ),
50 | ],
51 | ),
52 | ),
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/pages/category/widgets/widgets.dart:
--------------------------------------------------------------------------------
1 | library widgets;
2 |
3 | export 'news_page_list.dart';
4 | export 'news_item.dart';
5 |
--------------------------------------------------------------------------------
/lib/pages/frame/notfound/bindings.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'controller.dart';
4 |
5 | class NotfoundBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(() => NotfoundController());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/pages/frame/notfound/controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'index.dart';
4 |
5 | class NotfoundController extends GetxController {
6 | NotfoundController();
7 |
8 | /// 响应式成员变量
9 |
10 | final state = NotfoundState();
11 |
12 | /// 成员变量
13 |
14 | /// 事件
15 |
16 | // tap
17 | void handleTap(int index) {
18 | Get.snackbar(
19 | "标题",
20 | "消息",
21 | );
22 | }
23 |
24 | /// 生命周期
25 |
26 | ///在 widget 内存中分配后立即调用。
27 | ///你可以用它来为控制器初始化 initialize 一些东西。
28 | @override
29 | void onInit() {
30 | super.onInit();
31 | // new 对象
32 | // 初始静态数据
33 | }
34 |
35 | ///在 onInit() 之后调用 1 帧。这是进入的理想场所
36 | ///导航事件,例如 snackbar、对话框或新route,或
37 | ///async 异步请求。
38 | @override
39 | void onReady() {
40 | super.onReady();
41 | // async 拉取数据
42 | }
43 |
44 | ///在 [onDelete] 方法之前调用。 [onClose] 可能用于
45 | ///处理控制器使用的资源。就像 closing events 一样,
46 | ///或在控制器销毁之前的流。
47 | ///或者处置可能造成一些内存泄漏的对象,
48 | ///像 TextEditingControllers、AnimationControllers。
49 | ///将一些数据保存在磁盘上也可能很有用。
50 | @override
51 | void onClose() {
52 | super.onClose();
53 | // 1 stop & close 关闭对象
54 | // 2 save 持久化数据
55 | }
56 |
57 | ///dispose 释放内存
58 | @override
59 | void dispose() {
60 | super.dispose();
61 | // dispose 释放对象
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/lib/pages/frame/notfound/index.dart:
--------------------------------------------------------------------------------
1 | library notfound;
2 |
3 | export './state.dart';
4 | export './controller.dart';
5 | export './bindings.dart';
6 | export './view.dart';
7 |
--------------------------------------------------------------------------------
/lib/pages/frame/notfound/state.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | class NotfoundState {
4 | // title
5 | final _title = "".obs;
6 | set title(value) => this._title.value = value;
7 | get title => this._title.value;
8 | }
9 |
--------------------------------------------------------------------------------
/lib/pages/frame/notfound/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import 'index.dart';
5 | import 'widgets/widgets.dart';
6 |
7 | class NotfoundPage extends GetView {
8 | // 内容页
9 | Widget _buildView() {
10 | return HellowordWidget();
11 | }
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Scaffold(
16 | body: _buildView(),
17 | );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/pages/frame/notfound/widgets/helloword.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import '../index.dart';
5 |
6 | /// hellowrod
7 | class HellowordWidget extends GetView {
8 | @override
9 | Widget build(BuildContext context) {
10 | return Center(
11 | child: Obx(() => Text(controller.state.title)),
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/pages/frame/notfound/widgets/widgets.dart:
--------------------------------------------------------------------------------
1 | library widgets;
2 |
3 | export './helloword.dart';
4 |
--------------------------------------------------------------------------------
/lib/pages/frame/sign_in/bindings.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'controller.dart';
4 |
5 | class SignInBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(() => SignInController());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/pages/frame/sign_in/controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/apis/apis.dart';
3 | import 'package:flutter_ducafecat_news_getx/common/entities/entities.dart';
4 | import 'package:flutter_ducafecat_news_getx/common/routers/routes.dart';
5 | import 'package:flutter_ducafecat_news_getx/common/store/store.dart';
6 | import 'package:flutter_ducafecat_news_getx/common/utils/utils.dart';
7 | import 'package:flutter_ducafecat_news_getx/common/widgets/widgets.dart';
8 | import 'package:get/get.dart';
9 |
10 | import 'index.dart';
11 |
12 | class SignInController extends GetxController {
13 | final state = SignInState();
14 |
15 | SignInController();
16 |
17 | // email的控制器
18 | final TextEditingController emailController = TextEditingController();
19 | // 密码的控制器
20 | final TextEditingController passController = TextEditingController();
21 |
22 | // final MyRepository repository;
23 | // SignInController({@required this.repository}) : assert(repository != null);
24 |
25 | // 跳转 注册界面
26 | handleNavSignUp() {
27 | Get.toNamed(AppRoutes.SIGN_UP);
28 | }
29 |
30 | // 忘记密码
31 | handleFogotPassword() {
32 | toastInfo(msg: '忘记密码');
33 | }
34 |
35 | // 执行登录操作
36 | handleSignIn() async {
37 | // if (!duIsEmail(_emailController.value.text)) {
38 | // toastInfo(msg: '请正确输入邮件');
39 | // return;
40 | // }
41 | // if (!duCheckStringLength(_passController.value.text, 6)) {
42 | // toastInfo(msg: '密码不能小于6位');
43 | // return;
44 | // }
45 |
46 | UserLoginRequestEntity params = UserLoginRequestEntity(
47 | email: emailController.value.text,
48 | password: duSHA256(passController.value.text),
49 | );
50 |
51 | UserLoginResponseEntity userProfile = await UserAPI.login(
52 | params: params,
53 | );
54 | UserStore.to.saveProfile(userProfile);
55 |
56 | Get.offAndToNamed(AppRoutes.Application);
57 | }
58 |
59 | @override
60 | void onReady() {
61 | super.onReady();
62 | }
63 |
64 | @override
65 | void dispose() {
66 | emailController.dispose();
67 | passController.dispose();
68 | super.dispose();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/pages/frame/sign_in/index.dart:
--------------------------------------------------------------------------------
1 | library sign_in;
2 |
3 | export './state.dart';
4 | export './controller.dart';
5 | export './bindings.dart';
6 | export './view.dart';
7 |
--------------------------------------------------------------------------------
/lib/pages/frame/sign_in/state.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | class SignInState {
4 | final _obj = ''.obs;
5 | set obj(value) => this._obj.value = value;
6 | get obj => this._obj.value;
7 |
8 | // SignInState() {}
9 | }
10 |
--------------------------------------------------------------------------------
/lib/pages/frame/sign_up/bindings.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'controller.dart';
4 |
5 | class SignUpBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(() => SignUpController());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/pages/frame/sign_up/controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/apis/apis.dart';
3 | import 'package:flutter_ducafecat_news_getx/common/entities/entities.dart';
4 | import 'package:flutter_ducafecat_news_getx/common/utils/utils.dart';
5 | import 'package:flutter_ducafecat_news_getx/common/widgets/widgets.dart';
6 | import 'package:get/get.dart';
7 |
8 | import 'index.dart';
9 |
10 | class SignUpController extends GetxController {
11 | SignUpController();
12 |
13 | /// obs 响应式变量 才写入 state
14 | final state = SignUpState();
15 |
16 | /// 业务变量
17 |
18 | final TextEditingController fullnameController = TextEditingController();
19 | final TextEditingController emailController = TextEditingController();
20 | final TextEditingController passController = TextEditingController();
21 |
22 | /// 业务事件
23 |
24 | // 返回上一页
25 | handleNavPop() {
26 | Get.back();
27 | }
28 |
29 | // 提示信息
30 | handleTip() {
31 | toastInfo(msg: '这是注册界面');
32 | }
33 |
34 | // 忘记密码
35 | handleFogotPassword() {
36 | toastInfo(msg: '忘记密码');
37 | }
38 |
39 | // 执行注册操作
40 | handleSignUp() async {
41 | // if (!duCheckStringLength(fullnameController.value.text, 5)) {
42 | // toastInfo(msg: '用户名不能小于5位');
43 | // return;
44 | // }
45 | // if (!duIsEmail(emailController.value.text)) {
46 | // toastInfo(msg: '请正确输入邮件');
47 | // return;
48 | // }
49 | // if (!duCheckStringLength(passController.value.text, 6)) {
50 | // toastInfo(msg: '密码不能小于6位');
51 | // return;
52 | // }
53 |
54 | UserRegisterRequestEntity params = UserRegisterRequestEntity(
55 | email: emailController.value.text,
56 | password: duSHA256(passController.value.text),
57 | );
58 |
59 | await UserAPI.register(
60 | params: params,
61 | );
62 |
63 | Get.back();
64 | }
65 |
66 | /// 生命周期
67 |
68 | // 页面载入完成
69 | @override
70 | void onReady() {
71 | super.onReady();
72 | }
73 |
74 | @override
75 | void dispose() {
76 | fullnameController.dispose();
77 | emailController.dispose();
78 | passController.dispose();
79 | super.dispose();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/pages/frame/sign_up/index.dart:
--------------------------------------------------------------------------------
1 | library sign_up;
2 |
3 | export './state.dart';
4 | export './controller.dart';
5 | export './bindings.dart';
6 | export './view.dart';
7 |
--------------------------------------------------------------------------------
/lib/pages/frame/sign_up/state.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | class SignUpState {
4 | /// 响应变量用 get set 包下
5 |
6 | final _obj = ''.obs;
7 | set obj(value) => this._obj.value = value;
8 | get obj => this._obj.value;
9 |
10 | // SignUpState() {}
11 | }
12 |
--------------------------------------------------------------------------------
/lib/pages/frame/welcome/bindings.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'controller.dart';
4 |
5 | class WelcomeBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(() => WelcomeController());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/pages/frame/welcome/controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_ducafecat_news_getx/common/routers/routes.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/store/store.dart';
3 | import 'package:get/get.dart';
4 |
5 | import 'index.dart';
6 |
7 | class WelcomeController extends GetxController {
8 | final state = WelcomeState();
9 |
10 | WelcomeController();
11 |
12 | // 跳转 注册界面
13 | handleNavSignIn() async {
14 | await ConfigStore.to.saveAlreadyOpen();
15 | Get.offAndToNamed(AppRoutes.SIGN_IN);
16 | }
17 |
18 | @override
19 | void onReady() {
20 | super.onReady();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/pages/frame/welcome/index.dart:
--------------------------------------------------------------------------------
1 | library welcome;
2 |
3 | export './state.dart';
4 | export './controller.dart';
5 | export './bindings.dart';
6 | export './view.dart';
7 |
--------------------------------------------------------------------------------
/lib/pages/frame/welcome/state.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | class WelcomeState {
4 | final _obj = ''.obs;
5 | set obj(value) => this._obj.value = value;
6 | get obj => this._obj.value;
7 |
8 | // WelcomeState() {}
9 | }
10 |
--------------------------------------------------------------------------------
/lib/pages/index.txt:
--------------------------------------------------------------------------------
1 | export 'application/index.dart';
2 | export 'category/index.dart';
3 | export 'frame/notfound/index.dart';
4 | export 'frame/sign_in/index.dart';
5 | export 'frame/sign_up/index.dart';
6 | export 'frame/welcome/index.dart';
7 | export 'main/index.dart';
8 |
--------------------------------------------------------------------------------
/lib/pages/main/bindings.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import 'controller.dart';
4 |
5 | class MainBinding implements Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(() => MainController());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/pages/main/controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_ducafecat_news_getx/common/apis/apis.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/entities/entities.dart';
3 | import 'package:get/get.dart';
4 |
5 | import 'index.dart';
6 |
7 | class MainController extends GetxController {
8 | MainController();
9 |
10 | /// 响应式成员变量
11 |
12 | final state = MainState();
13 |
14 | /// 成员变量
15 |
16 | /// 方法
17 |
18 | // 拉取数据
19 | asyncLoadAllData() async {
20 | state.categories = await NewsAPI.categories(
21 | cacheDisk: true,
22 | );
23 | state.channels = await NewsAPI.channels(
24 | cacheDisk: true,
25 | );
26 | state.newsRecommend = await NewsAPI.newsRecommend(
27 | cacheDisk: true,
28 | );
29 | state.newsPageList = await NewsAPI.newsPageList(
30 | cacheDisk: true,
31 | );
32 |
33 | state.selCategoryCode = state.categories.first.code;
34 | }
35 |
36 | // 拉取推荐、新闻
37 | asyncLoadNewsData(
38 | categoryCode, {
39 | bool refresh = false,
40 | }) async {
41 | state.selCategoryCode = categoryCode;
42 | state.newsRecommend = await NewsAPI.newsRecommend(
43 | params: NewsRecommendRequestEntity(categoryCode: categoryCode),
44 | refresh: refresh,
45 | cacheDisk: true,
46 | );
47 | state.newsPageList = await NewsAPI.newsPageList(
48 | params: NewsPageListRequestEntity(categoryCode: categoryCode),
49 | refresh: refresh,
50 | cacheDisk: true,
51 | );
52 | }
53 |
54 | /// 事件
55 |
56 | /// 生命周期
57 |
58 | /// 初始
59 | @override
60 | void onInit() {
61 | super.onInit();
62 | }
63 |
64 | /// 可 async 拉取数据
65 | /// 可触发展示交互组件
66 | /// onInit 之后
67 | @override
68 | void onReady() {
69 | super.onReady();
70 | asyncLoadAllData();
71 | }
72 |
73 | /// 关闭页面
74 | /// 可以缓存数据,关闭各种控制器
75 | /// dispose 之前
76 | @override
77 | void onClose() {
78 | super.onClose();
79 | }
80 |
81 | /// 被释放
82 | /// 手动 释放各种内存资源
83 | @override
84 | void dispose() {
85 | super.dispose();
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/lib/pages/main/index.dart:
--------------------------------------------------------------------------------
1 | library main;
2 |
3 | export './state.dart';
4 | export './controller.dart';
5 | export './bindings.dart';
6 | export './view.dart';
7 |
--------------------------------------------------------------------------------
/lib/pages/main/state.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_ducafecat_news_getx/common/entities/entities.dart';
2 | import 'package:get/get.dart';
3 |
4 | class MainState {
5 | // 分类
6 | var _categories = Rx?>(null);
7 | set categories(value) => _categories.value = value;
8 | get categories => _categories.value;
9 |
10 | // 新闻翻页
11 | var _newsPageList = Rx(null);
12 | set newsPageList(value) => _newsPageList.value = value;
13 | get newsPageList => _newsPageList.value;
14 | void appendNewsPageList(NewsPageListResponseEntity value) {
15 | if (_newsPageList.value != null) {
16 | _newsPageList.value!.items?.addAll(value.items!.toList());
17 | }
18 | }
19 |
20 | // 新闻推荐
21 | var _newsRecommend = Rx(null);
22 | set newsRecommend(value) => _newsRecommend.value = value;
23 | get newsRecommend => _newsRecommend.value;
24 |
25 | // 频道
26 | var _channels = Rx?>(null);
27 | set channels(value) => _channels.value = value;
28 | get channels => _channels.value;
29 |
30 | // 选中的分类Code
31 | var _selCategoryCode = "".obs;
32 | set selCategoryCode(value) => _selCategoryCode.value = value;
33 | get selCategoryCode => _selCategoryCode.value;
34 | }
35 |
--------------------------------------------------------------------------------
/lib/pages/main/view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import 'index.dart';
5 | import 'widgets/widgets.dart';
6 |
7 | class MainPage extends GetView {
8 | @override
9 | Widget build(BuildContext context) {
10 | return SingleChildScrollView(
11 | child: Column(
12 | children: [
13 | NewsCategoriesWidget(),
14 | Divider(height: 1),
15 | NewsRecommendWidget(),
16 | Divider(height: 1),
17 | NewsChannelsWidget(),
18 | Divider(height: 1),
19 | NewsListWidget(),
20 | Divider(height: 1),
21 | NewsletterWidget(),
22 | ],
23 | ),
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/pages/main/widgets/ad.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/values/values.dart';
3 | import 'package:get/get.dart';
4 | import 'package:flutter_screenutil/flutter_screenutil.dart';
5 |
6 | import '../index.dart';
7 |
8 | /// ad广告
9 | class AdWidget extends GetView {
10 | @override
11 | Widget build(BuildContext context) {
12 | return Container(
13 | alignment: Alignment.center,
14 | height: 100.w,
15 | padding: EdgeInsets.all(20.w),
16 | child: Container(
17 | padding: EdgeInsets.symmetric(horizontal: 20.w),
18 | decoration: BoxDecoration(
19 | border: Border.fromBorderSide(Borders.primaryBorder),
20 | borderRadius: Radii.k6pxRadius,
21 | ),
22 | child: Column(
23 | mainAxisAlignment: MainAxisAlignment.center,
24 | children: [
25 | Text(
26 | "Tired of Ads? Get Premium - \$9.99",
27 | textAlign: TextAlign.center,
28 | style: TextStyle(
29 | color: AppColors.primaryText,
30 | fontFamily: "Avenir",
31 | fontWeight: FontWeight.w400,
32 | fontSize: 18.sp,
33 | height: 18.sp / 18,
34 | ),
35 | ),
36 | ],
37 | ),
38 | ),
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/pages/main/widgets/categories.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_ducafecat_news_getx/common/values/values.dart';
3 | import 'package:flutter_screenutil/flutter_screenutil.dart';
4 | import 'package:get/get.dart';
5 |
6 | import '../index.dart';
7 |
8 | /// 分类导航
9 | class NewsCategoriesWidget extends GetView {
10 | NewsCategoriesWidget();
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Obx(
15 | () => controller.state.categories == null
16 | ? Container()
17 | : SingleChildScrollView(
18 | scrollDirection: Axis.horizontal,
19 | child: Row(
20 | children: controller.state.categories.map((item) {
21 | return Container(
22 | alignment: Alignment.center,
23 | height: 52.h,
24 | padding: EdgeInsets.symmetric(horizontal: 8),
25 | child: GestureDetector(
26 | child: Text(
27 | item.title,
28 | style: TextStyle(
29 | color: controller.state.selCategoryCode == item.code
30 | ? AppColors.secondaryElementText
31 | : AppColors.primaryText,
32 | fontSize: 18.sp,
33 | fontFamily: 'Montserrat',
34 | fontWeight: FontWeight.w600,
35 | ),
36 | ),
37 | onTap: () {
38 | // 拉取数据
39 | controller.asyncLoadNewsData(item.code);
40 | },
41 | ),
42 | );
43 | }).toList(),
44 | ),
45 | ),
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/pages/main/widgets/newsletter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/gestures.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_ducafecat_news_getx/common/values/values.dart';
4 | import 'package:flutter_ducafecat_news_getx/common/widgets/widgets.dart';
5 | import 'package:flutter_screenutil/flutter_screenutil.dart';
6 | import 'package:get/get.dart';
7 |
8 | import '../index.dart';
9 |
10 | /// 邮件订阅
11 | class NewsletterWidget extends GetView {
12 | @override
13 | Widget build(BuildContext context) {
14 | return Container(
15 | margin: EdgeInsets.all(20.w),
16 | child: Column(
17 | children: [
18 | // newsletter
19 | Row(
20 | children: [
21 | Text(
22 | 'Newsletter',
23 | style: TextStyle(
24 | fontFamily: 'Montserrat',
25 | fontSize: 18.sp,
26 | fontWeight: FontWeight.w600,
27 | color: AppColors.thirdElement,
28 | ),
29 | ),
30 | Spacer(),
31 | IconButton(
32 | icon: Icon(
33 | Icons.close,
34 | color: AppColors.thirdElementText,
35 | size: 17.sp,
36 | ),
37 | onPressed: () {},
38 | ),
39 | ],
40 | ),
41 |
42 | // email
43 | inputEmailEdit(
44 | marginTop: 19,
45 | keyboardType: TextInputType.emailAddress,
46 | hintText: "Email",
47 | isPassword: false,
48 | controller: null,
49 | ),
50 |
51 | // btn subcrible
52 | Padding(
53 | padding: EdgeInsets.only(top: 15),
54 | child: btnFlatButtonWidget(
55 | onPressed: () {},
56 | width: 335.w,
57 | height: 44.h,
58 | fontWeight: FontWeight.w600,
59 | title: "Subscribe",
60 | ),
61 | ),
62 |
63 | // disc
64 | Container(
65 | margin: EdgeInsets.only(top: 29.h),
66 | width: 261.w,
67 | child: Text.rich(TextSpan(children: [
68 | TextSpan(
69 | text: 'By clicking on Subscribe button you agree to accept',
70 | style: new TextStyle(
71 | color: AppColors.thirdElementText,
72 | fontFamily: "Avenir",
73 | fontWeight: FontWeight.w400,
74 | fontSize: 14.sp,
75 | ),
76 | ),
77 | TextSpan(
78 | text: ' Privacy Policy',
79 | style: new TextStyle(
80 | color: AppColors.secondaryElementText,
81 | fontFamily: "Avenir",
82 | fontWeight: FontWeight.w400,
83 | fontSize: 14.sp,
84 | ),
85 | recognizer: TapGestureRecognizer()
86 | ..onTap = () {
87 | toastInfo(msg: 'Privacy Policy');
88 | },
89 | ),
90 | ])),
91 | ),
92 | ],
93 | ),
94 | );
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/lib/pages/main/widgets/widgets.dart:
--------------------------------------------------------------------------------
1 | library widgets;
2 |
3 | export './ad.dart';
4 | export './categories.dart';
5 | export './channels.dart';
6 | export 'news_list.dart';
7 | export './newsletter.dart';
8 | export './recommend.dart';
9 |
--------------------------------------------------------------------------------
/linux/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral
2 |
--------------------------------------------------------------------------------
/linux/flutter/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.10)
2 |
3 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
4 |
5 | # Configuration provided via flutter tool.
6 | include(${EPHEMERAL_DIR}/generated_config.cmake)
7 |
8 | # TODO: Move the rest of this into files in ephemeral. See
9 | # https://github.com/flutter/flutter/issues/57146.
10 |
11 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...),
12 | # which isn't available in 3.10.
13 | function(list_prepend LIST_NAME PREFIX)
14 | set(NEW_LIST "")
15 | foreach(element ${${LIST_NAME}})
16 | list(APPEND NEW_LIST "${PREFIX}${element}")
17 | endforeach(element)
18 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
19 | endfunction()
20 |
21 | # === Flutter Library ===
22 | # System-level dependencies.
23 | find_package(PkgConfig REQUIRED)
24 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
25 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
26 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
27 |
28 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
29 |
30 | # Published to parent scope for install step.
31 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
32 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
33 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
34 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
35 |
36 | list(APPEND FLUTTER_LIBRARY_HEADERS
37 | "fl_basic_message_channel.h"
38 | "fl_binary_codec.h"
39 | "fl_binary_messenger.h"
40 | "fl_dart_project.h"
41 | "fl_engine.h"
42 | "fl_json_message_codec.h"
43 | "fl_json_method_codec.h"
44 | "fl_message_codec.h"
45 | "fl_method_call.h"
46 | "fl_method_channel.h"
47 | "fl_method_codec.h"
48 | "fl_method_response.h"
49 | "fl_plugin_registrar.h"
50 | "fl_plugin_registry.h"
51 | "fl_standard_message_codec.h"
52 | "fl_standard_method_codec.h"
53 | "fl_string_codec.h"
54 | "fl_value.h"
55 | "fl_view.h"
56 | "flutter_linux.h"
57 | )
58 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
59 | add_library(flutter INTERFACE)
60 | target_include_directories(flutter INTERFACE
61 | "${EPHEMERAL_DIR}"
62 | )
63 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
64 | target_link_libraries(flutter INTERFACE
65 | PkgConfig::GTK
66 | PkgConfig::GLIB
67 | PkgConfig::GIO
68 | )
69 | add_dependencies(flutter flutter_assemble)
70 |
71 | # === Flutter tool backend ===
72 | # _phony_ is a non-existent file to force this command to run every time,
73 | # since currently there's no way to get a full input/output list from the
74 | # flutter tool.
75 | add_custom_command(
76 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
77 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_
78 | COMMAND ${CMAKE_COMMAND} -E env
79 | ${FLUTTER_TOOL_ENVIRONMENT}
80 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
81 | ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
82 | VERBATIM
83 | )
84 | add_custom_target(flutter_assemble DEPENDS
85 | "${FLUTTER_LIBRARY}"
86 | ${FLUTTER_LIBRARY_HEADERS}
87 | )
88 |
--------------------------------------------------------------------------------
/linux/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 |
10 | void fl_register_plugins(FlPluginRegistry* registry) {
11 | }
12 |
--------------------------------------------------------------------------------
/linux/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void fl_register_plugins(FlPluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/linux/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | )
7 |
8 | set(PLUGIN_BUNDLED_LIBRARIES)
9 |
10 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
11 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
12 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
13 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
14 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
15 | endforeach(plugin)
16 |
--------------------------------------------------------------------------------
/linux/main.cc:
--------------------------------------------------------------------------------
1 | #include "my_application.h"
2 |
3 | int main(int argc, char** argv) {
4 | g_autoptr(MyApplication) app = my_application_new();
5 | return g_application_run(G_APPLICATION(app), argc, argv);
6 | }
7 |
--------------------------------------------------------------------------------
/linux/my_application.cc:
--------------------------------------------------------------------------------
1 | #include "my_application.h"
2 |
3 | #include
4 | #ifdef GDK_WINDOWING_X11
5 | #include
6 | #endif
7 |
8 | #include "flutter/generated_plugin_registrant.h"
9 |
10 | struct _MyApplication {
11 | GtkApplication parent_instance;
12 | char** dart_entrypoint_arguments;
13 | };
14 |
15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
16 |
17 | // Implements GApplication::activate.
18 | static void my_application_activate(GApplication* application) {
19 | MyApplication* self = MY_APPLICATION(application);
20 | GtkWindow* window =
21 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
22 |
23 | // Use a header bar when running in GNOME as this is the common style used
24 | // by applications and is the setup most users will be using (e.g. Ubuntu
25 | // desktop).
26 | // If running on X and not using GNOME then just use a traditional title bar
27 | // in case the window manager does more exotic layout, e.g. tiling.
28 | // If running on Wayland assume the header bar will work (may need changing
29 | // if future cases occur).
30 | gboolean use_header_bar = TRUE;
31 | #ifdef GDK_WINDOWING_X11
32 | GdkScreen *screen = gtk_window_get_screen(window);
33 | if (GDK_IS_X11_SCREEN(screen)) {
34 | const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
35 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
36 | use_header_bar = FALSE;
37 | }
38 | }
39 | #endif
40 | if (use_header_bar) {
41 | GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
42 | gtk_widget_show(GTK_WIDGET(header_bar));
43 | gtk_header_bar_set_title(header_bar, "flutter_ducafecat_news_getx");
44 | gtk_header_bar_set_show_close_button(header_bar, TRUE);
45 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
46 | }
47 | else {
48 | gtk_window_set_title(window, "flutter_ducafecat_news_getx");
49 | }
50 |
51 | gtk_window_set_default_size(window, 1280, 720);
52 | gtk_widget_show(GTK_WIDGET(window));
53 |
54 | g_autoptr(FlDartProject) project = fl_dart_project_new();
55 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
56 |
57 | FlView* view = fl_view_new(project);
58 | gtk_widget_show(GTK_WIDGET(view));
59 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
60 |
61 | fl_register_plugins(FL_PLUGIN_REGISTRY(view));
62 |
63 | gtk_widget_grab_focus(GTK_WIDGET(view));
64 | }
65 |
66 | // Implements GApplication::local_command_line.
67 | static gboolean my_application_local_command_line(GApplication* application, gchar ***arguments, int *exit_status) {
68 | MyApplication* self = MY_APPLICATION(application);
69 | // Strip out the first argument as it is the binary name.
70 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
71 |
72 | g_autoptr(GError) error = nullptr;
73 | if (!g_application_register(application, nullptr, &error)) {
74 | g_warning("Failed to register: %s", error->message);
75 | *exit_status = 1;
76 | return TRUE;
77 | }
78 |
79 | g_application_activate(application);
80 | *exit_status = 0;
81 |
82 | return TRUE;
83 | }
84 |
85 | // Implements GObject::dispose.
86 | static void my_application_dispose(GObject *object) {
87 | MyApplication* self = MY_APPLICATION(object);
88 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
89 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
90 | }
91 |
92 | static void my_application_class_init(MyApplicationClass* klass) {
93 | G_APPLICATION_CLASS(klass)->activate = my_application_activate;
94 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
95 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
96 | }
97 |
98 | static void my_application_init(MyApplication* self) {}
99 |
100 | MyApplication* my_application_new() {
101 | return MY_APPLICATION(g_object_new(my_application_get_type(),
102 | "application-id", APPLICATION_ID,
103 | "flags", G_APPLICATION_NON_UNIQUE,
104 | nullptr));
105 | }
106 |
--------------------------------------------------------------------------------
/linux/my_application.h:
--------------------------------------------------------------------------------
1 | #ifndef FLUTTER_MY_APPLICATION_H_
2 | #define FLUTTER_MY_APPLICATION_H_
3 |
4 | #include
5 |
6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
7 | GtkApplication)
8 |
9 | /**
10 | * my_application_new:
11 | *
12 | * Creates a new Flutter-based application.
13 | *
14 | * Returns: a new #MyApplication.
15 | */
16 | MyApplication* my_application_new();
17 |
18 | #endif // FLUTTER_MY_APPLICATION_H_
19 |
--------------------------------------------------------------------------------
/macos/.gitignore:
--------------------------------------------------------------------------------
1 | # Flutter-related
2 | **/Flutter/ephemeral/
3 | **/Pods/
4 |
5 | # Xcode-related
6 | **/xcuserdata/
7 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Flutter/GeneratedPluginRegistrant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | import FlutterMacOS
6 | import Foundation
7 |
8 | import package_info
9 | import path_provider_macos
10 | import shared_preferences_macos
11 | import sqflite
12 |
13 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
14 | FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin"))
15 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
16 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
17 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
18 | }
19 |
--------------------------------------------------------------------------------
/macos/Podfile:
--------------------------------------------------------------------------------
1 | platform :osx, '10.11'
2 |
3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
5 |
6 | project 'Runner', {
7 | 'Debug' => :debug,
8 | 'Profile' => :release,
9 | 'Release' => :release,
10 | }
11 |
12 | def flutter_root
13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
14 | unless File.exist?(generated_xcode_build_settings_path)
15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
16 | end
17 |
18 | File.foreach(generated_xcode_build_settings_path) do |line|
19 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
20 | return matches[1].strip if matches
21 | end
22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
23 | end
24 |
25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
26 |
27 | flutter_macos_podfile_setup
28 |
29 | target 'Runner' do
30 | use_frameworks!
31 | use_modular_headers!
32 |
33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
34 | end
35 |
36 | post_install do |installer|
37 | installer.pods_project.targets.each do |target|
38 | flutter_additional_macos_build_settings(target)
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/macos/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - FlutterMacOS (1.0.0)
3 | - FMDB (2.7.5):
4 | - FMDB/standard (= 2.7.5)
5 | - FMDB/standard (2.7.5)
6 | - package_info (0.0.1):
7 | - FlutterMacOS
8 | - path_provider_macos (0.0.1):
9 | - FlutterMacOS
10 | - shared_preferences_macos (0.0.1):
11 | - FlutterMacOS
12 | - sqflite (0.0.2):
13 | - FlutterMacOS
14 | - FMDB (>= 2.7.5)
15 |
16 | DEPENDENCIES:
17 | - FlutterMacOS (from `Flutter/ephemeral`)
18 | - package_info (from `Flutter/ephemeral/.symlinks/plugins/package_info/macos`)
19 | - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
20 | - shared_preferences_macos (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos`)
21 | - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`)
22 |
23 | SPEC REPOS:
24 | trunk:
25 | - FMDB
26 |
27 | EXTERNAL SOURCES:
28 | FlutterMacOS:
29 | :path: Flutter/ephemeral
30 | package_info:
31 | :path: Flutter/ephemeral/.symlinks/plugins/package_info/macos
32 | path_provider_macos:
33 | :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
34 | shared_preferences_macos:
35 | :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos
36 | sqflite:
37 | :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos
38 |
39 | SPEC CHECKSUMS:
40 | FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
41 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
42 | package_info: 6eba2fd8d3371dda2d85c8db6fe97488f24b74b2
43 | path_provider_macos: a0a3fd666cb7cd0448e936fb4abad4052961002b
44 | shared_preferences_macos: 480ce071d0666e37cef23fe6c702293a3d21799e
45 | sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea
46 |
47 | PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c
48 |
49 | COCOAPODS: 1.11.2
50 |
--------------------------------------------------------------------------------
/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
64 |
65 |
71 |
73 |
79 |
80 |
81 |
82 |
84 |
85 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | @NSApplicationMain
5 | class AppDelegate: FlutterAppDelegate {
6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
7 | return true
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "app_icon_16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "app_icon_32.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "app_icon_32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "app_icon_64.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "app_icon_128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "app_icon_256.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "app_icon_256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "app_icon_512.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "app_icon_512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "512x512",
59 | "idiom" : "mac",
60 | "filename" : "app_icon_1024.png",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
--------------------------------------------------------------------------------
/macos/Runner/Configs/AppInfo.xcconfig:
--------------------------------------------------------------------------------
1 | // Application-level settings for the Runner target.
2 | //
3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
4 | // future. If not, the values below would default to using the project name when this becomes a
5 | // 'flutter create' template.
6 |
7 | // The application's name. By default this is also the title of the Flutter window.
8 | PRODUCT_NAME = flutter_ducafecat_news_getx
9 |
10 | // The application's bundle identifier
11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterDucafecatNewsGetx
12 |
13 | // The copyright displayed in application information
14 | PRODUCT_COPYRIGHT = Copyright © 2021 com.example. All rights reserved.
15 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Debug.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Release.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Warnings.xcconfig:
--------------------------------------------------------------------------------
1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
2 | GCC_WARN_UNDECLARED_SELECTOR = YES
3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
6 | CLANG_WARN_PRAGMA_PACK = YES
7 | CLANG_WARN_STRICT_PROTOTYPES = YES
8 | CLANG_WARN_COMMA = YES
9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES
10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
12 | GCC_WARN_SHADOW = YES
13 | CLANG_WARN_UNREACHABLE_CODE = YES
14 |
--------------------------------------------------------------------------------
/macos/Runner/DebugProfile.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.cs.allow-jit
8 |
9 | com.apple.security.network.server
10 |
11 | com.apple.security.network.client
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/macos/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | $(PRODUCT_COPYRIGHT)
27 | NSMainNibFile
28 | MainMenu
29 | NSPrincipalClass
30 | NSApplication
31 |
32 |
33 |
--------------------------------------------------------------------------------
/macos/Runner/MainFlutterWindow.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | class MainFlutterWindow: NSWindow {
5 | override func awakeFromNib() {
6 | let flutterViewController = FlutterViewController.init()
7 | let windowFrame = self.frame
8 | self.contentViewController = flutterViewController
9 | self.setFrame(windowFrame, display: true)
10 |
11 | RegisterGeneratedPlugins(registry: flutterViewController)
12 |
13 | super.awakeFromNib()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/macos/Runner/Release.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/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:flutter_ducafecat_news_getx/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/web/favicon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | flutter_ducafecat_news_getx
27 |
28 |
29 |
30 |
33 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "flutter_ducafecat_news_getx",
3 | "short_name": "flutter_ducafecat_news_getx",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/windows/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral/
2 |
3 | # Visual Studio user-specific files.
4 | *.suo
5 | *.user
6 | *.userosscache
7 | *.sln.docstates
8 |
9 | # Visual Studio build-related files.
10 | x64/
11 | x86/
12 |
13 | # Visual Studio cache files
14 | # files ending in .cache can be ignored
15 | *.[Cc]ache
16 | # but keep track of directories ending in .cache
17 | !*.[Cc]ache/
18 |
--------------------------------------------------------------------------------
/windows/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15)
2 | project(flutter_ducafecat_news_getx LANGUAGES CXX)
3 |
4 | set(BINARY_NAME "flutter_ducafecat_news_getx")
5 |
6 | cmake_policy(SET CMP0063 NEW)
7 |
8 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
9 |
10 | # Configure build options.
11 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
12 | if(IS_MULTICONFIG)
13 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
14 | CACHE STRING "" FORCE)
15 | else()
16 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
17 | set(CMAKE_BUILD_TYPE "Debug" CACHE
18 | STRING "Flutter build mode" FORCE)
19 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
20 | "Debug" "Profile" "Release")
21 | endif()
22 | endif()
23 |
24 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
25 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
26 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
27 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
28 |
29 | # Use Unicode for all projects.
30 | add_definitions(-DUNICODE -D_UNICODE)
31 |
32 | # Compilation settings that should be applied to most targets.
33 | function(APPLY_STANDARD_SETTINGS TARGET)
34 | target_compile_features(${TARGET} PUBLIC cxx_std_17)
35 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
36 | target_compile_options(${TARGET} PRIVATE /EHsc)
37 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
38 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>")
39 | endfunction()
40 |
41 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
42 |
43 | # Flutter library and tool build rules.
44 | add_subdirectory(${FLUTTER_MANAGED_DIR})
45 |
46 | # Application build
47 | add_subdirectory("runner")
48 |
49 | # Generated plugin build rules, which manage building the plugins and adding
50 | # them to the application.
51 | include(flutter/generated_plugins.cmake)
52 |
53 |
54 | # === Installation ===
55 | # Support files are copied into place next to the executable, so that it can
56 | # run in place. This is done instead of making a separate bundle (as on Linux)
57 | # so that building and running from within Visual Studio will work.
58 | set(BUILD_BUNDLE_DIR "$")
59 | # Make the "install" step default, as it's required to run.
60 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
61 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
62 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
63 | endif()
64 |
65 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
66 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
67 |
68 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
69 | COMPONENT Runtime)
70 |
71 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
72 | COMPONENT Runtime)
73 |
74 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
75 | COMPONENT Runtime)
76 |
77 | if(PLUGIN_BUNDLED_LIBRARIES)
78 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
79 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
80 | COMPONENT Runtime)
81 | endif()
82 |
83 | # Fully re-copy the assets directory on each build to avoid having stale files
84 | # from a previous install.
85 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
86 | install(CODE "
87 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
88 | " COMPONENT Runtime)
89 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
90 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
91 |
92 | # Install the AOT library on non-Debug builds only.
93 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
94 | CONFIGURATIONS Profile;Release
95 | COMPONENT Runtime)
96 |
--------------------------------------------------------------------------------
/windows/flutter/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15)
2 |
3 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
4 |
5 | # Configuration provided via flutter tool.
6 | include(${EPHEMERAL_DIR}/generated_config.cmake)
7 |
8 | # TODO: Move the rest of this into files in ephemeral. See
9 | # https://github.com/flutter/flutter/issues/57146.
10 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
11 |
12 | # === Flutter Library ===
13 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
14 |
15 | # Published to parent scope for install step.
16 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
17 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
18 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
19 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
20 |
21 | list(APPEND FLUTTER_LIBRARY_HEADERS
22 | "flutter_export.h"
23 | "flutter_windows.h"
24 | "flutter_messenger.h"
25 | "flutter_plugin_registrar.h"
26 | "flutter_texture_registrar.h"
27 | )
28 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
29 | add_library(flutter INTERFACE)
30 | target_include_directories(flutter INTERFACE
31 | "${EPHEMERAL_DIR}"
32 | )
33 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
34 | add_dependencies(flutter flutter_assemble)
35 |
36 | # === Wrapper ===
37 | list(APPEND CPP_WRAPPER_SOURCES_CORE
38 | "core_implementations.cc"
39 | "standard_codec.cc"
40 | )
41 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
42 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
43 | "plugin_registrar.cc"
44 | )
45 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
46 | list(APPEND CPP_WRAPPER_SOURCES_APP
47 | "flutter_engine.cc"
48 | "flutter_view_controller.cc"
49 | )
50 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
51 |
52 | # Wrapper sources needed for a plugin.
53 | add_library(flutter_wrapper_plugin STATIC
54 | ${CPP_WRAPPER_SOURCES_CORE}
55 | ${CPP_WRAPPER_SOURCES_PLUGIN}
56 | )
57 | apply_standard_settings(flutter_wrapper_plugin)
58 | set_target_properties(flutter_wrapper_plugin PROPERTIES
59 | POSITION_INDEPENDENT_CODE ON)
60 | set_target_properties(flutter_wrapper_plugin PROPERTIES
61 | CXX_VISIBILITY_PRESET hidden)
62 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
63 | target_include_directories(flutter_wrapper_plugin PUBLIC
64 | "${WRAPPER_ROOT}/include"
65 | )
66 | add_dependencies(flutter_wrapper_plugin flutter_assemble)
67 |
68 | # Wrapper sources needed for the runner.
69 | add_library(flutter_wrapper_app STATIC
70 | ${CPP_WRAPPER_SOURCES_CORE}
71 | ${CPP_WRAPPER_SOURCES_APP}
72 | )
73 | apply_standard_settings(flutter_wrapper_app)
74 | target_link_libraries(flutter_wrapper_app PUBLIC flutter)
75 | target_include_directories(flutter_wrapper_app PUBLIC
76 | "${WRAPPER_ROOT}/include"
77 | )
78 | add_dependencies(flutter_wrapper_app flutter_assemble)
79 |
80 | # === Flutter tool backend ===
81 | # _phony_ is a non-existent file to force this command to run every time,
82 | # since currently there's no way to get a full input/output list from the
83 | # flutter tool.
84 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
85 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
86 | add_custom_command(
87 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
88 | ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
89 | ${CPP_WRAPPER_SOURCES_APP}
90 | ${PHONY_OUTPUT}
91 | COMMAND ${CMAKE_COMMAND} -E env
92 | ${FLUTTER_TOOL_ENVIRONMENT}
93 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
94 | windows-x64 $
95 | VERBATIM
96 | )
97 | add_custom_target(flutter_assemble DEPENDS
98 | "${FLUTTER_LIBRARY}"
99 | ${FLUTTER_LIBRARY_HEADERS}
100 | ${CPP_WRAPPER_SOURCES_CORE}
101 | ${CPP_WRAPPER_SOURCES_PLUGIN}
102 | ${CPP_WRAPPER_SOURCES_APP}
103 | )
104 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 |
10 | void RegisterPlugins(flutter::PluginRegistry* registry) {
11 | }
12 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void RegisterPlugins(flutter::PluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | )
7 |
8 | set(PLUGIN_BUNDLED_LIBRARIES)
9 |
10 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
11 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
12 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
13 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
14 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
15 | endforeach(plugin)
16 |
--------------------------------------------------------------------------------
/windows/runner/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15)
2 | project(runner LANGUAGES CXX)
3 |
4 | add_executable(${BINARY_NAME} WIN32
5 | "flutter_window.cpp"
6 | "main.cpp"
7 | "utils.cpp"
8 | "win32_window.cpp"
9 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
10 | "Runner.rc"
11 | "runner.exe.manifest"
12 | )
13 | apply_standard_settings(${BINARY_NAME})
14 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
15 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
16 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
17 | add_dependencies(${BINARY_NAME} flutter_assemble)
18 |
--------------------------------------------------------------------------------
/windows/runner/Runner.rc:
--------------------------------------------------------------------------------
1 | // Microsoft Visual C++ generated resource script.
2 | //
3 | #pragma code_page(65001)
4 | #include "resource.h"
5 |
6 | #define APSTUDIO_READONLY_SYMBOLS
7 | /////////////////////////////////////////////////////////////////////////////
8 | //
9 | // Generated from the TEXTINCLUDE 2 resource.
10 | //
11 | #include "winres.h"
12 |
13 | /////////////////////////////////////////////////////////////////////////////
14 | #undef APSTUDIO_READONLY_SYMBOLS
15 |
16 | /////////////////////////////////////////////////////////////////////////////
17 | // English (United States) resources
18 |
19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
21 |
22 | #ifdef APSTUDIO_INVOKED
23 | /////////////////////////////////////////////////////////////////////////////
24 | //
25 | // TEXTINCLUDE
26 | //
27 |
28 | 1 TEXTINCLUDE
29 | BEGIN
30 | "resource.h\0"
31 | END
32 |
33 | 2 TEXTINCLUDE
34 | BEGIN
35 | "#include ""winres.h""\r\n"
36 | "\0"
37 | END
38 |
39 | 3 TEXTINCLUDE
40 | BEGIN
41 | "\r\n"
42 | "\0"
43 | END
44 |
45 | #endif // APSTUDIO_INVOKED
46 |
47 |
48 | /////////////////////////////////////////////////////////////////////////////
49 | //
50 | // Icon
51 | //
52 |
53 | // Icon with lowest ID value placed first to ensure application icon
54 | // remains consistent on all systems.
55 | IDI_APP_ICON ICON "resources\\app_icon.ico"
56 |
57 |
58 | /////////////////////////////////////////////////////////////////////////////
59 | //
60 | // Version
61 | //
62 |
63 | #ifdef FLUTTER_BUILD_NUMBER
64 | #define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER
65 | #else
66 | #define VERSION_AS_NUMBER 1,0,0
67 | #endif
68 |
69 | #ifdef FLUTTER_BUILD_NAME
70 | #define VERSION_AS_STRING #FLUTTER_BUILD_NAME
71 | #else
72 | #define VERSION_AS_STRING "1.0.0"
73 | #endif
74 |
75 | VS_VERSION_INFO VERSIONINFO
76 | FILEVERSION VERSION_AS_NUMBER
77 | PRODUCTVERSION VERSION_AS_NUMBER
78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
79 | #ifdef _DEBUG
80 | FILEFLAGS VS_FF_DEBUG
81 | #else
82 | FILEFLAGS 0x0L
83 | #endif
84 | FILEOS VOS__WINDOWS32
85 | FILETYPE VFT_APP
86 | FILESUBTYPE 0x0L
87 | BEGIN
88 | BLOCK "StringFileInfo"
89 | BEGIN
90 | BLOCK "040904e4"
91 | BEGIN
92 | VALUE "CompanyName", "com.example" "\0"
93 | VALUE "FileDescription", "A new Flutter project." "\0"
94 | VALUE "FileVersion", VERSION_AS_STRING "\0"
95 | VALUE "InternalName", "flutter_ducafecat_news_getx" "\0"
96 | VALUE "LegalCopyright", "Copyright (C) 2021 com.example. All rights reserved." "\0"
97 | VALUE "OriginalFilename", "flutter_ducafecat_news_getx.exe" "\0"
98 | VALUE "ProductName", "flutter_ducafecat_news_getx" "\0"
99 | VALUE "ProductVersion", VERSION_AS_STRING "\0"
100 | END
101 | END
102 | BLOCK "VarFileInfo"
103 | BEGIN
104 | VALUE "Translation", 0x409, 1252
105 | END
106 | END
107 |
108 | #endif // English (United States) resources
109 | /////////////////////////////////////////////////////////////////////////////
110 |
111 |
112 |
113 | #ifndef APSTUDIO_INVOKED
114 | /////////////////////////////////////////////////////////////////////////////
115 | //
116 | // Generated from the TEXTINCLUDE 3 resource.
117 | //
118 |
119 |
120 | /////////////////////////////////////////////////////////////////////////////
121 | #endif // not APSTUDIO_INVOKED
122 |
--------------------------------------------------------------------------------
/windows/runner/flutter_window.cpp:
--------------------------------------------------------------------------------
1 | #include "flutter_window.h"
2 |
3 | #include
4 |
5 | #include "flutter/generated_plugin_registrant.h"
6 |
7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project)
8 | : project_(project) {}
9 |
10 | FlutterWindow::~FlutterWindow() {}
11 |
12 | bool FlutterWindow::OnCreate() {
13 | if (!Win32Window::OnCreate()) {
14 | return false;
15 | }
16 |
17 | RECT frame = GetClientArea();
18 |
19 | // The size here must match the window dimensions to avoid unnecessary surface
20 | // creation / destruction in the startup path.
21 | flutter_controller_ = std::make_unique(
22 | frame.right - frame.left, frame.bottom - frame.top, project_);
23 | // Ensure that basic setup of the controller was successful.
24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) {
25 | return false;
26 | }
27 | RegisterPlugins(flutter_controller_->engine());
28 | SetChildContent(flutter_controller_->view()->GetNativeWindow());
29 | return true;
30 | }
31 |
32 | void FlutterWindow::OnDestroy() {
33 | if (flutter_controller_) {
34 | flutter_controller_ = nullptr;
35 | }
36 |
37 | Win32Window::OnDestroy();
38 | }
39 |
40 | LRESULT
41 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
42 | WPARAM const wparam,
43 | LPARAM const lparam) noexcept {
44 | // Give Flutter, including plugins, an opportunity to handle window messages.
45 | if (flutter_controller_) {
46 | std::optional result =
47 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
48 | lparam);
49 | if (result) {
50 | return *result;
51 | }
52 | }
53 |
54 | switch (message) {
55 | case WM_FONTCHANGE:
56 | flutter_controller_->engine()->ReloadSystemFonts();
57 | break;
58 | }
59 |
60 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
61 | }
62 |
--------------------------------------------------------------------------------
/windows/runner/flutter_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_FLUTTER_WINDOW_H_
2 | #define RUNNER_FLUTTER_WINDOW_H_
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | #include "win32_window.h"
10 |
11 | // A window that does nothing but host a Flutter view.
12 | class FlutterWindow : public Win32Window {
13 | public:
14 | // Creates a new FlutterWindow hosting a Flutter view running |project|.
15 | explicit FlutterWindow(const flutter::DartProject& project);
16 | virtual ~FlutterWindow();
17 |
18 | protected:
19 | // Win32Window:
20 | bool OnCreate() override;
21 | void OnDestroy() override;
22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
23 | LPARAM const lparam) noexcept override;
24 |
25 | private:
26 | // The project to run.
27 | flutter::DartProject project_;
28 |
29 | // The Flutter instance hosted by this window.
30 | std::unique_ptr flutter_controller_;
31 | };
32 |
33 | #endif // RUNNER_FLUTTER_WINDOW_H_
34 |
--------------------------------------------------------------------------------
/windows/runner/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "flutter_window.h"
6 | #include "utils.h"
7 |
8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
9 | _In_ wchar_t *command_line, _In_ int show_command) {
10 | // Attach to console when present (e.g., 'flutter run') or create a
11 | // new console when running with a debugger.
12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
13 | CreateAndAttachConsole();
14 | }
15 |
16 | // Initialize COM, so that it is available for use in the library and/or
17 | // plugins.
18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
19 |
20 | flutter::DartProject project(L"data");
21 |
22 | std::vector command_line_arguments =
23 | GetCommandLineArguments();
24 |
25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
26 |
27 | FlutterWindow window(project);
28 | Win32Window::Point origin(10, 10);
29 | Win32Window::Size size(1280, 720);
30 | if (!window.CreateAndShow(L"flutter_ducafecat_news_getx", origin, size)) {
31 | return EXIT_FAILURE;
32 | }
33 | window.SetQuitOnClose(true);
34 |
35 | ::MSG msg;
36 | while (::GetMessage(&msg, nullptr, 0, 0)) {
37 | ::TranslateMessage(&msg);
38 | ::DispatchMessage(&msg);
39 | }
40 |
41 | ::CoUninitialize();
42 | return EXIT_SUCCESS;
43 | }
44 |
--------------------------------------------------------------------------------
/windows/runner/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by Runner.rc
4 | //
5 | #define IDI_APP_ICON 101
6 |
7 | // Next default values for new objects
8 | //
9 | #ifdef APSTUDIO_INVOKED
10 | #ifndef APSTUDIO_READONLY_SYMBOLS
11 | #define _APS_NEXT_RESOURCE_VALUE 102
12 | #define _APS_NEXT_COMMAND_VALUE 40001
13 | #define _APS_NEXT_CONTROL_VALUE 1001
14 | #define _APS_NEXT_SYMED_VALUE 101
15 | #endif
16 | #endif
17 |
--------------------------------------------------------------------------------
/windows/runner/resources/app_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducafecat/flutter_ducafecat_news_getx/4147945837e655632530653ac8c864d68e1d2a68/windows/runner/resources/app_icon.ico
--------------------------------------------------------------------------------
/windows/runner/runner.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PerMonitorV2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/windows/runner/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | void CreateAndAttachConsole() {
11 | if (::AllocConsole()) {
12 | FILE *unused;
13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
14 | _dup2(_fileno(stdout), 1);
15 | }
16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
17 | _dup2(_fileno(stdout), 2);
18 | }
19 | std::ios::sync_with_stdio();
20 | FlutterDesktopResyncOutputStreams();
21 | }
22 | }
23 |
24 | std::vector GetCommandLineArguments() {
25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
26 | int argc;
27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
28 | if (argv == nullptr) {
29 | return std::vector();
30 | }
31 |
32 | std::vector command_line_arguments;
33 |
34 | // Skip the first argument as it's the binary name.
35 | for (int i = 1; i < argc; i++) {
36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
37 | }
38 |
39 | ::LocalFree(argv);
40 |
41 | return command_line_arguments;
42 | }
43 |
44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) {
45 | if (utf16_string == nullptr) {
46 | return std::string();
47 | }
48 | int target_length = ::WideCharToMultiByte(
49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
50 | -1, nullptr, 0, nullptr, nullptr);
51 | if (target_length == 0) {
52 | return std::string();
53 | }
54 | std::string utf8_string;
55 | utf8_string.resize(target_length);
56 | int converted_length = ::WideCharToMultiByte(
57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
58 | -1, utf8_string.data(),
59 | target_length, nullptr, nullptr);
60 | if (converted_length == 0) {
61 | return std::string();
62 | }
63 | return utf8_string;
64 | }
65 |
--------------------------------------------------------------------------------
/windows/runner/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_UTILS_H_
2 | #define RUNNER_UTILS_H_
3 |
4 | #include
5 | #include
6 |
7 | // Creates a console for the process, and redirects stdout and stderr to
8 | // it for both the runner and the Flutter library.
9 | void CreateAndAttachConsole();
10 |
11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
12 | // encoded in UTF-8. Returns an empty std::string on failure.
13 | std::string Utf8FromUtf16(const wchar_t* utf16_string);
14 |
15 | // Gets the command line arguments passed in as a std::vector,
16 | // encoded in UTF-8. Returns an empty std::vector on failure.
17 | std::vector GetCommandLineArguments();
18 |
19 | #endif // RUNNER_UTILS_H_
20 |
--------------------------------------------------------------------------------
/windows/runner/win32_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_WIN32_WINDOW_H_
2 | #define RUNNER_WIN32_WINDOW_H_
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be
11 | // inherited from by classes that wish to specialize with custom
12 | // rendering and input handling
13 | class Win32Window {
14 | public:
15 | struct Point {
16 | unsigned int x;
17 | unsigned int y;
18 | Point(unsigned int x, unsigned int y) : x(x), y(y) {}
19 | };
20 |
21 | struct Size {
22 | unsigned int width;
23 | unsigned int height;
24 | Size(unsigned int width, unsigned int height)
25 | : width(width), height(height) {}
26 | };
27 |
28 | Win32Window();
29 | virtual ~Win32Window();
30 |
31 | // Creates and shows a win32 window with |title| and position and size using
32 | // |origin| and |size|. New windows are created on the default monitor. Window
33 | // sizes are specified to the OS in physical pixels, hence to ensure a
34 | // consistent size to will treat the width height passed in to this function
35 | // as logical pixels and scale to appropriate for the default monitor. Returns
36 | // true if the window was created successfully.
37 | bool CreateAndShow(const std::wstring& title,
38 | const Point& origin,
39 | const Size& size);
40 |
41 | // Release OS resources associated with window.
42 | void Destroy();
43 |
44 | // Inserts |content| into the window tree.
45 | void SetChildContent(HWND content);
46 |
47 | // Returns the backing Window handle to enable clients to set icon and other
48 | // window properties. Returns nullptr if the window has been destroyed.
49 | HWND GetHandle();
50 |
51 | // If true, closing this window will quit the application.
52 | void SetQuitOnClose(bool quit_on_close);
53 |
54 | // Return a RECT representing the bounds of the current client area.
55 | RECT GetClientArea();
56 |
57 | protected:
58 | // Processes and route salient window messages for mouse handling,
59 | // size change and DPI. Delegates handling of these to member overloads that
60 | // inheriting classes can handle.
61 | virtual LRESULT MessageHandler(HWND window,
62 | UINT const message,
63 | WPARAM const wparam,
64 | LPARAM const lparam) noexcept;
65 |
66 | // Called when CreateAndShow is called, allowing subclass window-related
67 | // setup. Subclasses should return false if setup fails.
68 | virtual bool OnCreate();
69 |
70 | // Called when Destroy is called.
71 | virtual void OnDestroy();
72 |
73 | private:
74 | friend class WindowClassRegistrar;
75 |
76 | // OS callback called by message pump. Handles the WM_NCCREATE message which
77 | // is passed when the non-client area is being created and enables automatic
78 | // non-client DPI scaling so that the non-client area automatically
79 | // responsponds to changes in DPI. All other messages are handled by
80 | // MessageHandler.
81 | static LRESULT CALLBACK WndProc(HWND const window,
82 | UINT const message,
83 | WPARAM const wparam,
84 | LPARAM const lparam) noexcept;
85 |
86 | // Retrieves a class instance pointer for |window|
87 | static Win32Window* GetThisFromHandle(HWND const window) noexcept;
88 |
89 | bool quit_on_close_ = false;
90 |
91 | // window handle for top level window.
92 | HWND window_handle_ = nullptr;
93 |
94 | // window handle for hosted content.
95 | HWND child_content_ = nullptr;
96 | };
97 |
98 | #endif // RUNNER_WIN32_WINDOW_H_
99 |
--------------------------------------------------------------------------------