├── .flutter-plugins-dependencies
├── .gitignore
├── .metadata
├── README.md
├── android
├── .project
├── .settings
│ └── org.eclipse.buildship.core.prefs
├── app
│ ├── .classpath
│ ├── .project
│ ├── .settings
│ │ └── org.eclipse.buildship.core.prefs
│ ├── build.gradle
│ ├── google-services.json
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── douyin_demo
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── settings_aar.gradle
├── ios
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── 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
│ ├── GoogleService-Info .plist
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── lib
├── detector_painters.dart
├── images
│ ├── pingguo.jpeg
│ ├── sky.jpg
│ ├── temple.jpg
│ ├── waterdrop.jpg
│ ├── whitehouse.jpg
│ ├── woman.jpg
│ ├── woman2.jpg
│ └── zhifei.jpg
├── main.dart
├── models
│ ├── PostsModel.dart
│ └── PostsModel.g.dart
├── pages
│ ├── CameraPage
│ │ └── CameraMain.dart
│ ├── FaceDetect
│ │ └── FaceDetection.dart
│ ├── RecommendPage
│ │ ├── BottomSheet.dart
│ │ └── FriendList.dart
│ ├── loadData
│ │ └── loadData.dart
│ ├── sameCity
│ │ └── SameCityPage.dart
│ └── selfHome
│ │ └── HomePage.dart
├── providers
│ ├── AtUserProvider.dart
│ ├── CameraProvider.dart
│ ├── PostsGalleryProvider.dart
│ └── RecommendProvider.dart
├── utils.dart
└── widgets
│ ├── BottomBar.dart
│ ├── FavAnimation.dart
│ └── WebRequest.dart
├── pubspec.lock
├── pubspec.yaml
└── test
└── widget_test.dart
/.flutter-plugins-dependencies:
--------------------------------------------------------------------------------
1 | {"_info":"// This is a generated file; do not edit or check into version control.","dependencyGraph":[{"name":"camera","dependencies":[]},{"name":"firebase_ml_vision","dependencies":[]},{"name":"image_gallery_saver","dependencies":[]},{"name":"image_picker","dependencies":[]},{"name":"image_picker_saver","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"shared_preferences","dependencies":[]},{"name":"video_player","dependencies":[]}]}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .packages
28 | .pub-cache/
29 | .pub/
30 | /build/
31 |
32 | # Android related
33 | **/android/**/gradle-wrapper.jar
34 | **/android/.gradle
35 | **/android/captures/
36 | **/android/gradlew
37 | **/android/gradlew.bat
38 | **/android/local.properties
39 | **/android/**/GeneratedPluginRegistrant.java
40 |
41 | # iOS/XCode related
42 | **/ios/**/*.mode1v3
43 | **/ios/**/*.mode2v3
44 | **/ios/**/*.moved-aside
45 | **/ios/**/*.pbxuser
46 | **/ios/**/*.perspectivev3
47 | **/ios/**/*sync/
48 | **/ios/**/.sconsign.dblite
49 | **/ios/**/.tags*
50 | **/ios/**/.vagrant/
51 | **/ios/**/DerivedData/
52 | **/ios/**/Icon?
53 | **/ios/**/Pods/
54 | **/ios/**/.symlinks/
55 | **/ios/**/profile
56 | **/ios/**/xcuserdata
57 | **/ios/.generated/
58 | **/ios/Flutter/App.framework
59 | **/ios/Flutter/Flutter.framework
60 | **/ios/Flutter/Generated.xcconfig
61 | **/ios/Flutter/app.flx
62 | **/ios/Flutter/app.zip
63 | **/ios/Flutter/flutter_assets/
64 | **/ios/Flutter/flutter_export_environment.sh
65 | **/ios/ServiceDefinitions.json
66 | **/ios/Runner/GeneratedPluginRegistrant.*
67 |
68 | # Exceptions to above rules.
69 | !**/ios/**/default.mode1v3
70 | !**/ios/**/default.mode2v3
71 | !**/ios/**/default.pbxuser
72 | !**/ios/**/default.perspectivev3
73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
74 |
--------------------------------------------------------------------------------
/.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: 2d2a1ffec95cc70a3218872a2cd3f8de4933c42f
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # douyin_demo
2 |
3 | This is a Flutter project to copy Dou Yin (which named Tik Tok overseas).
4 | 这是一个利用Flutter复制抖音(海外叫做TikTok)的小项目。
5 |
6 | # Demo for the recommend page. 推荐页面效果图
7 | 
8 |
9 |
10 |
11 | ## Getting Started
12 |
13 | [Need to Know First]
14 | 【写在前面】
15 |
16 | This project is just for tutorial purpose, NO BUSINESS USING IS ALLOWED.
17 | 本项目只作教材使用,不允许有任何商业用途
18 |
19 | We are going to continously update the tutorial video synchronously on Bilibili.
If you want to learn more about Flutter and not just stop your pace at the elementary stage, this is a good choice for you to follow.(Oversea users? Don't worry, maybe we would update the same video on youtube, but you need to learn more about chinese first...)
20 | 我们将持续在Bilibili更新有关Flutter的教程视频,初步设想把抖音的大部分内容复制下来吧。。
如果你想学习更多与Flutter相关的内容,而不是听了一些基础课程就难以迈出下一步,那就来关注我们吧~括号里的我就不翻译了,反正呢。。youtube的事情咱也就瞎说的。
21 |
22 | # Bilibili space (Bilibili课程地址)
23 |
24 |
https://space.bilibili.com/283403747
25 |
26 | ## make a recommendPage for TikTok within 1 hour(1小时做个抖音推荐页)
27 | https://www.bilibili.com/video/av68733100
28 | 
29 |
30 | ## decorate the recommendPage to have a nice look (精修推荐页)
31 | https://www.bilibili.com/video/av68815634
32 | 
33 |
34 | continously updating (持续更新中...)
35 |
--------------------------------------------------------------------------------
/android/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | android
4 | Project android created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.buildship.core.gradleprojectbuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.buildship.core.gradleprojectnature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/android/.settings/org.eclipse.buildship.core.prefs:
--------------------------------------------------------------------------------
1 | connection.project.dir=
2 | eclipse.preferences.version=1
3 |
--------------------------------------------------------------------------------
/android/app/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/android/app/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | app
4 | Project app created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.buildship.core.gradleprojectbuilder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | org.eclipse.buildship.core.gradleprojectnature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/android/app/.settings/org.eclipse.buildship.core.prefs:
--------------------------------------------------------------------------------
1 | connection.project.dir=..
2 | eclipse.preferences.version=1
3 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 28
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
41 | applicationId "com.example.douyin_demo"
42 | minSdkVersion 21
43 | targetSdkVersion 28
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
47 | }
48 |
49 | buildTypes {
50 | release {
51 | // TODO: Add your own signing config for the release build.
52 | // Signing with the debug keys for now, so `flutter run --release` works.
53 | signingConfig signingConfigs.debug
54 | }
55 | }
56 | }
57 |
58 | flutter {
59 | source '../..'
60 | }
61 |
62 | dependencies {
63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
64 | testImplementation 'junit:junit:4.12'
65 | androidTestImplementation 'androidx.test:runner:1.1.0'
66 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
67 | implementation 'com.google.firebase:firebase-analytics:17.2.0'
68 | api 'com.google.firebase:firebase-ml-vision-image-label-model:17.0.2'
69 | api 'com.google.firebase:firebase-ml-vision-face-model:17.0.2'
70 | }
71 |
72 | apply plugin: 'com.google.gms.google-services'
73 |
--------------------------------------------------------------------------------
/android/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "416855912244",
4 | "firebase_url": "https://douyindemo.firebaseio.com",
5 | "project_id": "douyindemo",
6 | "storage_bucket": "douyindemo.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:416855912244:android:e38e3a5b3b0c678b2dff61",
12 | "android_client_info": {
13 | "package_name": "com.example.douyin_demo"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "416855912244-5avobokp2nrhk8bgrt0sodtjggorhr9k.apps.googleusercontent.com",
19 | "client_type": 3
20 | }
21 | ],
22 | "api_key": [
23 | {
24 | "current_key": "AIzaSyCtYf-GF_H8wDLD116rsudevTOkgzOaNEg"
25 | }
26 | ],
27 | "services": {
28 | "appinvite_service": {
29 | "other_platform_oauth_client": [
30 | {
31 | "client_id": "416855912244-5avobokp2nrhk8bgrt0sodtjggorhr9k.apps.googleusercontent.com",
32 | "client_type": 3
33 | },
34 | {
35 | "client_id": "416855912244-nqmupjevgtbf7ifcjfv42uocjdv5c77f.apps.googleusercontent.com",
36 | "client_type": 2,
37 | "ios_info": {
38 | "bundle_id": "com.example.douyinDemo"
39 | }
40 | }
41 | ]
42 | }
43 | }
44 | }
45 | ],
46 | "configuration_version": "1"
47 | }
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
13 |
20 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/douyin_demo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.douyin_demo
2 |
3 | import android.os.Bundle
4 |
5 | import io.flutter.app.FlutterActivity
6 | import io.flutter.plugins.GeneratedPluginRegistrant
7 |
8 | class MainActivity: FlutterActivity() {
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 | GeneratedPluginRegistrant.registerWith(this)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.2.71'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.2.1'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | classpath 'com.google.gms:google-services:4.2.0'
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | }
20 | }
21 |
22 | rootProject.buildDir = '../build'
23 | subprojects {
24 | project.buildDir = "${rootProject.buildDir}/${project.name}"
25 | }
26 | subprojects {
27 | project.evaluationDependsOn(':app')
28 | }
29 |
30 | subprojects {
31 | project.configurations.all {
32 | resolutionStrategy.eachDependency { details ->
33 | if (details.requested.group == 'androidx.exifinterface'
34 | && !details.requested.name.contains('multidex') ) {
35 | details.useVersion "1.0.0"
36 | }
37 | }
38 | }
39 | }
40 |
41 | subprojects {
42 | project.configurations.all {
43 | resolutionStrategy.eachDependency { details ->
44 | if (details.requested.group == 'androidx.core'
45 | && !details.requested.name.contains('multidex') ) {
46 | details.useVersion "1.0.2"
47 | }
48 | }
49 | }
50 | }
51 |
52 | task clean(type: Delete) {
53 | delete rootProject.buildDir
54 | }
55 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | android.enableJetifier=true
2 | android.useAndroidX=true
3 | org.gradle.jvmargs=-Xmx1536M
4 |
5 | android.enableR8=true
6 |
--------------------------------------------------------------------------------
/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-4.10.2-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/android/settings_aar.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Using a CDN with CocoaPods 1.7.2 or later can save a lot of time on pod installation, but it's experimental rather than the default.
2 | # source 'https://cdn.cocoapods.org/'
3 |
4 | # Uncomment this line to define a global platform for your project
5 | # platform :ios, '9.0'
6 |
7 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
8 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
9 |
10 | project 'Runner', {
11 | 'Debug' => :debug,
12 | 'Profile' => :release,
13 | 'Release' => :release,
14 | }
15 |
16 | pod 'Firebase/Analytics'
17 |
18 | def parse_KV_file(file, separator='=')
19 | file_abs_path = File.expand_path(file)
20 | if !File.exists? file_abs_path
21 | return [];
22 | end
23 | pods_ary = []
24 | skip_line_start_symbols = ["#", "/"]
25 | File.foreach(file_abs_path) { |line|
26 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
27 | plugin = line.split(pattern=separator)
28 | if plugin.length == 2
29 | podname = plugin[0].strip()
30 | path = plugin[1].strip()
31 | podpath = File.expand_path("#{path}", file_abs_path)
32 | pods_ary.push({:name => podname, :path => podpath});
33 | else
34 | puts "Invalid plugin specification: #{line}"
35 | end
36 | }
37 | return pods_ary
38 | end
39 |
40 | target 'Runner' do
41 |
42 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
43 | # referring to absolute paths on developers' machines.
44 | system('rm -rf .symlinks')
45 | system('mkdir -p .symlinks/plugins')
46 |
47 | # Flutter Pods
48 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
49 | if generated_xcode_build_settings.empty?
50 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first."
51 | end
52 | generated_xcode_build_settings.map { |p|
53 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
54 | symlink = File.join('.symlinks', 'flutter')
55 | File.symlink(File.dirname(p[:path]), symlink)
56 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
57 | end
58 | }
59 |
60 | # Plugin Pods
61 | plugin_pods = parse_KV_file('../.flutter-plugins')
62 | plugin_pods.map { |p|
63 | symlink = File.join('.symlinks', 'plugins', p[:name])
64 | File.symlink(p[:path], symlink)
65 | pod p[:name], :path => File.join(symlink, 'ios')
66 | }
67 | end
68 |
69 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
70 | install! 'cocoapods', :disable_input_output_paths => true
71 |
72 | post_install do |installer|
73 | installer.pods_project.targets.each do |target|
74 | target.build_configurations.each do |config|
75 | config.build_settings['ENABLE_BITCODE'] = 'NO'
76 | end
77 | end
78 | end
79 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - camera (0.0.1):
3 | - Flutter
4 | - Firebase/Analytics (6.11.0):
5 | - Firebase/Core
6 | - Firebase/Core (6.11.0):
7 | - Firebase/CoreOnly
8 | - FirebaseAnalytics (= 6.1.3)
9 | - Firebase/CoreOnly (6.11.0):
10 | - FirebaseCore (= 6.3.2)
11 | - FirebaseAnalytics (6.1.3):
12 | - FirebaseCore (~> 6.3)
13 | - FirebaseInstanceID (~> 4.2)
14 | - GoogleAppMeasurement (= 6.1.3)
15 | - GoogleUtilities/AppDelegateSwizzler (~> 6.0)
16 | - GoogleUtilities/MethodSwizzler (~> 6.0)
17 | - GoogleUtilities/Network (~> 6.0)
18 | - "GoogleUtilities/NSData+zlib (~> 6.0)"
19 | - nanopb (~> 0.3.901)
20 | - FirebaseCore (6.3.2):
21 | - FirebaseCoreDiagnostics (~> 1.0)
22 | - FirebaseCoreDiagnosticsInterop (~> 1.0)
23 | - GoogleUtilities/Environment (~> 6.2)
24 | - GoogleUtilities/Logger (~> 6.2)
25 | - FirebaseCoreDiagnostics (1.1.1):
26 | - FirebaseCoreDiagnosticsInterop (~> 1.0)
27 | - GoogleDataTransportCCTSupport (~> 1.0)
28 | - GoogleUtilities/Environment (~> 6.2)
29 | - GoogleUtilities/Logger (~> 6.2)
30 | - nanopb (~> 0.3.901)
31 | - FirebaseCoreDiagnosticsInterop (1.0.0)
32 | - FirebaseInstanceID (4.2.6):
33 | - FirebaseCore (~> 6.0)
34 | - GoogleUtilities/Environment (~> 6.0)
35 | - GoogleUtilities/UserDefaults (~> 6.0)
36 | - Flutter (1.0.0)
37 | - GoogleAppMeasurement (6.1.3):
38 | - GoogleUtilities/AppDelegateSwizzler (~> 6.0)
39 | - GoogleUtilities/MethodSwizzler (~> 6.0)
40 | - GoogleUtilities/Network (~> 6.0)
41 | - "GoogleUtilities/NSData+zlib (~> 6.0)"
42 | - nanopb (~> 0.3.901)
43 | - GoogleDataTransport (3.0.1)
44 | - GoogleDataTransportCCTSupport (1.2.1):
45 | - GoogleDataTransport (~> 3.0)
46 | - nanopb (~> 0.3.901)
47 | - GoogleUtilities/AppDelegateSwizzler (6.3.1):
48 | - GoogleUtilities/Environment
49 | - GoogleUtilities/Logger
50 | - GoogleUtilities/Network
51 | - GoogleUtilities/Environment (6.3.1)
52 | - GoogleUtilities/Logger (6.3.1):
53 | - GoogleUtilities/Environment
54 | - GoogleUtilities/MethodSwizzler (6.3.1):
55 | - GoogleUtilities/Logger
56 | - GoogleUtilities/Network (6.3.1):
57 | - GoogleUtilities/Logger
58 | - "GoogleUtilities/NSData+zlib"
59 | - GoogleUtilities/Reachability
60 | - "GoogleUtilities/NSData+zlib (6.3.1)"
61 | - GoogleUtilities/Reachability (6.3.1):
62 | - GoogleUtilities/Logger
63 | - GoogleUtilities/UserDefaults (6.3.1):
64 | - GoogleUtilities/Logger
65 | - image_gallery_saver (0.0.1):
66 | - Flutter
67 | - image_picker_saver (0.0.1):
68 | - Flutter
69 | - nanopb (0.3.904):
70 | - nanopb/decode (= 0.3.904)
71 | - nanopb/encode (= 0.3.904)
72 | - nanopb/decode (0.3.904)
73 | - nanopb/encode (0.3.904)
74 | - path_provider (0.0.1):
75 | - Flutter
76 | - shared_preferences (0.0.1):
77 | - Flutter
78 | - video_player (0.0.1):
79 | - Flutter
80 |
81 | DEPENDENCIES:
82 | - camera (from `.symlinks/plugins/camera/ios`)
83 | - Firebase/Analytics
84 | - Flutter (from `.symlinks/flutter/ios`)
85 | - image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`)
86 | - image_picker_saver (from `.symlinks/plugins/image_picker_saver/ios`)
87 | - path_provider (from `.symlinks/plugins/path_provider/ios`)
88 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
89 | - video_player (from `.symlinks/plugins/video_player/ios`)
90 |
91 | SPEC REPOS:
92 | trunk:
93 | - Firebase
94 | - FirebaseAnalytics
95 | - FirebaseCore
96 | - FirebaseCoreDiagnostics
97 | - FirebaseCoreDiagnosticsInterop
98 | - FirebaseInstanceID
99 | - GoogleAppMeasurement
100 | - GoogleDataTransport
101 | - GoogleDataTransportCCTSupport
102 | - GoogleUtilities
103 | - nanopb
104 |
105 | EXTERNAL SOURCES:
106 | camera:
107 | :path: ".symlinks/plugins/camera/ios"
108 | Flutter:
109 | :path: ".symlinks/flutter/ios"
110 | image_gallery_saver:
111 | :path: ".symlinks/plugins/image_gallery_saver/ios"
112 | image_picker_saver:
113 | :path: ".symlinks/plugins/image_picker_saver/ios"
114 | path_provider:
115 | :path: ".symlinks/plugins/path_provider/ios"
116 | shared_preferences:
117 | :path: ".symlinks/plugins/shared_preferences/ios"
118 | video_player:
119 | :path: ".symlinks/plugins/video_player/ios"
120 |
121 | SPEC CHECKSUMS:
122 | camera: 38cc83ae9a5667bb5a71c7d9edaf60a91920fd4e
123 | Firebase: bc9cfc7a96c73268656d5aaab453ff1b4b530e0e
124 | FirebaseAnalytics: 0e3ecff2c5d86070f7d4325e21f1edabfbd558dc
125 | FirebaseCore: beeff42c07c30ea94702471d99db2089b594fbbd
126 | FirebaseCoreDiagnostics: af29e43048607588c050889d19204f4d7b758c9f
127 | FirebaseCoreDiagnosticsInterop: 6829da2b8d1fc795ff1bd99df751d3788035d2cb
128 | FirebaseInstanceID: d0eafcd8bdbd3447cd694594734078c3e3e77d8b
129 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
130 | GoogleAppMeasurement: 434cc7be25e71dc04b8d0e3079125127b330e84a
131 | GoogleDataTransport: 166f9b9f82cbf60a204e8fe2daa9db3e3ec1fb15
132 | GoogleDataTransportCCTSupport: f6ab1962e9dc05ab1fb938b795e5b310209edeec
133 | GoogleUtilities: f895fde57977df4e0233edda0dbeac490e3703b6
134 | image_gallery_saver: 73b3cd8ad9c950c739878af9c311744d1bf5405d
135 | image_picker_saver: 4f28bd70e1efdca68ad88beab0f11d22cffe04f6
136 | nanopb: 06f6030d554e6473f5e172460173fcf80f5548f4
137 | path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d
138 | shared_preferences: 1feebfa37bb57264736e16865e7ffae7fc99b523
139 | video_player: 3964090a33353060ed7f58aa6427c7b4b208ec21
140 |
141 | PODFILE CHECKSUM: 4f0d2701c4ba58cfe1b30e95dda891f7c336a7fe
142 |
143 | COCOAPODS: 1.8.3
144 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 362629AB2361F7C300E3C8A6 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 362629AA2361F7C300E3C8A6 /* GoogleService-Info.plist */; };
12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
13 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
14 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
15 | 604C5850D878DB6F044AEF77 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 722C26CDBD3C591472F82773 /* Pods_Runner.framework */; };
16 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
17 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
18 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
19 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
20 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
21 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
22 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
23 | /* End PBXBuildFile section */
24 |
25 | /* Begin PBXCopyFilesBuildPhase section */
26 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
27 | isa = PBXCopyFilesBuildPhase;
28 | buildActionMask = 2147483647;
29 | dstPath = "";
30 | dstSubfolderSpec = 10;
31 | files = (
32 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
33 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
34 | );
35 | name = "Embed Frameworks";
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXCopyFilesBuildPhase section */
39 |
40 | /* Begin PBXFileReference section */
41 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
42 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
43 | 1D316F3E638415790BE1439B /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
44 | 362629AA2361F7C300E3C8A6 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../../../Downloads/GoogleService-Info.plist"; sourceTree = ""; };
45 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
46 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
47 | 4019BE41A61CCF7EF6BB2649 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
48 | 54C773278ECE4CC8A8870A9C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
49 | 722C26CDBD3C591472F82773 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
50 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
51 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
52 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
53 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
54 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
55 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
56 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
57 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
58 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
59 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
60 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
61 | /* End PBXFileReference section */
62 |
63 | /* Begin PBXFrameworksBuildPhase section */
64 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
65 | isa = PBXFrameworksBuildPhase;
66 | buildActionMask = 2147483647;
67 | files = (
68 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
69 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
70 | 604C5850D878DB6F044AEF77 /* Pods_Runner.framework in Frameworks */,
71 | );
72 | runOnlyForDeploymentPostprocessing = 0;
73 | };
74 | /* End PBXFrameworksBuildPhase section */
75 |
76 | /* Begin PBXGroup section */
77 | 8423D0A36C799C525D07A0EF /* Frameworks */ = {
78 | isa = PBXGroup;
79 | children = (
80 | 722C26CDBD3C591472F82773 /* Pods_Runner.framework */,
81 | );
82 | name = Frameworks;
83 | sourceTree = "";
84 | };
85 | 9740EEB11CF90186004384FC /* Flutter */ = {
86 | isa = PBXGroup;
87 | children = (
88 | 3B80C3931E831B6300D905FE /* App.framework */,
89 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
90 | 9740EEBA1CF902C7004384FC /* Flutter.framework */,
91 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
92 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
93 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
94 | );
95 | name = Flutter;
96 | sourceTree = "";
97 | };
98 | 97C146E51CF9000F007C117D = {
99 | isa = PBXGroup;
100 | children = (
101 | 9740EEB11CF90186004384FC /* Flutter */,
102 | 97C146F01CF9000F007C117D /* Runner */,
103 | 97C146EF1CF9000F007C117D /* Products */,
104 | CDEBBB0FDF15C16076542746 /* Pods */,
105 | 8423D0A36C799C525D07A0EF /* Frameworks */,
106 | );
107 | sourceTree = "";
108 | };
109 | 97C146EF1CF9000F007C117D /* Products */ = {
110 | isa = PBXGroup;
111 | children = (
112 | 97C146EE1CF9000F007C117D /* Runner.app */,
113 | );
114 | name = Products;
115 | sourceTree = "";
116 | };
117 | 97C146F01CF9000F007C117D /* Runner */ = {
118 | isa = PBXGroup;
119 | children = (
120 | 362629AA2361F7C300E3C8A6 /* GoogleService-Info.plist */,
121 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
122 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
123 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
124 | 97C147021CF9000F007C117D /* Info.plist */,
125 | 97C146F11CF9000F007C117D /* Supporting Files */,
126 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
127 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
128 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
129 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
130 | );
131 | path = Runner;
132 | sourceTree = "";
133 | };
134 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
135 | isa = PBXGroup;
136 | children = (
137 | );
138 | name = "Supporting Files";
139 | sourceTree = "";
140 | };
141 | CDEBBB0FDF15C16076542746 /* Pods */ = {
142 | isa = PBXGroup;
143 | children = (
144 | 4019BE41A61CCF7EF6BB2649 /* Pods-Runner.debug.xcconfig */,
145 | 1D316F3E638415790BE1439B /* Pods-Runner.release.xcconfig */,
146 | 54C773278ECE4CC8A8870A9C /* Pods-Runner.profile.xcconfig */,
147 | );
148 | path = Pods;
149 | sourceTree = "";
150 | };
151 | /* End PBXGroup section */
152 |
153 | /* Begin PBXNativeTarget section */
154 | 97C146ED1CF9000F007C117D /* Runner */ = {
155 | isa = PBXNativeTarget;
156 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
157 | buildPhases = (
158 | E7D294A0D6B8678EA525B583 /* [CP] Check Pods Manifest.lock */,
159 | 9740EEB61CF901F6004384FC /* Run Script */,
160 | 97C146EA1CF9000F007C117D /* Sources */,
161 | 97C146EB1CF9000F007C117D /* Frameworks */,
162 | 97C146EC1CF9000F007C117D /* Resources */,
163 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
164 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
165 | E25D9A001ACCDFBD9456B371 /* [CP] Embed Pods Frameworks */,
166 | );
167 | buildRules = (
168 | );
169 | dependencies = (
170 | );
171 | name = Runner;
172 | productName = Runner;
173 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
174 | productType = "com.apple.product-type.application";
175 | };
176 | /* End PBXNativeTarget section */
177 |
178 | /* Begin PBXProject section */
179 | 97C146E61CF9000F007C117D /* Project object */ = {
180 | isa = PBXProject;
181 | attributes = {
182 | LastUpgradeCheck = 1020;
183 | ORGANIZATIONNAME = "The Chromium Authors";
184 | TargetAttributes = {
185 | 97C146ED1CF9000F007C117D = {
186 | CreatedOnToolsVersion = 7.3.1;
187 | DevelopmentTeam = 7DFM6K6KA8;
188 | LastSwiftMigration = 0910;
189 | };
190 | };
191 | };
192 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
193 | compatibilityVersion = "Xcode 3.2";
194 | developmentRegion = en;
195 | hasScannedForEncodings = 0;
196 | knownRegions = (
197 | en,
198 | Base,
199 | );
200 | mainGroup = 97C146E51CF9000F007C117D;
201 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
202 | projectDirPath = "";
203 | projectRoot = "";
204 | targets = (
205 | 97C146ED1CF9000F007C117D /* Runner */,
206 | );
207 | };
208 | /* End PBXProject section */
209 |
210 | /* Begin PBXResourcesBuildPhase section */
211 | 97C146EC1CF9000F007C117D /* Resources */ = {
212 | isa = PBXResourcesBuildPhase;
213 | buildActionMask = 2147483647;
214 | files = (
215 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
216 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
217 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
218 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
219 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
220 | 362629AB2361F7C300E3C8A6 /* GoogleService-Info.plist in Resources */,
221 | );
222 | runOnlyForDeploymentPostprocessing = 0;
223 | };
224 | /* End PBXResourcesBuildPhase section */
225 |
226 | /* Begin PBXShellScriptBuildPhase section */
227 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
228 | isa = PBXShellScriptBuildPhase;
229 | buildActionMask = 2147483647;
230 | files = (
231 | );
232 | inputPaths = (
233 | );
234 | name = "Thin Binary";
235 | outputPaths = (
236 | );
237 | runOnlyForDeploymentPostprocessing = 0;
238 | shellPath = /bin/sh;
239 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
240 | };
241 | 9740EEB61CF901F6004384FC /* Run Script */ = {
242 | isa = PBXShellScriptBuildPhase;
243 | buildActionMask = 2147483647;
244 | files = (
245 | );
246 | inputPaths = (
247 | );
248 | name = "Run Script";
249 | outputPaths = (
250 | );
251 | runOnlyForDeploymentPostprocessing = 0;
252 | shellPath = /bin/sh;
253 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
254 | };
255 | E25D9A001ACCDFBD9456B371 /* [CP] Embed Pods Frameworks */ = {
256 | isa = PBXShellScriptBuildPhase;
257 | buildActionMask = 2147483647;
258 | files = (
259 | );
260 | inputPaths = (
261 | );
262 | name = "[CP] Embed Pods Frameworks";
263 | outputPaths = (
264 | );
265 | runOnlyForDeploymentPostprocessing = 0;
266 | shellPath = /bin/sh;
267 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
268 | showEnvVarsInLog = 0;
269 | };
270 | E7D294A0D6B8678EA525B583 /* [CP] Check Pods Manifest.lock */ = {
271 | isa = PBXShellScriptBuildPhase;
272 | buildActionMask = 2147483647;
273 | files = (
274 | );
275 | inputFileListPaths = (
276 | );
277 | inputPaths = (
278 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
279 | "${PODS_ROOT}/Manifest.lock",
280 | );
281 | name = "[CP] Check Pods Manifest.lock";
282 | outputFileListPaths = (
283 | );
284 | outputPaths = (
285 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
286 | );
287 | runOnlyForDeploymentPostprocessing = 0;
288 | shellPath = /bin/sh;
289 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
290 | showEnvVarsInLog = 0;
291 | };
292 | /* End PBXShellScriptBuildPhase section */
293 |
294 | /* Begin PBXSourcesBuildPhase section */
295 | 97C146EA1CF9000F007C117D /* Sources */ = {
296 | isa = PBXSourcesBuildPhase;
297 | buildActionMask = 2147483647;
298 | files = (
299 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
300 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
301 | );
302 | runOnlyForDeploymentPostprocessing = 0;
303 | };
304 | /* End PBXSourcesBuildPhase section */
305 |
306 | /* Begin PBXVariantGroup section */
307 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
308 | isa = PBXVariantGroup;
309 | children = (
310 | 97C146FB1CF9000F007C117D /* Base */,
311 | );
312 | name = Main.storyboard;
313 | sourceTree = "";
314 | };
315 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
316 | isa = PBXVariantGroup;
317 | children = (
318 | 97C147001CF9000F007C117D /* Base */,
319 | );
320 | name = LaunchScreen.storyboard;
321 | sourceTree = "";
322 | };
323 | /* End PBXVariantGroup section */
324 |
325 | /* Begin XCBuildConfiguration section */
326 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
327 | isa = XCBuildConfiguration;
328 | buildSettings = {
329 | ALWAYS_SEARCH_USER_PATHS = NO;
330 | CLANG_ANALYZER_NONNULL = YES;
331 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
332 | CLANG_CXX_LIBRARY = "libc++";
333 | CLANG_ENABLE_MODULES = YES;
334 | CLANG_ENABLE_OBJC_ARC = YES;
335 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
336 | CLANG_WARN_BOOL_CONVERSION = YES;
337 | CLANG_WARN_COMMA = YES;
338 | CLANG_WARN_CONSTANT_CONVERSION = YES;
339 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
340 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
341 | CLANG_WARN_EMPTY_BODY = YES;
342 | CLANG_WARN_ENUM_CONVERSION = YES;
343 | CLANG_WARN_INFINITE_RECURSION = YES;
344 | CLANG_WARN_INT_CONVERSION = YES;
345 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
346 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
347 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
348 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
349 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
350 | CLANG_WARN_STRICT_PROTOTYPES = YES;
351 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
352 | CLANG_WARN_UNREACHABLE_CODE = YES;
353 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
354 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
355 | COPY_PHASE_STRIP = NO;
356 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
357 | ENABLE_NS_ASSERTIONS = NO;
358 | ENABLE_STRICT_OBJC_MSGSEND = YES;
359 | GCC_C_LANGUAGE_STANDARD = gnu99;
360 | GCC_NO_COMMON_BLOCKS = YES;
361 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
362 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
363 | GCC_WARN_UNDECLARED_SELECTOR = YES;
364 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
365 | GCC_WARN_UNUSED_FUNCTION = YES;
366 | GCC_WARN_UNUSED_VARIABLE = YES;
367 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
368 | MTL_ENABLE_DEBUG_INFO = NO;
369 | SDKROOT = iphoneos;
370 | TARGETED_DEVICE_FAMILY = "1,2";
371 | VALIDATE_PRODUCT = YES;
372 | };
373 | name = Profile;
374 | };
375 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
376 | isa = XCBuildConfiguration;
377 | baseConfigurationReference = 54C773278ECE4CC8A8870A9C /* Pods-Runner.profile.xcconfig */;
378 | buildSettings = {
379 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
380 | CLANG_ENABLE_MODULES = YES;
381 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
382 | DEVELOPMENT_TEAM = 7DFM6K6KA8;
383 | ENABLE_BITCODE = NO;
384 | FLUTTER_ROOT = $HOME/development/flutter;
385 | FRAMEWORK_SEARCH_PATHS = (
386 | "$(inherited)",
387 | "$(PROJECT_DIR)/Flutter",
388 | );
389 | INFOPLIST_FILE = Runner/Info.plist;
390 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
391 | LIBRARY_SEARCH_PATHS = (
392 | "$(inherited)",
393 | "$(PROJECT_DIR)/Flutter",
394 | );
395 | PODS_BUILD_DIR = "$(inherited)";
396 | PRODUCT_BUNDLE_IDENTIFIER = com.example.douyinDemo;
397 | PRODUCT_NAME = "$(TARGET_NAME)";
398 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
399 | SWIFT_VERSION = 4.0;
400 | VERSIONING_SYSTEM = "apple-generic";
401 | };
402 | name = Profile;
403 | };
404 | 97C147031CF9000F007C117D /* Debug */ = {
405 | isa = XCBuildConfiguration;
406 | buildSettings = {
407 | ALWAYS_SEARCH_USER_PATHS = NO;
408 | CLANG_ANALYZER_NONNULL = YES;
409 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
410 | CLANG_CXX_LIBRARY = "libc++";
411 | CLANG_ENABLE_MODULES = YES;
412 | CLANG_ENABLE_OBJC_ARC = YES;
413 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
414 | CLANG_WARN_BOOL_CONVERSION = YES;
415 | CLANG_WARN_COMMA = YES;
416 | CLANG_WARN_CONSTANT_CONVERSION = YES;
417 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
418 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
419 | CLANG_WARN_EMPTY_BODY = YES;
420 | CLANG_WARN_ENUM_CONVERSION = YES;
421 | CLANG_WARN_INFINITE_RECURSION = YES;
422 | CLANG_WARN_INT_CONVERSION = YES;
423 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
424 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
425 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
426 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
427 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
428 | CLANG_WARN_STRICT_PROTOTYPES = YES;
429 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
430 | CLANG_WARN_UNREACHABLE_CODE = YES;
431 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
432 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
433 | COPY_PHASE_STRIP = NO;
434 | DEBUG_INFORMATION_FORMAT = dwarf;
435 | ENABLE_STRICT_OBJC_MSGSEND = YES;
436 | ENABLE_TESTABILITY = YES;
437 | GCC_C_LANGUAGE_STANDARD = gnu99;
438 | GCC_DYNAMIC_NO_PIC = NO;
439 | GCC_NO_COMMON_BLOCKS = YES;
440 | GCC_OPTIMIZATION_LEVEL = 0;
441 | GCC_PREPROCESSOR_DEFINITIONS = (
442 | "DEBUG=1",
443 | "$(inherited)",
444 | );
445 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
446 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
447 | GCC_WARN_UNDECLARED_SELECTOR = YES;
448 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
449 | GCC_WARN_UNUSED_FUNCTION = YES;
450 | GCC_WARN_UNUSED_VARIABLE = YES;
451 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
452 | MTL_ENABLE_DEBUG_INFO = YES;
453 | ONLY_ACTIVE_ARCH = YES;
454 | SDKROOT = iphoneos;
455 | TARGETED_DEVICE_FAMILY = "1,2";
456 | };
457 | name = Debug;
458 | };
459 | 97C147041CF9000F007C117D /* Release */ = {
460 | isa = XCBuildConfiguration;
461 | buildSettings = {
462 | ALWAYS_SEARCH_USER_PATHS = NO;
463 | CLANG_ANALYZER_NONNULL = YES;
464 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
465 | CLANG_CXX_LIBRARY = "libc++";
466 | CLANG_ENABLE_MODULES = YES;
467 | CLANG_ENABLE_OBJC_ARC = YES;
468 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
469 | CLANG_WARN_BOOL_CONVERSION = YES;
470 | CLANG_WARN_COMMA = YES;
471 | CLANG_WARN_CONSTANT_CONVERSION = YES;
472 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
473 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
474 | CLANG_WARN_EMPTY_BODY = YES;
475 | CLANG_WARN_ENUM_CONVERSION = YES;
476 | CLANG_WARN_INFINITE_RECURSION = YES;
477 | CLANG_WARN_INT_CONVERSION = YES;
478 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
479 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
480 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
481 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
482 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
483 | CLANG_WARN_STRICT_PROTOTYPES = YES;
484 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
485 | CLANG_WARN_UNREACHABLE_CODE = YES;
486 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
487 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
488 | COPY_PHASE_STRIP = NO;
489 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
490 | ENABLE_NS_ASSERTIONS = NO;
491 | ENABLE_STRICT_OBJC_MSGSEND = YES;
492 | GCC_C_LANGUAGE_STANDARD = gnu99;
493 | GCC_NO_COMMON_BLOCKS = YES;
494 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
495 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
496 | GCC_WARN_UNDECLARED_SELECTOR = YES;
497 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
498 | GCC_WARN_UNUSED_FUNCTION = YES;
499 | GCC_WARN_UNUSED_VARIABLE = YES;
500 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
501 | MTL_ENABLE_DEBUG_INFO = NO;
502 | SDKROOT = iphoneos;
503 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
504 | TARGETED_DEVICE_FAMILY = "1,2";
505 | VALIDATE_PRODUCT = YES;
506 | };
507 | name = Release;
508 | };
509 | 97C147061CF9000F007C117D /* Debug */ = {
510 | isa = XCBuildConfiguration;
511 | baseConfigurationReference = 4019BE41A61CCF7EF6BB2649 /* Pods-Runner.debug.xcconfig */;
512 | buildSettings = {
513 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
514 | CLANG_ENABLE_MODULES = YES;
515 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
516 | DEVELOPMENT_TEAM = 7DFM6K6KA8;
517 | ENABLE_BITCODE = NO;
518 | FLUTTER_ROOT = $HOME/development/flutter;
519 | FRAMEWORK_SEARCH_PATHS = (
520 | "$(inherited)",
521 | "$(PROJECT_DIR)/Flutter",
522 | );
523 | INFOPLIST_FILE = Runner/Info.plist;
524 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
525 | LIBRARY_SEARCH_PATHS = (
526 | "$(inherited)",
527 | "$(PROJECT_DIR)/Flutter",
528 | );
529 | PODS_BUILD_DIR = "$(inherited)";
530 | PRODUCT_BUNDLE_IDENTIFIER = com.example.douyinDemo;
531 | PRODUCT_NAME = "$(TARGET_NAME)";
532 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
533 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
534 | SWIFT_VERSION = 4.0;
535 | VERSIONING_SYSTEM = "apple-generic";
536 | };
537 | name = Debug;
538 | };
539 | 97C147071CF9000F007C117D /* Release */ = {
540 | isa = XCBuildConfiguration;
541 | baseConfigurationReference = 1D316F3E638415790BE1439B /* Pods-Runner.release.xcconfig */;
542 | buildSettings = {
543 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
544 | CLANG_ENABLE_MODULES = YES;
545 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
546 | DEVELOPMENT_TEAM = 7DFM6K6KA8;
547 | ENABLE_BITCODE = NO;
548 | FLUTTER_ROOT = $HOME/development/flutter;
549 | FRAMEWORK_SEARCH_PATHS = (
550 | "$(inherited)",
551 | "$(PROJECT_DIR)/Flutter",
552 | );
553 | INFOPLIST_FILE = Runner/Info.plist;
554 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
555 | LIBRARY_SEARCH_PATHS = (
556 | "$(inherited)",
557 | "$(PROJECT_DIR)/Flutter",
558 | );
559 | PODS_BUILD_DIR = "$(inherited)";
560 | PRODUCT_BUNDLE_IDENTIFIER = com.example.douyinDemo;
561 | PRODUCT_NAME = "$(TARGET_NAME)";
562 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
563 | SWIFT_VERSION = 4.0;
564 | VERSIONING_SYSTEM = "apple-generic";
565 | };
566 | name = Release;
567 | };
568 | /* End XCBuildConfiguration section */
569 |
570 | /* Begin XCConfigurationList section */
571 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
572 | isa = XCConfigurationList;
573 | buildConfigurations = (
574 | 97C147031CF9000F007C117D /* Debug */,
575 | 97C147041CF9000F007C117D /* Release */,
576 | 249021D3217E4FDB00AE95B9 /* Profile */,
577 | );
578 | defaultConfigurationIsVisible = 0;
579 | defaultConfigurationName = Release;
580 | };
581 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
582 | isa = XCConfigurationList;
583 | buildConfigurations = (
584 | 97C147061CF9000F007C117D /* Debug */,
585 | 97C147071CF9000F007C117D /* Release */,
586 | 249021D4217E4FDB00AE95B9 /* Profile */,
587 | );
588 | defaultConfigurationIsVisible = 0;
589 | defaultConfigurationName = Release;
590 | };
591 | /* End XCConfigurationList section */
592 | };
593 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
594 | }
595 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 | import Firebase
4 | //
5 | @UIApplicationMain
6 | @objc class AppDelegate: FlutterAppDelegate {
7 | override func application(
8 | _ application: UIApplication,
9 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
10 | ) -> Bool {
11 | FirebaseApp.configure()
12 | GeneratedPluginRegistrant.register(with: self)
13 |
14 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
15 | }
16 | }
17 |
18 |
19 | //@UIApplicationMain
20 | //class AppDelegate: UIResponder, UIApplicationDelegate {
21 | //
22 | // var window: UIWindow?
23 | //
24 | // func application(_ application: UIApplication,
25 | // didFinishLaunchingWithOptions launchOptions:
26 | // [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
27 | // FirebaseApp.configure()
28 | //
29 | // return true
30 | // }
31 | //}
32 |
--------------------------------------------------------------------------------
/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/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/GoogleService-Info .plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CLIENT_ID
6 | 416855912244-nqmupjevgtbf7ifcjfv42uocjdv5c77f.apps.googleusercontent.com
7 | REVERSED_CLIENT_ID
8 | com.googleusercontent.apps.416855912244-nqmupjevgtbf7ifcjfv42uocjdv5c77f
9 | API_KEY
10 | AIzaSyCSAI7AIcmi8285VKOBPKnLjh0rH0WRRQ4
11 | GCM_SENDER_ID
12 | 416855912244
13 | PLIST_VERSION
14 | 1
15 | BUNDLE_ID
16 | com.example.douyinDemo
17 | PROJECT_ID
18 | douyindemo
19 | STORAGE_BUCKET
20 | douyindemo.appspot.com
21 | IS_ADS_ENABLED
22 |
23 | IS_ANALYTICS_ENABLED
24 |
25 | IS_APPINVITE_ENABLED
26 |
27 | IS_GCM_ENABLED
28 |
29 | IS_SIGNIN_ENABLED
30 |
31 | GOOGLE_APP_ID
32 | 1:416855912244:ios:966e409b00d2d6762dff61
33 | DATABASE_URL
34 | https://douyindemo.firebaseio.com
35 |
36 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | CFBundleDevelopmentRegion
8 | $(DEVELOPMENT_LANGUAGE)
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | douyin_demo
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | douyinDemo
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 0.01
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UIViewControllerBasedStatusBarAppearance
45 |
46 | NSCameraUsageDescription
47 | 系统将使用您的相机进行图片拍摄,视频拍摄等
48 | NSMicrophoneUsageDescription
49 | 系统将使用您的麦克风进行音频录制
50 | NSPhotoLibraryUsageDescription
51 | 我们将存储照片至您的相册以及从相册获取图片信息
52 | NSAppTransportSecurity
53 |
54 | NSAllowsArbitraryLoads
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/lib/detector_painters.dart:
--------------------------------------------------------------------------------
1 | // Copyright 2018 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | import 'dart:ui' as ui;
6 |
7 | import 'package:firebase_ml_vision/firebase_ml_vision.dart';
8 | import 'package:flutter/foundation.dart';
9 | import 'package:flutter/material.dart';
10 |
11 | enum Detector { barcode, face, label, cloudLabel, text }
12 |
13 | class BarcodeDetectorPainter extends CustomPainter {
14 | BarcodeDetectorPainter(this.imageSize, this.barcodes);
15 |
16 | final Size imageSize;
17 | final List barcodes;
18 |
19 | @override
20 | void paint(Canvas canvas, Size size) {
21 | final Paint paint = Paint()
22 | ..style = PaintingStyle.stroke
23 | ..strokeWidth = 2.0;
24 |
25 | for (Barcode barcode in barcodes) {
26 | paint.color = Colors.green;
27 | canvas.drawRect(
28 | _scaleRect(
29 | rect: barcode.boundingBox,
30 | imageSize: imageSize,
31 | widgetSize: size,
32 | ),
33 | paint,
34 | );
35 | }
36 | }
37 |
38 | @override
39 | bool shouldRepaint(BarcodeDetectorPainter oldDelegate) {
40 | return oldDelegate.imageSize != imageSize ||
41 | oldDelegate.barcodes != barcodes;
42 | }
43 | }
44 |
45 | class FaceDetectorPainter extends CustomPainter {
46 | FaceDetectorPainter(this.imageSize, this.faces);
47 |
48 | final Size imageSize;
49 | final List faces;
50 |
51 | @override
52 | void paint(Canvas canvas, Size size) {
53 | final Paint paint = Paint()
54 | ..style = PaintingStyle.stroke
55 | ..strokeWidth = 2.0
56 | ..color = Colors.red;
57 |
58 | for (Face face in faces) {
59 | canvas.drawRect(
60 | _scaleRect(
61 | rect: face.boundingBox,
62 | imageSize: imageSize,
63 | widgetSize: size,
64 | ),
65 | paint,
66 | );
67 | }
68 | }
69 |
70 | @override
71 | bool shouldRepaint(FaceDetectorPainter oldDelegate) {
72 | return oldDelegate.imageSize != imageSize || oldDelegate.faces != faces;
73 | }
74 | }
75 |
76 | class LabelDetectorPainter extends CustomPainter {
77 | LabelDetectorPainter(this.imageSize, this.labels);
78 |
79 | final Size imageSize;
80 | final List labels;
81 |
82 | @override
83 | void paint(Canvas canvas, Size size) {
84 | final ui.ParagraphBuilder builder = ui.ParagraphBuilder(
85 | ui.ParagraphStyle(
86 | textAlign: TextAlign.left,
87 | fontSize: 23.0,
88 | textDirection: TextDirection.ltr),
89 | );
90 |
91 | builder.pushStyle(ui.TextStyle(color: Colors.green));
92 | // for (Label label in labels) {
93 | // builder.addText('Label: ${label.label}, '
94 | // 'Confidence: ${label.confidence.toStringAsFixed(2)}\n');
95 | // }
96 | builder.pop();
97 |
98 | canvas.drawParagraph(
99 | builder.build()
100 | ..layout(ui.ParagraphConstraints(
101 | width: size.width,
102 | )),
103 | const Offset(0.0, 0.0),
104 | );
105 | }
106 |
107 | @override
108 | bool shouldRepaint(LabelDetectorPainter oldDelegate) {
109 | return oldDelegate.imageSize != imageSize || oldDelegate.labels != labels;
110 | }
111 | }
112 |
113 | // Paints rectangles around all the text in the image.
114 | class TextDetectorPainter extends CustomPainter {
115 | TextDetectorPainter(this.imageSize, this.visionText);
116 |
117 | final Size imageSize;
118 | final VisionText visionText;
119 |
120 | @override
121 | void paint(Canvas canvas, Size size) {
122 | final Paint paint = Paint()
123 | ..style = PaintingStyle.stroke
124 | ..strokeWidth = 2.0;
125 |
126 | Rect _getRect(TextContainer container) {
127 | return _scaleRect(
128 | rect: container.boundingBox,
129 | imageSize: imageSize,
130 | widgetSize: size,
131 | );
132 | }
133 |
134 | for (TextBlock block in visionText.blocks) {
135 | for (TextLine line in block.lines) {
136 | for (TextElement element in line.elements) {
137 | paint.color = Colors.green;
138 | canvas.drawRect(_getRect(element), paint);
139 | }
140 |
141 | paint.color = Colors.yellow;
142 | canvas.drawRect(_getRect(line), paint);
143 | }
144 |
145 | paint.color = Colors.red;
146 | canvas.drawRect(_getRect(block), paint);
147 | }
148 | }
149 |
150 | @override
151 | bool shouldRepaint(TextDetectorPainter oldDelegate) {
152 | return oldDelegate.imageSize != imageSize ||
153 | oldDelegate.visionText != visionText;
154 | }
155 | }
156 |
157 | Rect _scaleRect({
158 | @required Rect rect,
159 | @required Size imageSize,
160 | @required Size widgetSize,
161 | }) {
162 | final double scaleX = widgetSize.width / imageSize.width;
163 | final double scaleY = widgetSize.height / imageSize.height;
164 |
165 | return Rect.fromLTRB(
166 | rect.left.toDouble() * scaleX,
167 | rect.top.toDouble() * scaleY,
168 | rect.right.toDouble() * scaleX,
169 | rect.bottom.toDouble() * scaleY,
170 | );
171 | }
--------------------------------------------------------------------------------
/lib/images/pingguo.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/lib/images/pingguo.jpeg
--------------------------------------------------------------------------------
/lib/images/sky.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/lib/images/sky.jpg
--------------------------------------------------------------------------------
/lib/images/temple.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/lib/images/temple.jpg
--------------------------------------------------------------------------------
/lib/images/waterdrop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/lib/images/waterdrop.jpg
--------------------------------------------------------------------------------
/lib/images/whitehouse.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/lib/images/whitehouse.jpg
--------------------------------------------------------------------------------
/lib/images/woman.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/lib/images/woman.jpg
--------------------------------------------------------------------------------
/lib/images/woman2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/lib/images/woman2.jpg
--------------------------------------------------------------------------------
/lib/images/zhifei.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todother/flutter_douyin_demo/948d51ccb6f238411c6fe29b2ed46a0d59fb4429/lib/images/zhifei.jpg
--------------------------------------------------------------------------------
/lib/models/PostsModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:json_annotation/json_annotation.dart';
2 | part 'PostsModel.g.dart';
3 |
4 | @JsonSerializable()
5 | class PostsModel extends Object {
6 | String postsID;
7 | String postsContent;
8 | String postsMaker;
9 | DateTime postsMakeDate;
10 | int postsPicCount;
11 | int postsReaded;
12 | int postsLoved;
13 | String postsPics;
14 | String makerName;
15 | String makerID;
16 | String picsSimpPath;
17 | String picsPath;
18 | String whenPosts;
19 | String makerPhoto;
20 | double latitude;
21 | double longitude;
22 | String postsLocation;
23 | String postsType;
24 | int postsStatus;
25 | int ifOfficial;
26 | int ifLY;
27 | double picsRate;
28 | bool ifUserLoved;
29 |
30 | PostsModel(this.postsID,this.postsContent,this.postsMaker,this.postsMakeDate,this.postsPicCount,this.postsReaded,this.postsLoved,this.postsPics,this.ifLY
31 | ,this.ifOfficial,this.ifUserLoved,this.latitude,this.longitude,this.makerID,this.makerName,this.makerPhoto,this.picsPath,this.picsRate,this.picsSimpPath,this.postsLocation,this.postsStatus
32 | ,this.postsType,this.whenPosts);
33 |
34 |
35 | factory PostsModel.fromJson(Map json) => _$PostsModelFromJson(json);
36 | Map toJson() => _$PostsModelToJson(this);
37 | }
--------------------------------------------------------------------------------
/lib/models/PostsModel.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'PostsModel.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | PostsModel _$PostsModelFromJson(Map json) {
10 | return PostsModel(
11 | json['postsID'] as String,
12 | json['postsContent'] as String,
13 | json['postsMaker'] as String,
14 | json['postsMakeDate'] == null
15 | ? null
16 | : DateTime.parse(json['postsMakeDate'] as String),
17 | json['postsPicCount'] as int,
18 | json['postsReaded'] as int,
19 | json['postsLoved'] as int,
20 | json['postsPics'] as String,
21 | json['ifLY'] as int,
22 | json['ifOfficial'] as int,
23 | json['ifUserLoved'] as bool,
24 | (json['latitude'] as num)?.toDouble(),
25 | (json['longitude'] as num)?.toDouble(),
26 | json['makerID'] as String,
27 | json['makerName'] as String,
28 | json['makerPhoto'] as String,
29 | json['picsPath'] as String,
30 | (json['picsRate'] as num)?.toDouble(),
31 | json['picsSimpPath'] as String,
32 | json['postsLocation'] as String,
33 | json['postsStatus'] as int,
34 | json['postsType'] as String,
35 | json['whenPosts'] as String,
36 | );
37 | }
38 |
39 | Map _$PostsModelToJson(PostsModel instance) =>
40 | {
41 | 'postsID': instance.postsID,
42 | 'postsContent': instance.postsContent,
43 | 'postsMaker': instance.postsMaker,
44 | 'postsMakeDate': instance.postsMakeDate?.toIso8601String(),
45 | 'postsPicCount': instance.postsPicCount,
46 | 'postsReaded': instance.postsReaded,
47 | 'postsLoved': instance.postsLoved,
48 | 'postsPics': instance.postsPics,
49 | 'makerName': instance.makerName,
50 | 'makerID': instance.makerID,
51 | 'picsSimpPath': instance.picsSimpPath,
52 | 'picsPath': instance.picsPath,
53 | 'whenPosts': instance.whenPosts,
54 | 'makerPhoto': instance.makerPhoto,
55 | 'latitude': instance.latitude,
56 | 'longitude': instance.longitude,
57 | 'postsLocation': instance.postsLocation,
58 | 'postsType': instance.postsType,
59 | 'postsStatus': instance.postsStatus,
60 | 'ifOfficial': instance.ifOfficial,
61 | 'ifLY': instance.ifLY,
62 | 'picsRate': instance.picsRate,
63 | 'ifUserLoved': instance.ifUserLoved,
64 | };
65 |
--------------------------------------------------------------------------------
/lib/pages/CameraPage/CameraMain.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 | import 'dart:math';
3 |
4 | import 'package:camera/camera.dart';
5 | import 'package:camera/new/src/support_android/camera.dart';
6 | import 'package:douyin_demo/providers/CameraProvider.dart';
7 | import 'package:firebase_ml_vision/firebase_ml_vision.dart';
8 | import 'package:flutter/material.dart';
9 | import 'package:image_gallery_saver/image_gallery_saver.dart';
10 | import 'package:provider/provider.dart';
11 | import 'package:path/path.dart' as p;
12 | import 'package:image_picker_saver/image_picker_saver.dart';
13 |
14 | class CameraPage extends StatelessWidget {
15 | const CameraPage({Key key}) : super(key: key);
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Scaffold(
20 | backgroundColor: Theme.of(context).primaryColor,
21 | body: CameraMain(
22 | rpx: MediaQuery.of(context).size.width / 750,
23 | ),
24 | bottomNavigationBar: BottomAppBar(),
25 | );
26 | }
27 | }
28 |
29 | class CameraMain extends StatefulWidget {
30 | CameraMain({Key key, @required this.rpx}) : super(key: key);
31 | final double rpx;
32 | @override
33 | _CameraMainState createState() => _CameraMainState();
34 | }
35 |
36 | class _CameraMainState extends State {
37 | CameraProvider provider;
38 | double rpx;
39 | double toTop;
40 | double outBox;
41 | double innerBox;
42 | CameraController _controller;
43 | bool findFace = false;
44 | var cameras;
45 | @override
46 | void initState() {
47 | super.initState();
48 |
49 | // provider = Provider.of(context);
50 | // getCameras();
51 | rpx = widget.rpx;
52 | toTop = 100 * rpx;
53 | outBox = 170 * rpx;
54 | innerBox = 130 * rpx;
55 | }
56 |
57 | getCameras() async {
58 | cameras = await availableCameras();
59 | _controller = CameraController(cameras[1], ResolutionPreset.medium);
60 |
61 | _controller.initialize().then((_) {
62 | if (!mounted) {
63 | return;
64 | }
65 | _controller.startImageStream((CameraImage availableImage) {
66 | _controller.stopImageStream();
67 | _scanFrame(availableImage);
68 | });
69 |
70 | setState(() {});
71 | });
72 | }
73 |
74 | void _scanFrame(CameraImage availableImage) async {
75 |
76 | final FirebaseVisionImageMetadata metadata = FirebaseVisionImageMetadata(
77 | rawFormat: availableImage.format.raw,
78 | size: Size(
79 | availableImage.width.toDouble(), availableImage.height.toDouble()),
80 | planeData: availableImage.planes
81 | .map((currentPlane) => FirebaseVisionImagePlaneMetadata(
82 | bytesPerRow: currentPlane.bytesPerRow,
83 | height: currentPlane.height,
84 | width: currentPlane.width))
85 | .toList(),
86 | rotation: ImageRotation.rotation90);
87 | final FirebaseVisionImage visionImage =
88 | FirebaseVisionImage.fromBytes(availableImage.planes[0].bytes, metadata);
89 | final FaceDetector detector = FirebaseVision.instance.faceDetector();
90 | final List faces = await detector.processImage(visionImage);
91 |
92 | if (faces.length > 0) {
93 | setState(() {
94 | findFace = true;
95 | _controller.startImageStream((CameraImage availableImage) {
96 | _controller.stopImageStream();
97 | _scanFrame(availableImage);
98 | });
99 | });
100 | } else {
101 | setState(() {
102 | findFace = false;
103 | _controller.startImageStream((CameraImage availableImage) {
104 | _controller.stopImageStream();
105 | _scanFrame(availableImage);
106 | });
107 | });
108 | }
109 |
110 | // for (TextBlock block in visionText.blocks) {
111 |
112 | // // final Rectangle boundingBox = block.boundingBox;
113 | // // final List> cornerPoints = block.cornerPoints;
114 | // print(block.text);
115 | // final List languages = block.recognizedLanguages;
116 |
117 | // for (TextLine line in block.lines) {
118 | // // Same getters as TextBlock
119 | // print(line.text);
120 | // for (TextElement element in line.elements) {
121 | // // Same getters as TextBlock
122 | // print(element.text);
123 | // }
124 | // }
125 | // }
126 | }
127 |
128 | @override
129 | void dispose() {
130 | // TODO: implement dispose
131 | _controller.dispose();
132 | super.dispose();
133 | }
134 |
135 | @override
136 | Widget build(BuildContext context) {
137 | provider = Provider.of(context);
138 | _controller=provider.cameraController;
139 | if (provider == null || _controller == null) {
140 | return Container(
141 | child: Center(child: CircularProgressIndicator()),
142 | );
143 | }
144 |
145 | bool ifMakeVideo = provider.ifMakeVideo;
146 | if (_controller == null || _controller?.value == null) {
147 | return Container(
148 | child: Center(child: CircularProgressIndicator()),
149 | );
150 | }
151 | final size = MediaQuery.of(context).size;
152 | return _controller.value.isInitialized
153 | ? Stack(children: [
154 | // Camera.open(cameraId),
155 | findFace? Positioned(
156 | top: 0,
157 | left: 0,
158 | child: Container(width: 100,height: 100,color: Colors.red,)
159 | ):Container(),
160 | ClipRect(
161 | child: Transform.scale(
162 | scale: _controller.value.aspectRatio / size.aspectRatio,
163 | child: Center(
164 | child: AspectRatio(
165 | aspectRatio: _controller.value.aspectRatio,
166 | child: CameraPreview(_controller),
167 | ),
168 | ),
169 | )),
170 | Positioned(
171 | //顶部关闭按钮
172 | top: toTop,
173 | left: 30 * rpx,
174 | child: IconButton(
175 | icon: Icon(
176 | Icons.close,
177 | color: Colors.white,
178 | size: 60 * rpx,
179 | ),
180 | onPressed: () {
181 | Navigator.pop(context);
182 | },
183 | ),
184 | ),
185 | Positioned(
186 | //选择音乐
187 | top: toTop,
188 | left: 250 * rpx,
189 | child: Container(
190 | width: 250 * rpx,
191 | child: FlatButton(
192 | onPressed: () {},
193 | child: Row(
194 | children: [
195 | Icon(
196 | Icons.music_note,
197 | color: Colors.white,
198 | ),
199 | SizedBox(
200 | width: 10 * rpx,
201 | ),
202 | Text(
203 | "选择音乐",
204 | style: TextStyle(color: Colors.white),
205 | ),
206 | ],
207 | ),
208 | ),
209 | ),
210 | ),
211 | Positioned(
212 | //拍照按钮
213 | bottom: 140 * rpx,
214 | // left: (750*rpx-outBox)/2,
215 | child: Container(
216 | width: 750 * rpx,
217 | child: Row(
218 | mainAxisAlignment: MainAxisAlignment.spaceAround,
219 | children: [
220 | ifMakeVideo
221 | ? Container(
222 | width: 80 * rpx,
223 | )
224 | : IconWithText(
225 | icon: Icon(
226 | Icons.search,
227 | color: Colors.white,
228 | ),
229 | text: "道具"),
230 | ifMakeVideo
231 | ? AnimVideoButton(
232 | rpx: rpx,
233 | outWidth: outBox,
234 | innerWidth: innerBox - 30 * rpx,
235 | provider: provider,
236 | )
237 | : CircleTakePhoto(
238 | outBox: outBox,
239 | innerBox: innerBox,
240 | ),
241 | ifMakeVideo
242 | ? IconButton(
243 | padding: EdgeInsets.all(0),
244 | icon: Icon(
245 | Icons.check_circle,
246 | color: Color.fromARGB(255, 219, 48, 85),
247 | size: 80 * rpx,
248 | ),
249 | onPressed: () async {
250 | provider.cameraController
251 | .stopVideoRecording();
252 | await ImageGallerySaver.saveFile(
253 | provider.fileName);
254 | File(provider.fileName).delete();
255 | },
256 | )
257 | : IconWithText(
258 | icon: Icon(
259 | Icons.search,
260 | color: Colors.white,
261 | ),
262 | text: "道具"),
263 | ])),
264 | ),
265 | Positioned(
266 | bottom: 40 * rpx,
267 | child: ScrollBottomBar(
268 | rpx: rpx,
269 | ),
270 | ),
271 | Positioned(
272 | right: 30 * rpx,
273 | top: 80 * rpx,
274 | child: IconButton(
275 | icon: Icon(Icons.camera_front),
276 | onPressed: () {
277 | provider.changeCamera();
278 | }),
279 | )
280 | ])
281 | : Container();
282 | }
283 | }
284 |
285 | // class CameraMain extends StatelessWidget {
286 | // const CameraMain({Key key}) : super(key: key);
287 |
288 | // @override
289 | // Widget build(BuildContext context) {
290 | // CameraProvider provider = Provider.of(context);
291 | // if (provider == null || provider.cameraController == null) {
292 | // return Container(
293 | // child: Center(child: CircularProgressIndicator()),
294 | // );
295 | // }
296 | // double rpx = MediaQuery.of(context).size.width / 750;
297 | // double toTop = 100 * rpx;
298 | // double outBox = 170 * rpx;
299 | // double innerBox = 130 * rpx;
300 | // CameraController _controller = provider.cameraController;
301 | // var cameras = provider.cameras;
302 |
303 | // bool ifMakeVideo = provider.ifMakeVideo;
304 | // if (_controller == null || _controller?.value == null) {
305 | // return Container(
306 | // child: Center(child: CircularProgressIndicator()),
307 | // );
308 | // }
309 | // final size = MediaQuery.of(context).size;
310 | // return _controller.value.isInitialized
311 | // ? Stack(children: [
312 | // // Camera.open(cameraId),
313 |
314 | // ClipRect(
315 | // child: Transform.scale(
316 | // scale: _controller.value.aspectRatio / size.aspectRatio,
317 | // child: Center(
318 | // child: AspectRatio(
319 | // aspectRatio: _controller.value.aspectRatio,
320 | // child: CameraPreview(_controller),
321 | // ),
322 | // ),
323 | // )),
324 | // Positioned(
325 | // //顶部关闭按钮
326 | // top: toTop,
327 | // left: 30 * rpx,
328 | // child: IconButton(
329 | // icon: Icon(
330 | // Icons.close,
331 | // color: Colors.white,
332 | // size: 60 * rpx,
333 | // ),
334 | // onPressed: () {
335 | // Navigator.pop(context);
336 | // },
337 | // ),
338 | // ),
339 | // Positioned(
340 | // //选择音乐
341 | // top: toTop,
342 | // left: 250 * rpx,
343 | // child: Container(
344 | // width: 250 * rpx,
345 | // child: FlatButton(
346 | // onPressed: () {},
347 | // child: Row(
348 | // children: [
349 | // Icon(
350 | // Icons.music_note,
351 | // color: Colors.white,
352 | // ),
353 | // SizedBox(
354 | // width: 10 * rpx,
355 | // ),
356 | // Text(
357 | // "选择音乐",
358 | // style: TextStyle(color: Colors.white),
359 | // ),
360 | // ],
361 | // ),
362 | // ),
363 | // ),
364 | // ),
365 | // Positioned(
366 | // //拍照按钮
367 | // bottom: 140 * rpx,
368 | // // left: (750*rpx-outBox)/2,
369 | // child: Container(
370 | // width: 750 * rpx,
371 | // child: Row(
372 | // mainAxisAlignment: MainAxisAlignment.spaceAround,
373 | // children: [
374 | // ifMakeVideo
375 | // ? Container(
376 | // width: 80 * rpx,
377 | // )
378 | // : IconWithText(
379 | // icon: Icon(
380 | // Icons.search,
381 | // color: Colors.white,
382 | // ),
383 | // text: "道具"),
384 | // ifMakeVideo
385 | // ? AnimVideoButton(
386 | // rpx: rpx,
387 | // outWidth: outBox,
388 | // innerWidth: innerBox - 30 * rpx,
389 | // provider: provider,
390 | // )
391 | // : CircleTakePhoto(
392 | // outBox: outBox,
393 | // innerBox: innerBox,
394 | // ),
395 | // ifMakeVideo
396 | // ? IconButton(
397 | // padding: EdgeInsets.all(0),
398 | // icon: Icon(
399 | // Icons.check_circle,
400 | // color: Color.fromARGB(255, 219, 48, 85),
401 | // size: 80 * rpx,
402 | // ),
403 | // onPressed: () async {
404 | // provider.cameraController
405 | // .stopVideoRecording();
406 | // await ImageGallerySaver.saveFile(
407 | // provider.fileName);
408 | // File(provider.fileName).delete();
409 | // },
410 | // )
411 | // : IconWithText(
412 | // icon: Icon(
413 | // Icons.search,
414 | // color: Colors.white,
415 | // ),
416 | // text: "道具"),
417 | // ])),
418 | // ),
419 | // Positioned(
420 | // bottom: 40 * rpx,
421 | // child: ScrollBottomBar(
422 | // rpx: rpx,
423 | // ),
424 | // ),
425 | // Positioned(
426 | // right: 30 * rpx,
427 | // top: 80 * rpx,
428 | // child: IconButton(
429 | // icon: Icon(Icons.camera_front),
430 | // onPressed: () {
431 | // provider.changeCamera();
432 | // }),
433 | // )
434 | // ])
435 | // : Container();
436 | // }
437 | // }
438 |
439 | class AnimVideoButton extends StatefulWidget {
440 | AnimVideoButton(
441 | {Key key,
442 | @required this.outWidth,
443 | @required this.innerWidth,
444 | @required this.rpx,
445 | @required this.provider})
446 | : super(key: key);
447 | final double outWidth;
448 | final double innerWidth;
449 | final double rpx;
450 | final CameraProvider provider;
451 | _AnimVideoButtonState createState() => _AnimVideoButtonState();
452 | }
453 |
454 | class _AnimVideoButtonState extends State
455 | with TickerProviderStateMixin {
456 | Animation animation;
457 | AnimationController controller;
458 | double outWidth;
459 | double innerWidth;
460 | double outBorder;
461 | double rpx;
462 | double maxBorder;
463 | bool ifRecording;
464 | CameraProvider provider;
465 | double curBorder;
466 | @override
467 | void dispose() {
468 | // TODO: implement dispose
469 | controller.dispose();
470 | super.dispose();
471 | }
472 |
473 | @override
474 | void initState() {
475 | super.initState();
476 | ifRecording = true;
477 | provider = widget.provider;
478 | outWidth = widget.outWidth;
479 | innerWidth = widget.innerWidth;
480 | rpx = widget.rpx;
481 | outBorder = 5 * rpx;
482 | maxBorder = (outWidth - innerWidth) / 2 - 10 * rpx;
483 | curBorder = outBorder;
484 | controller =
485 | AnimationController(duration: Duration(milliseconds: 500), vsync: this);
486 | animation =
487 | Tween(begin: outBorder, end: maxBorder).animate(controller)
488 | ..addListener(() {
489 | setState(() {
490 | curBorder = animation.value;
491 | });
492 | });
493 | controller.repeat(reverse: true);
494 | }
495 |
496 | pauseRecording() {
497 | // provider.cameraController.pauseVideoRecording();
498 | controller.stop();
499 | provider.cameraController.pauseVideoRecording();
500 | setState(() {
501 | ifRecording = false;
502 | });
503 | }
504 |
505 | resumeRecording() {
506 | // provider.cameraController.resumeVideoRecording();
507 | controller.repeat(reverse: true);
508 | provider.cameraController.resumeVideoRecording();
509 | setState(() {
510 | ifRecording = true;
511 | });
512 | }
513 |
514 | @override
515 | Widget build(BuildContext context) {
516 | return Container(
517 | width: outWidth,
518 | height: outWidth,
519 | decoration: BoxDecoration(
520 | shape: BoxShape.circle,
521 | color: Colors.transparent,
522 | border: Border.all(
523 | width: curBorder, color: Color.fromARGB(128, 219, 48, 85))),
524 | child: Container(
525 | child: !ifRecording
526 | ? IconButton(
527 | padding: EdgeInsets.all(0),
528 | icon: Icon(
529 | Icons.play_arrow,
530 | size: innerWidth,
531 | color: Color.fromARGB(255, 219, 48, 85),
532 | ),
533 | onPressed: () {
534 | resumeRecording();
535 | },
536 | )
537 | : IconButton(
538 | padding: EdgeInsets.all(0),
539 | icon: Icon(
540 | Icons.pause,
541 | size: innerWidth,
542 | color: Color.fromARGB(255, 219, 48, 85),
543 | ),
544 | onPressed: () {
545 | pauseRecording();
546 | },
547 | ),
548 | ),
549 | );
550 | }
551 | }
552 |
553 | class ScrollBottomBar extends StatefulWidget {
554 | ScrollBottomBar({Key key, @required this.rpx}) : super(key: key);
555 | final double rpx;
556 | _ScrollBottomBarState createState() => _ScrollBottomBarState();
557 | }
558 |
559 | class _ScrollBottomBarState extends State {
560 | double rpx;
561 | double eachWidth;
562 | double eachSide;
563 | List items;
564 | ScrollController controller;
565 | double startX = 0;
566 | double finalX = 0;
567 | double minValue;
568 | double maxValue;
569 | double curX;
570 | int curIndex;
571 |
572 | @override
573 | void initState() {
574 | super.initState();
575 | rpx = widget.rpx;
576 | eachWidth = 130 * rpx;
577 | eachSide = (750 - eachWidth / rpx) / 2 * rpx;
578 | curIndex = 2;
579 | minValue = 0;
580 |
581 | items = [
582 | '拍照',
583 | '拍15秒',
584 | '拍60秒',
585 | '影集',
586 | '开直播',
587 | ];
588 | maxValue = (items.length - 1) * eachWidth;
589 | curX = curIndex * eachWidth;
590 | controller = ScrollController(initialScrollOffset: curX);
591 | }
592 |
593 | moveToItem(index) {
594 | curX = index * eachWidth;
595 | controller.animateTo(curX,
596 | duration: Duration(milliseconds: 200), curve: Curves.linear);
597 | setState(() {
598 | curX = curX;
599 | curIndex = index;
600 | });
601 | }
602 |
603 | @override
604 | Widget build(BuildContext context) {
605 | return Column(children: [
606 | Listener(
607 | onPointerDown: (result) {
608 | setState(() {
609 | startX = result.position.dx;
610 | });
611 | },
612 | onPointerMove: (result) {
613 | double moveValue = result.position.dx;
614 | double moved = startX - moveValue;
615 | // curX+moved
616 | double afterMoved = min(max(curX + moved, minValue), maxValue);
617 | setState(() {
618 | curX = afterMoved;
619 | startX = result.position.dx;
620 | });
621 | },
622 | onPointerUp: (result) {
623 | int index = 0;
624 | double finalPosition = curX - eachWidth / 2;
625 | index = (finalPosition / eachWidth).ceil();
626 | moveToItem(index);
627 | },
628 | child: Container(
629 | width: 750 * rpx,
630 | height: 100 * rpx,
631 | child: SingleChildScrollView(
632 | scrollDirection: Axis.horizontal,
633 | controller: controller,
634 | child: Container(
635 | child: Row(
636 | mainAxisSize: MainAxisSize.min,
637 | children: [
638 | SizedBox(
639 | width: eachSide,
640 | ),
641 | Row(
642 | children: List.generate(items.length, (index) {
643 | return Container(
644 | width: eachWidth,
645 | child: FlatButton(
646 | child: Text(
647 | items[index],
648 | style: TextStyle(
649 | color: curIndex == index
650 | ? Colors.white
651 | : Colors.white.withOpacity(0.5)),
652 | ),
653 | padding: EdgeInsets.all(0),
654 | onPressed: () {
655 | moveToItem(index);
656 | },
657 | ),
658 | );
659 | })),
660 | SizedBox(
661 | width: eachSide,
662 | ),
663 | ],
664 | ),
665 | ),
666 | )),
667 | ),
668 | Center(
669 | child: Container(
670 | decoration:
671 | BoxDecoration(shape: BoxShape.circle, color: Colors.white),
672 | width: 8 * rpx,
673 | height: 8 * rpx,
674 | ),
675 | )
676 | ]);
677 | }
678 | }
679 |
680 | class CircleTakePhoto extends StatelessWidget {
681 | const CircleTakePhoto(
682 | {Key key, @required this.outBox, @required this.innerBox})
683 | : super(key: key);
684 | final double outBox;
685 | final double innerBox;
686 | @override
687 | Widget build(BuildContext context) {
688 | double rpx = MediaQuery.of(context).size.width / 750;
689 | CameraProvider provider = Provider.of(context);
690 |
691 | // double outBox=160*rpx;
692 | // double innerBox=130*rpx;
693 | return Container(
694 | width: outBox,
695 | height: outBox,
696 | padding: EdgeInsets.all(10 * rpx),
697 | decoration: BoxDecoration(
698 | color: Colors.transparent,
699 | borderRadius: BorderRadius.circular(90 * rpx),
700 | border: Border.all(
701 | width: 10 * rpx, color: Color.fromARGB(128, 219, 48, 85)),
702 | ),
703 | child: FlatButton(
704 | padding: EdgeInsets.all(0),
705 | onPressed: () async {
706 | // provider.changeFileName('png');
707 | // print(provider.fileName);
708 | // await provider.cameraController
709 | // .takePicture(provider.fileName)
710 | // .then((_) {
711 | // // Navigator.push(context, MaterialPageRoute(fullscreenDialog: true,builder: (_){
712 | // // return Image.file(File(provider.fileName) );
713 | // // }));
714 | // ImagePickerSaver.saveFile(
715 | // fileData: File(provider.fileName).readAsBytesSync());
716 | // });
717 | provider.changeFileName('mp4');
718 | provider.cameraController.startVideoRecording(provider.fileName);
719 | provider.changePhotoWidget();
720 | },
721 | child: Container(
722 | width: innerBox,
723 | height: innerBox,
724 | alignment: Alignment.center,
725 | decoration: BoxDecoration(
726 | color: Color.fromARGB(255, 219, 48, 85),
727 | borderRadius: BorderRadius.circular(75 * rpx)),
728 | )),
729 | );
730 | }
731 | }
732 |
733 | class IconWithText extends StatelessWidget {
734 | const IconWithText({Key key, @required this.icon, @required this.text})
735 | : super(key: key);
736 | final Icon icon;
737 | final String text;
738 | @override
739 | Widget build(BuildContext context) {
740 | return Column(
741 | children: [
742 | icon,
743 | Text(
744 | text,
745 | style: TextStyle(color: Colors.white),
746 | )
747 | ],
748 | );
749 | }
750 | }
751 |
--------------------------------------------------------------------------------
/lib/pages/FaceDetect/FaceDetection.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:firebase_ml_vision/firebase_ml_vision.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:image_picker/image_picker.dart';
6 |
7 |
8 | class FaceDetectionView extends StatefulWidget {
9 | FaceDetectionView({Key key}) : super(key: key);
10 |
11 | @override
12 | _FaceDetectionViewState createState() => _FaceDetectionViewState();
13 | }
14 |
15 | class _FaceDetectionViewState extends State {
16 | File filePath;
17 | @override
18 | void initState() {
19 | super.initState();
20 |
21 | }
22 | chooseImage() async {
23 | filePath=await ImagePicker.pickImage(source: ImageSource.gallery,imageQuality: 100,maxWidth: MediaQuery.of(context).size.width);
24 | var availableImage=filePath;
25 | // final FirebaseVisionImageMetadata metadata = FirebaseVisionImageMetadata(
26 | // rawFormat: availableImage.format.raw,
27 | // size: Size(
28 | // availableImage.width.toDouble(), availableImage.height.toDouble()),
29 | // planeData: availableImage.planes
30 | // .map((currentPlane) => FirebaseVisionImagePlaneMetadata(
31 | // bytesPerRow: currentPlane.bytesPerRow,
32 | // height: currentPlane.height,
33 | // width: currentPlane.width))
34 | // .toList(),
35 | // rotation: ImageRotation.rotation90);
36 | final FirebaseVisionImage visionImage =
37 | FirebaseVisionImage.fromFile(filePath);
38 | final FaceDetector detector = FirebaseVision.instance.faceDetector();
39 | final List faces = await detector.processImage(visionImage);
40 |
41 | print(faces[0].boundingBox);
42 |
43 | setState(() {
44 | filePath=filePath;
45 | });
46 | }
47 | @override
48 | Widget build(BuildContext context) {
49 | return Stack(
50 | children: [
51 | RaisedButton(child: Text("选择图片"),onPressed: (){chooseImage();},),
52 | filePath==null?Container():
53 | Container(
54 | child: Image.file(filePath,fit: BoxFit.fitWidth,),
55 | )
56 | ]
57 | );
58 | }
59 | }
60 |
61 | class FaceMain extends StatelessWidget {
62 | const FaceMain({Key key}) : super(key: key);
63 |
64 | @override
65 | Widget build(BuildContext context) {
66 | return Scaffold(
67 | body: FaceDetectionView(),
68 | );
69 | }
70 | }
--------------------------------------------------------------------------------
/lib/pages/RecommendPage/BottomSheet.dart:
--------------------------------------------------------------------------------
1 | import 'package:douyin_demo/pages/RecommendPage/FriendList.dart';
2 | import 'package:douyin_demo/providers/AtUserProvider.dart';
3 | import 'package:douyin_demo/providers/RecommendProvider.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:provider/provider.dart';
6 |
7 | class ReplyFullList extends StatelessWidget {
8 | const ReplyFullList({Key key,this.pCtx}) : super(key: key);
9 | final BuildContext pCtx;
10 | @override
11 | Widget build(BuildContext context) {
12 | double rpx = MediaQuery.of(context).size.width / 750;
13 | RecommendProvider provider = Provider.of(pCtx);
14 | Reply reply = provider.reply;
15 | List replies = List();
16 |
17 | replies.add(reply);
18 | replies.add(reply);
19 | replies.add(reply);
20 | ScrollController controller = ScrollController();
21 | return Scaffold(
22 | appBar: PreferredSize(
23 | preferredSize: Size.fromHeight(80*rpx),
24 | child: AppBar(
25 | leading: Container(),
26 | elevation:0,
27 | backgroundColor: Colors.grey[50],
28 | actions: [
29 |
30 | IconButton(
31 | icon: Icon(
32 | Icons.close,
33 | color: Colors.black,
34 | ),
35 | onPressed: () {
36 | Navigator.pop(context);
37 | },
38 | )
39 | ],
40 | title: Text(
41 | "10条评论",
42 | style: TextStyle(color: Colors.grey[700],fontSize: 25*rpx),
43 | ),
44 | // elevation: 1,
45 | )
46 | ),
47 | bottomNavigationBar: SafeArea(
48 | child: BottomReplyBar(pCtx: pCtx,),
49 | ),
50 | body: SingleChildScrollView(
51 | controller: controller,
52 | child: Container(
53 | child: genReplyList(replies, controller),
54 | )));
55 | }
56 | }
57 |
58 | class ReplyList extends StatelessWidget {
59 | const ReplyList({Key key, this.reply, this.controller}) : super(key: key);
60 | final Reply reply;
61 | final ScrollController controller;
62 | @override
63 | Widget build(BuildContext context) {
64 | double rpx = MediaQuery.of(context).size.width / 750;
65 | List replies = List();
66 | replies.add(reply);
67 | replies.add(reply);
68 | replies.add(reply);
69 | // RecommendProvider provider=Provider.of(context);
70 | return Container(
71 | child: Column(
72 | mainAxisSize: MainAxisSize.min,
73 | children: [
74 | Row(
75 | children: [
76 | Container(
77 | width: 100 * rpx,
78 | height: 100 * rpx,
79 | padding: EdgeInsets.all(10 * rpx),
80 | child: CircleAvatar(
81 | backgroundImage: NetworkImage("${reply.replyMakerAvatar}"),
82 | ),
83 | ),
84 | Container(
85 | width: 550 * rpx,
86 | child: ListTile(
87 | title: Text("${reply.replyMakerName}"),
88 | subtitle: Text(
89 | "${reply.replyContent}",
90 | maxLines: 2,
91 | overflow: TextOverflow.ellipsis,
92 | ),
93 | ),
94 | ),
95 | Container(
96 | width: 100 * rpx,
97 | child: IconButton(
98 | onPressed: () {},
99 | icon: Icon(
100 | Icons.favorite,
101 | color: Colors.grey[300],
102 | ),
103 | ),
104 | )
105 | ],
106 | ),
107 | genAfterReplyList(replies, controller)
108 | ],
109 | ),
110 | );
111 | }
112 | }
113 |
114 | class AfterReply extends StatelessWidget {
115 | const AfterReply({Key key, this.afterReply}) : super(key: key);
116 | final Reply afterReply;
117 | @override
118 | Widget build(BuildContext context) {
119 | double rpx = MediaQuery.of(context).size.width / 750;
120 | return Container(
121 | child: Column(
122 | mainAxisSize: MainAxisSize.min,
123 | children: [
124 | Row(
125 | children: [
126 | Container(
127 | width: 100 * rpx,
128 | ),
129 | Container(
130 | width: 550 * rpx,
131 | child: Row(
132 | crossAxisAlignment: CrossAxisAlignment.start,
133 | children: [
134 | Container(
135 | width: 70 * rpx,
136 | height: 70 * rpx,
137 | margin: EdgeInsets.only(top: 15 * rpx),
138 | padding: EdgeInsets.all(10 * rpx),
139 | child: CircleAvatar(
140 | backgroundImage:
141 | NetworkImage("${afterReply.replyMakerAvatar}"),
142 | ),
143 | ),
144 | Container(
145 | width: 480 * rpx,
146 | child: ListTile(
147 | title: Text("${afterReply.replyMakerName}"),
148 | subtitle: RichText(
149 | text: TextSpan(
150 | text: "${afterReply.replyContent}",
151 | style: TextStyle(color: Colors.grey[500]),
152 | children: [
153 | TextSpan(text: " ${afterReply.whenReplied}")
154 | ]),
155 | ),
156 |
157 | // Text(
158 | // "${afterReply.replyContent}",
159 | // maxLines: 2,
160 | // overflow: TextOverflow.ellipsis,
161 | // ),
162 | ),
163 | )
164 | ],
165 | ),
166 | ),
167 | Container(
168 | width: 100 * rpx,
169 | child: IconButton(
170 | onPressed: () {},
171 | icon: Icon(
172 | Icons.favorite,
173 | color: Colors.grey[300],
174 | ),
175 | ),
176 | )
177 | ],
178 | )
179 | ],
180 | ),
181 | );
182 | }
183 | }
184 |
185 | genReplyList(List replies, ScrollController controller) {
186 | return ListView.builder(
187 | shrinkWrap: true,
188 | controller: controller,
189 | itemCount: replies.length,
190 | itemBuilder: (context, index) {
191 | return ReplyList(
192 | reply: replies[index],
193 | controller: controller,
194 | );
195 | },
196 | );
197 | }
198 |
199 | genAfterReplyList(List replies, ScrollController controller) {
200 | return ListView.builder(
201 | shrinkWrap: true,
202 | controller: controller,
203 | itemCount: replies.length <= 2 ? replies.length : 2,
204 | itemBuilder: (context, index) {
205 | return AfterReply(
206 | afterReply: replies[index],
207 | );
208 | },
209 | );
210 | }
211 |
212 | class BottomReplyBar extends StatelessWidget {
213 | const BottomReplyBar({Key key,this.pCtx}) : super(key: key);
214 | final BuildContext pCtx;
215 | @override
216 | Widget build(BuildContext context) {
217 | TextEditingController _controller=TextEditingController();
218 | double toBottom=MediaQuery.of(context).viewInsets.bottom;
219 | double rpx=MediaQuery.of(context).size.width/750;
220 | return Container(
221 | padding: EdgeInsets.only(bottom: toBottom),
222 | decoration: BoxDecoration(border: Border(top: BorderSide(color: Colors.grey[200],width: 1))),
223 | child: Row(children: [
224 | Expanded(
225 | child: Container(
226 | padding: EdgeInsets.only(left: 30*rpx),
227 | // width: 600*rspx,
228 | child: TextField(controller: _controller,decoration: InputDecoration(hintText: "留下你的精彩评论",border: InputBorder.none),),
229 | )
230 | ),
231 | IconButton(icon: Icon(Icons.email,color: Colors.grey[500],size: 50*rpx,),onPressed: (){showAtFriendPage(pCtx);},),
232 | IconButton(icon: Icon(Icons.face,color: Colors.grey[500],size: 50*rpx),onPressed: (){},),
233 | SizedBox(width: 20*rpx,)
234 | ],),
235 | );
236 | }
237 | }
238 |
239 | showAtFriendPage(BuildContext context){
240 | Navigator.of(context).push(new MaterialPageRoute(
241 | builder: (BuildContext context) {
242 | return MultiProvider(
243 | providers: [ChangeNotifierProvider(builder:(context)=>AtUserProvider())],
244 | child: AtFriendPage()
245 | );
246 | },
247 | fullscreenDialog: true
248 | ));
249 | }
250 |
--------------------------------------------------------------------------------
/lib/pages/RecommendPage/FriendList.dart:
--------------------------------------------------------------------------------
1 | import 'package:douyin_demo/providers/AtUserProvider.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:provider/provider.dart';
4 | import 'package:sticky_headers/sticky_headers.dart';
5 |
6 | class AtFriendPage extends StatelessWidget {
7 | const AtFriendPage({Key key}) : super(key: key);
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | ScrollController controller = ScrollController();
12 | double rpx = MediaQuery.of(context).size.width / 750;
13 | AtUserProvider provider = Provider.of(context);
14 | // AtUserProvider provider = Provider.of(context);
15 |
16 | List groupList = provider.groupList;
17 | return provider != null
18 | ? Scaffold(
19 | backgroundColor: Color(0xff121319),
20 | appBar: AppBar(
21 | backgroundColor: Color(0xff121319),
22 | leading: Container(
23 | width: 80 * rpx,
24 | child: IconButton(
25 | icon: Icon(Icons.close),
26 | onPressed: () {
27 | Navigator.pop(context);
28 | },
29 | )),
30 | title: Text("@好友"),
31 | bottom: PreferredSize(
32 | preferredSize: Size.fromHeight(80 * rpx),
33 | child: Container(
34 | margin: EdgeInsets.symmetric(horizontal: 30 * rpx),
35 | decoration: BoxDecoration(color: Color(0xff2a2b33)),
36 | padding: EdgeInsets.symmetric(horizontal: 20 * rpx),
37 | child: TextField(
38 | decoration: InputDecoration(
39 | icon: Icon(
40 | Icons.search,
41 | color: Colors.grey[500],
42 | ),
43 | hintText: "搜索用户备注或名字",
44 | hintStyle: TextStyle(
45 | color: Colors.grey[500],
46 | )),
47 | ),
48 | ),
49 | )),
50 | body: ListView.builder(
51 | shrinkWrap: true,
52 | controller: controller,
53 | itemCount: groupList.length,
54 | itemBuilder: (BuildContext context, int index) {
55 | return StickyHeader(
56 | header: Container(
57 | width: MediaQuery.of(context).size.width,
58 | padding:EdgeInsets.only(left: 20*rpx) ,
59 | height: 50,
60 | decoration: BoxDecoration(color: Color(0xff121319)),
61 | alignment: Alignment.centerLeft,
62 | child: Text(
63 | groupList[index].toString(),
64 | style: TextStyle(color: Colors.white, fontSize: 35*rpx),
65 | ),
66 | ),
67 | content: genContentList(
68 | provider.result[provider.groupList[index]],
69 | context,
70 | controller),
71 | );
72 | },
73 | ),
74 | )
75 | : Scaffold();
76 | }
77 | }
78 |
79 | genUserList(context, controller) {
80 | AtUserProvider provider = Provider.of(context);
81 |
82 | List groupList = provider.groupList;
83 | return ListView.builder(
84 | shrinkWrap: true,
85 | controller: controller,
86 | itemCount: groupList.length,
87 | itemBuilder: (BuildContext context, int index) {
88 | return StickyHeader(
89 | header: Container(
90 | width: MediaQuery.of(context).size.width,
91 | height: 50,
92 | decoration: BoxDecoration(color: Colors.black),
93 | child: Text(
94 | groupList[index].toString(),
95 | style: TextStyle(color: Colors.white, fontSize: 20),
96 | ),
97 | ),
98 | content: genContentList(
99 | provider.result[provider.groupList[index]], context, controller),
100 | );
101 | },
102 | );
103 | }
104 |
105 | genContentList(
106 | List friends, BuildContext context, ScrollController controller) {
107 | double rpx = MediaQuery.of(context).size.width / 750;
108 | return ListView.builder(
109 | shrinkWrap: true,
110 | controller: controller,
111 | itemCount: friends.length,
112 | itemBuilder: (BuildContext context, int index) {
113 | return Container(
114 | decoration: BoxDecoration(color: Color(0xff121319)),
115 | height: 130 * rpx,
116 | child: Row(
117 | children: [
118 | Container(
119 | padding: EdgeInsets.all(15 * rpx),
120 | width: 100 * rpx,
121 | height: 100 * rpx,
122 | child: CircleAvatar(
123 | backgroundImage: NetworkImage(friends[index]["avatarUrl"]),
124 | ),
125 | ),
126 | Container(
127 | width: 450 * rpx,
128 | child: friends[index]["desc"].toString().length > 0
129 | ? Column(
130 | crossAxisAlignment: CrossAxisAlignment.start,
131 | mainAxisAlignment: MainAxisAlignment.center,
132 | children: [
133 | Container(
134 | child: Text(
135 | friends[index]["userName"],
136 | style: TextStyle(
137 | fontSize: 32 * rpx, color: Colors.white),
138 | maxLines: 1,
139 | overflow: TextOverflow.ellipsis,
140 | ),
141 | ),
142 | Container(
143 | child: Text(
144 | friends[index]["desc"],
145 | style: TextStyle(color: Colors.grey[500]),
146 | maxLines: 1,
147 | overflow: TextOverflow.ellipsis,
148 | ),
149 | ),
150 | ],
151 | )
152 | : Container(
153 | child: Text(
154 | friends[index]["userName"],
155 | style: TextStyle(
156 | fontSize: 32 * rpx, color: Colors.white),
157 | maxLines: 1,
158 | overflow: TextOverflow.ellipsis,
159 | ),
160 | ),
161 | ),
162 | Container(
163 | width: 200 * rpx,
164 | child: Icon(
165 | Icons.search,
166 | color: Colors.grey[500],
167 | ),
168 | )
169 | ],
170 | ));
171 | },
172 | );
173 | }
174 |
--------------------------------------------------------------------------------
/lib/pages/loadData/loadData.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class LoadDataDemo extends StatelessWidget {
4 | const LoadDataDemo({Key key}) : super(key: key);
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return Scaffold(
9 | appBar: AppBar(
10 | title: Text("获取数据"),
11 | centerTitle: true,
12 | ),
13 | body: RefreshPage());
14 | }
15 | }
16 |
17 | class RefreshPage extends StatefulWidget {
18 | RefreshPage({Key key}) : super(key: key);
19 |
20 | @override
21 | _RefreshPageState createState() => _RefreshPageState();
22 | }
23 |
24 | class _RefreshPageState extends State {
25 | List data = List();
26 | ScrollController controller;
27 | bool ifLoading = false;
28 | @override
29 | void initState() {
30 | super.initState();
31 | controller = ScrollController();
32 | List.generate(30, (i) => data.add("item ${i + 1}"));
33 | }
34 |
35 | @override
36 | Widget build(BuildContext context) {
37 | return Stack(children: [
38 | RefreshIndicator(
39 | onRefresh: () {
40 | return Future.delayed(Duration(seconds: 1), () {
41 | data=List();
42 | List.generate(30, (i) => data.add("item ${i + 1}"));
43 | setState(() {
44 | data = data;
45 | });
46 | });
47 | },
48 | child: NotificationListener(
49 | onNotification: (scroll) {
50 | if (!ifLoading &&
51 | scroll.metrics.maxScrollExtent <= controller.offset + 200) {
52 |
53 | setState(() {
54 | ifLoading = true;
55 | });
56 | List.generate(30, (i) {
57 | data.add("item ${data.length + 1}");
58 | });
59 | // setState(() {
60 | // data = data;
61 | // ifLoading = false;
62 | // });
63 | Future.delayed(Duration(seconds: 2), () {
64 | setState(() {
65 | data = data;
66 | ifLoading = false;
67 | });
68 | });
69 | }
70 | // return;
71 | },
72 | child: ListView.builder(
73 | controller: controller,
74 | shrinkWrap: true,
75 | itemCount: data.length,
76 | itemBuilder: (context, index) {
77 | return Container(
78 | height: 80,
79 | child: Text(data[index]),
80 | );
81 | },
82 | )),
83 | ),
84 | ifLoading
85 | ? Center(
86 | child: CircularProgressIndicator(),
87 | )
88 | : Container()
89 | ]);
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/lib/pages/sameCity/SameCityPage.dart:
--------------------------------------------------------------------------------
1 | import 'package:douyin_demo/models/PostsModel.dart';
2 | import 'package:douyin_demo/providers/PostsGalleryProvider.dart';
3 | import 'package:douyin_demo/widgets/BottomBar.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:provider/provider.dart';
6 |
7 | class SameCityMain extends StatelessWidget {
8 | const SameCityMain({Key key, this.selIndex}) : super(key: key);
9 | final int selIndex;
10 | @override
11 | Widget build(BuildContext context) {
12 | PostsGalleryProvider provider =
13 | Provider.of(context); //null
14 | double rpx = MediaQuery.of(context).size.width / 750;
15 | ScrollController controller = ScrollController();
16 | return provider == null || provider.model1 == null
17 | ? Scaffold(
18 | // body: Loading(),
19 | )
20 | : Scaffold(
21 | backgroundColor: Theme.of(context).primaryColor,
22 | appBar: AppBar(
23 | title: Text("同城"),
24 | ),
25 | bottomNavigationBar: Container(
26 | decoration: BoxDecoration(color: Colors.black),
27 | child: SafeArea(child: BtmBar(selectIndex: selIndex))),
28 | body: Column(
29 | mainAxisSize: MainAxisSize.min,
30 | children: [
31 | Container(
32 | height: 120 * rpx,
33 | padding: EdgeInsets.all(20 * rpx),
34 | child: Row(
35 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
36 | children: [
37 | Row(
38 | children: [
39 | Icon(
40 | Icons.near_me,
41 | color: Colors.grey[400],
42 | ),
43 | Text(
44 | "自动定位 :上海",
45 | style: TextStyle(color: Colors.grey[400]),
46 | ),
47 | ],
48 | ),
49 | Row(
50 | children: [
51 | Text("切换",
52 | style: TextStyle(color: Colors.grey[400])),
53 | Icon(Icons.arrow_right, color: Colors.grey[400])
54 | ],
55 | ),
56 | ],
57 | )),
58 | Expanded(
59 | child: SingleChildScrollView(
60 | controller: controller,
61 | child: Container(
62 | padding: EdgeInsets.symmetric(horizontal: 10 * rpx),
63 | child: Row(
64 | crossAxisAlignment: CrossAxisAlignment.start,
65 | children: [
66 | Flexible(
67 | flex: 1,
68 | child: WaterFallList(
69 | dataList: provider.model1,
70 | controller: controller,
71 | )),
72 | Flexible(
73 | flex: 1,
74 | child: WaterFallList(
75 | dataList: provider.model2,
76 | controller: controller),
77 | ),
78 | ],
79 | ))))
80 | ],
81 | ),
82 | );
83 | }
84 | }
85 |
86 | class WaterFallList extends StatelessWidget {
87 | const WaterFallList({Key key, this.dataList, this.controller})
88 | : super(key: key);
89 | final List dataList;
90 | final ScrollController controller;
91 | @override
92 | Widget build(BuildContext context) {
93 |
94 | double rpx = MediaQuery.of(context).size.width / 750;
95 | double outPadding=10*rpx;
96 | double eachSide=2*rpx;
97 | return ListView.builder(
98 | controller: controller,
99 | shrinkWrap: true,
100 | itemCount: dataList.length,
101 | itemBuilder: (context, index) {
102 | PostsModel curPosts = dataList[index];
103 | return Container(
104 | margin: EdgeInsets.only(bottom: 10*rpx),
105 | child: Column(
106 | mainAxisSize: MainAxisSize.min,
107 | children: [
108 | Stack(
109 | children: [
110 | Container(
111 | width: 345 * rpx,
112 | padding: EdgeInsets.symmetric(horizontal: eachSide),
113 | height: 345 * curPosts.picsRate * rpx,
114 | child: Image.network(
115 | "https://www.guojio.com/" + curPosts.postsPics,
116 | fit: BoxFit.fitWidth,
117 | )),
118 | Positioned(
119 | bottom: 0,
120 | child: Container(
121 | width: 345 * rpx,
122 | height: 60 * rpx,
123 | padding: EdgeInsets.all(eachSide+10*rpx),
124 | child: Row(
125 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
126 | children: [
127 | Row(
128 | children: [
129 | Icon(Icons.near_me,color: Colors.grey[400],size: 32*rpx,),
130 | Text("1km",style: TextStyle(color:Colors.grey[400],fontSize: 26*rpx),),
131 | ],
132 | ),
133 | Container(
134 | width: 40 * rpx,
135 | height: 40 * rpx,
136 | child: CircleAvatar(
137 | backgroundImage: NetworkImage(
138 | curPosts.makerPhoto,
139 | )))
140 | ],
141 | )),
142 | )
143 | ],
144 | ),
145 | Container(
146 | padding: EdgeInsets.all(10*rpx),
147 | child: Text(
148 | curPosts.postsContent,
149 | maxLines: 3,
150 | overflow: TextOverflow.ellipsis,
151 | style: TextStyle(color: Colors.white,fontSize: 26*rpx),
152 | )
153 | )
154 | ],
155 | )
156 | );
157 | },
158 | );
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/lib/pages/selfHome/HomePage.dart:
--------------------------------------------------------------------------------
1 | import 'package:after_layout/after_layout.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class SelfHomePage extends StatelessWidget {
5 | const SelfHomePage({Key key}) : super(key: key);
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | double rpx = MediaQuery.of(context).size.width / 750;
10 | return Scaffold(
11 | body: Container(
12 | child: HomeMain(
13 | rpx: rpx,
14 | ),
15 | ),
16 | );
17 | }
18 | }
19 |
20 | class HomeMain extends StatefulWidget {
21 | HomeMain({Key key, @required this.rpx}) : super(key: key);
22 | final double rpx;
23 | _HomeMainState createState() => _HomeMainState();
24 | }
25 |
26 | class _HomeMainState extends State with TickerProviderStateMixin {
27 | double extraPicHeight = 0;
28 | BoxFit fitType;
29 | double prev_dy;
30 | double rpx;
31 | AnimationController animationController;
32 | Animation anim;
33 | TabController tabController;
34 | double expanedHeight=300;
35 |
36 | @override
37 | void initState() {
38 | super.initState();
39 | tabController=TabController(vsync: this,length: 3);
40 | prev_dy = 0;
41 | fitType = BoxFit.fitWidth;
42 | animationController =
43 | AnimationController(vsync: this, duration: Duration(milliseconds: 300));
44 | anim = Tween(begin: 0.0, end: 0.0).animate(animationController);
45 | }
46 |
47 | updatePicHeight(changed) {
48 | if (prev_dy == 0) {
49 | prev_dy = changed;
50 | }
51 | extraPicHeight += changed - prev_dy;
52 | if (extraPicHeight >= 200 * widget.rpx) {
53 | fitType = BoxFit.fitHeight;
54 | } else {
55 | fitType = BoxFit.fitWidth;
56 | }
57 | setState(() {
58 | prev_dy = changed;
59 | extraPicHeight = extraPicHeight;
60 | fitType = fitType;
61 | });
62 | }
63 |
64 | updateExpandedHeight(height){
65 | setState(() {
66 | expanedHeight=height;
67 | });
68 | }
69 |
70 | runAnimate() {
71 | setState(() {
72 | anim = Tween(begin: extraPicHeight, end: 0.0).animate(animationController)
73 | ..addListener(() {
74 | if (extraPicHeight >= widget.rpx * 200) {
75 | fitType = BoxFit.fitHeight;
76 | } else {
77 | fitType = BoxFit.fitWidth;
78 | }
79 | setState(() {
80 | extraPicHeight = anim.value;
81 | fitType = fitType;
82 | });
83 | });
84 | prev_dy = 0;
85 | });
86 | }
87 |
88 | @override
89 | Widget build(BuildContext context) {
90 | double rpx = MediaQuery.of(context).size.width / 750;
91 | return Listener(
92 | onPointerMove: (result) {
93 | updatePicHeight(result.position.dy);
94 | },
95 | onPointerUp: (_) {
96 | runAnimate();
97 | animationController.forward(from: 0);
98 | },
99 | child: CustomScrollView(
100 | physics: ClampingScrollPhysics(),
101 | slivers: [
102 | SliverAppBar(
103 | pinned: true,
104 | floating: true,
105 | actions: [
106 | IconButton(
107 | icon: Icon(Icons.search),
108 | onPressed: () {},
109 | ),
110 | IconButton(
111 | icon: Icon(Icons.more_vert),
112 | onPressed: () {},
113 | ),
114 | ],
115 | leading: IconButton(
116 | icon: Icon(Icons.arrow_back),
117 | onPressed: () {},
118 | ),
119 | bottom: PreferredSize(
120 | preferredSize: Size.fromHeight(50), child:TabBar(controller: tabController,tabs: [
121 | Text("作品 91"),
122 | Text("动态 91"),
123 | Text("喜欢 91"),
124 | ],)),
125 | // expandedHeight: 510 * rpx + extraPicHeight,
126 | expandedHeight: expanedHeight+extraPicHeight,
127 | flexibleSpace: Container(
128 | child: TopBarWithCallback(
129 | extraPicHeight: extraPicHeight,
130 | fitType: fitType,
131 | updateHeight: updateExpandedHeight,
132 | ),
133 | ),
134 | ),
135 | SliverList(
136 | delegate: SliverChildBuilderDelegate((context, index) {
137 | return Container(
138 | height: 30,
139 | alignment: Alignment.centerLeft,
140 | color: Colors.blueAccent,
141 | child: Text("This is itm $index"),
142 | margin: EdgeInsets.symmetric(
143 | horizontal: 20 * rpx, vertical: 10 * rpx),
144 | );
145 | }, childCount: 80),
146 | )
147 | ],
148 | ));
149 | }
150 | }
151 |
152 | class TopBarWithCallback extends StatefulWidget {
153 | TopBarWithCallback({Key key,@required this.extraPicHeight, @required this.fitType, @required this.updateHeight}) : super(key: key);
154 | final double extraPicHeight;
155 | final BoxFit fitType;
156 | final Function(double) updateHeight;
157 | _TopBarWithCallbackState createState() => _TopBarWithCallbackState();
158 | }
159 |
160 | class _TopBarWithCallbackState extends State with AfterLayoutMixin {
161 | @override
162 | Widget build(BuildContext context) {
163 | return Container(
164 | child: SliverTopBar(extraPicHeight: widget.extraPicHeight,fitType: widget.fitType,),
165 | );
166 | }
167 |
168 | @override
169 | void afterFirstLayout(BuildContext context) {
170 | RenderBox box=context.findRenderObject();
171 | double height=box.getMaxIntrinsicHeight(MediaQuery.of(context).size.width);
172 | widget.updateHeight(height);
173 | }
174 | }
175 |
176 | class SliverTopBar extends StatelessWidget {
177 | const SliverTopBar(
178 | {Key key, @required this.extraPicHeight, @required this.fitType})
179 | : super(key: key);
180 | final double extraPicHeight;
181 | final BoxFit fitType;
182 | @override
183 | Widget build(BuildContext context) {
184 | double rpx = MediaQuery.of(context).size.width / 750;
185 | return Stack(
186 | children: [
187 | Column(
188 | mainAxisSize: MainAxisSize.min,
189 | children: [
190 | Image.asset(
191 | "lib/images/temple.jpg",
192 | width: 750 * rpx,
193 | height: 300 * rpx + extraPicHeight,
194 | fit: fitType,
195 | ),
196 | Container(
197 | padding: EdgeInsets.only(top: 20 * rpx),
198 | height: 120 * rpx,
199 | child: Row(
200 | mainAxisAlignment: MainAxisAlignment.end,
201 | children: [
202 | Container(
203 | height: 80 * rpx,
204 | width: 330 * rpx,
205 | child: RaisedButton(
206 | color: Color(0xffdc3254),
207 | child: Text(
208 | "+关注",
209 | style: TextStyle(
210 | fontSize: 30 * rpx,
211 | color: Colors.white,
212 | letterSpacing: 3 * rpx),
213 | ),
214 | onPressed: () {},
215 | )),
216 | SizedBox(
217 | width: 10 * rpx,
218 | ),
219 | Container(
220 | decoration: BoxDecoration(
221 | borderRadius: BorderRadius.circular(2),
222 | color: Color(0xff3b3c49),
223 | ),
224 | height: 80 * rpx,
225 | child: IconButton(
226 | icon: Center(
227 | child: Icon(
228 | Icons.arrow_drop_down,
229 | color: Colors.white,
230 | size: 50 * rpx,
231 | )),
232 | onPressed: () {},
233 | ),
234 | ),
235 | SizedBox(
236 | width: 30 * rpx,
237 | )
238 | ],
239 | ),
240 | ),
241 | SizedBox(
242 | height: 100 * rpx,
243 | ),
244 | Container(
245 | width: 750 * rpx,
246 | padding: EdgeInsets.symmetric(horizontal: 30 * rpx),
247 | child: Column(
248 | crossAxisAlignment: CrossAxisAlignment.start,
249 | children: [
250 | Text(
251 | "马友发",
252 | style: TextStyle(
253 | fontSize: 55 * rpx,
254 | color: Colors.white,
255 | fontWeight: FontWeight.bold),
256 | ),
257 | Text("抖音号:1234567",
258 | style: TextStyle(
259 | fontSize: 27 * rpx,
260 | color: Colors.white,
261 | )),
262 | SizedBox(
263 | height: 15 * rpx,
264 | )
265 | ],
266 | )),
267 | Padding(
268 | padding: EdgeInsets.symmetric(horizontal: 20 * rpx),
269 | child: Divider(
270 | color: Colors.grey[700],
271 | ),
272 | ),
273 | Container(
274 | padding: EdgeInsets.symmetric(horizontal: 20 * rpx),
275 | child: Row(
276 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
277 | children: [
278 | Row(
279 | children: [
280 | Icon(
281 | Icons.shop,
282 | color: Color(0xffeacd3f),
283 | ),
284 | Text(
285 | "商品橱窗",
286 | style: TextStyle(color: Color(0xffeacd3f)),
287 | )
288 | ],
289 | ),
290 | Icon(Icons.keyboard_arrow_right, color: Color(0xffeacd3f))
291 | ],
292 | )),
293 | Padding(
294 | padding: EdgeInsets.symmetric(horizontal: 20 * rpx),
295 | child: Divider(
296 | color: Colors.grey[700],
297 | ),
298 | ),
299 | Container(
300 | padding: EdgeInsets.symmetric(horizontal: 20 * rpx),
301 | height: 100 * rpx,
302 | width: 750 * rpx,
303 | child: Text(
304 | "爱神的箭发;黑色大力开发哈的\n阿萨德饭还是电话费拉开始的计划发",
305 | style: TextStyle(color: Colors.white, fontSize: 30 * rpx),
306 | ),
307 | ),
308 | Container(
309 | padding: EdgeInsets.symmetric(horizontal: 20*rpx,vertical: 10*rpx),
310 | child: Row(
311 | children: [
312 | Tag(text:"深圳" ,),
313 | Tag(text: "世界之窗",),
314 | Tag(text: "深圳大学",)
315 | ],
316 | ),
317 | ),
318 | Container(padding: EdgeInsets.symmetric(horizontal: 20*rpx,vertical: 30*rpx),child: Row(children: [
319 | NumWithDesc(numm: "100.2w",desc: "获赞",),
320 | NumWithDesc(numm: "15",desc: "关注",),
321 | NumWithDesc(numm: "10.8w",desc: "粉丝",),
322 | ],),)
323 | ],
324 | ),
325 | Positioned(
326 | top: 250 * rpx + extraPicHeight,
327 | left: 30 * rpx,
328 | child: Container(
329 | decoration: BoxDecoration(
330 | color: Theme.of(context).primaryColor,
331 | borderRadius: BorderRadius.circular(220 * rpx)),
332 | width: 220 * rpx,
333 | height: 220 * rpx,
334 | padding: EdgeInsets.all(10 * rpx),
335 | child: CircleAvatar(
336 | backgroundImage: NetworkImage(
337 | "https://pic2.zhimg.com/v2-a88cd7618933272ca681f86398e6240d_xll.jpg"))),
338 | )
339 | ],
340 | );
341 | }
342 | }
343 |
344 | class Tag extends StatelessWidget {
345 | const Tag({Key key, @required this.text}) : super(key: key);
346 | final String text;
347 | @override
348 | Widget build(BuildContext context) {
349 | double rpx = MediaQuery.of(context).size.width / 750;
350 | return Container(
351 | child: Text(
352 | text,
353 | style: TextStyle(fontSize: 26 * rpx,color: Color(0xff64626e)),
354 | ),
355 | color: Color(0xff3b3c49),
356 | padding: EdgeInsets.all(10 * rpx),
357 | margin: EdgeInsets.only(right: 10*rpx),
358 | );
359 | }
360 | }
361 |
362 | class NumWithDesc extends StatelessWidget {
363 | const NumWithDesc({Key key,@required this.numm,@required this.desc}) : super(key: key);
364 | final String numm;
365 | final String desc;
366 | @override
367 | Widget build(BuildContext context) {
368 |
369 | double rpx=MediaQuery.of(context).size.width/750;
370 | double textSize=35*rpx;
371 | return Padding(
372 | padding: EdgeInsets.only(right: 20*rpx),
373 | child: Row(
374 | children: [
375 | Text(numm,style: TextStyle(fontSize: textSize,color: Colors.white,fontWeight: FontWeight.bold),),
376 | SizedBox(width: 10*rpx,),
377 | Text(desc,style: TextStyle(fontSize: textSize,color: Color(0xff3b3c49)))
378 | ],
379 | )
380 | );
381 | }
382 | }
383 |
384 | // import 'package:flutter/material.dart';
385 |
386 | // class SelfHomePage extends StatelessWidget {
387 | // const SelfHomePage({Key key}) : super(key: key);
388 |
389 | // @override
390 | // Widget build(BuildContext context) {
391 | // return Scaffold(
392 | // body: CustomScrollView(
393 | // physics: ClampingScrollPhysics(),
394 | // slivers: [
395 | // SliverAppBar(
396 | // leading: IconButton(
397 | // icon: Icon(Icons.arrow_back),
398 | // onPressed: () {},
399 | // ),
400 | // floating: true,
401 | // pinned: false,
402 | // snap: true,
403 | // expandedHeight: 250,
404 | // flexibleSpace: FlexibleSpaceBar(
405 | // title: Text("This is Sliver App Bar"),
406 | // background: Image.asset("lib/images/temple.jpg",height: 250,fit: BoxFit.fitWidth,),
407 | // ),
408 | // ),
409 | // SliverList(delegate: SliverChildBuilderDelegate((context,index){
410 | // return Container(child: Text("This is item $index",style: TextStyle(fontSize: 20),),color: Colors.redAccent,);
411 | // },))
412 | // ],
413 | // ),
414 | // );
415 | // }
416 | // }
417 |
--------------------------------------------------------------------------------
/lib/providers/CameraProvider.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:firebase_ml_vision/firebase_ml_vision.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:camera/camera.dart';
6 |
7 | import 'package:path/path.dart' as p;
8 | import 'package:path_provider/path_provider.dart';
9 | import 'package:uuid/uuid.dart';
10 |
11 | class CameraProvider extends State
12 | with ChangeNotifier, TickerProviderStateMixin {
13 | CameraController cameraController;
14 | TabController tabController;
15 | List cameras;
16 | int curCamera = 1;
17 | String appFolder = "";
18 | String fileName;
19 | Widget photoButton;
20 | bool ifMakeVideo = false;
21 | FaceDetector faceDetector;
22 |
23 | CameraProvider() {
24 | tabController = TabController(length: 6, vsync: this);
25 | getCameras();
26 | }
27 |
28 | changeFileName(afterFix) {
29 | String id = Uuid().v4().toString();
30 | fileName = p.join(appFolder, '$id.$afterFix');
31 | notifyListeners();
32 | }
33 |
34 | captureFrame() {
35 |
36 | cameraController.startImageStream((CameraImage image) {
37 | cameraController.stopImageStream();
38 | detectImage(image);
39 | captureFrame();
40 | });
41 | }
42 |
43 | detectImage(image) async {
44 | final List faces = await faceDetector.processImage(
45 | FirebaseVisionImage.fromBytes(image.planes[0].bytes, null));
46 | print(faces);
47 | if (faces.length > 0) {
48 | print(faces[0].headEulerAngleY);
49 | }
50 | }
51 |
52 | getCameras() async {
53 | Directory appDocDir = await getApplicationDocumentsDirectory();
54 | if (!Directory(appDocDir.path).existsSync()) {
55 | appDocDir.createSync();
56 | }
57 | appFolder = appDocDir.path;
58 | cameras = await availableCameras();
59 | cameraController =
60 | CameraController(cameras[curCamera], ResolutionPreset.high);
61 |
62 | try {
63 | await cameraController.initialize();
64 | } catch (e) {
65 | print(e);
66 | }
67 |
68 | // cameraController.startImageStream(onAvailable);
69 |
70 | notifyListeners();
71 | // cameraController.initialize().then((_) {
72 |
73 | // cameraController.prepareForVideoRecording();
74 | // faceDetector = FirebaseVision.instance.faceDetector();
75 | // // captureFrame();
76 | // notifyListeners();
77 | // });
78 | }
79 |
80 | dispose() {
81 | cameraController.dispose();
82 | super.dispose();
83 | }
84 |
85 | changeCamera() {
86 | if (curCamera == 0) {
87 | curCamera = 1;
88 | } else {
89 | curCamera = 0;
90 | }
91 | cameraController =
92 | CameraController(cameras[curCamera], ResolutionPreset.max);
93 | cameraController.initialize().then((_) {
94 | notifyListeners();
95 | });
96 | }
97 |
98 | changePhotoWidget() {
99 | ifMakeVideo = !ifMakeVideo;
100 | notifyListeners();
101 | }
102 |
103 | @override
104 | Widget build(BuildContext context) {
105 | // TODO: implement build
106 | return null;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/lib/providers/PostsGalleryProvider.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:convert';
3 |
4 | import 'package:douyin_demo/models/PostsModel.dart';
5 | import 'package:douyin_demo/widgets/WebRequest.dart';
6 | import 'package:flutter/material.dart';
7 | import 'package:http/http.dart' as http;
8 | import 'package:provider/provider.dart';
9 |
10 |
11 | class PostsGalleryProvider with ChangeNotifier {
12 | List model1 = List();
13 | List model2 = List();
14 | double _len1 = 0;
15 | double _len2 = 0;
16 | List posts = List();
17 |
18 | PostsGalleryProvider() {
19 | getPosts(0, 0);
20 | // notifyListeners();
21 | }
22 |
23 | dispose(){
24 | super.dispose();
25 | }
26 |
27 | Future getPosts(orderType, ifRefresh) async {
28 | Uri url = await WebRequest().generate('posts/getPosts', {
29 | "openId": "ol_BV4zcyVJaOBtOTD5AfpkFERww",
30 | "dataFrom": "0",
31 | "count": "30",
32 | "refreshTime": DateTime.now().toString(),
33 | "currentSel": "1",
34 | "ulo": "0",
35 | "ula": "0"
36 | });
37 |
38 | var response = await http.get(url);
39 | //.then((response) {
40 | // var post = json.decode(response.body)["result"];
41 | setGalleryModel(response.body);
42 | notifyListeners();
43 | }
44 |
45 | setGalleryModel(String items) {
46 | var result = List();
47 |
48 | var posts = json.decode(items)["result"];
49 | // result.add(posts);
50 |
51 | for (var item in posts) {
52 | result.add(PostsModel.fromJson(item));
53 | }
54 | for (var item in result) {
55 | if (_len1 <= _len2) {
56 | item.makerName="";
57 | item.picsPath="";
58 | item.postsLocation="";
59 | item.postsReaded=0;
60 | model1.add(item);
61 | _len1 += item.picsRate;
62 | } else {
63 | model2.add(item);
64 | _len2 += item.picsRate;
65 | }
66 | }
67 | // notifyListeners();
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/lib/providers/RecommendProvider.dart:
--------------------------------------------------------------------------------
1 | // import 'package:flutter/foundation.dart';
2 | import 'package:provider/provider.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class RecommendProvider extends State
6 | with ChangeNotifier, TickerProviderStateMixin {
7 | bool ifShowBottom = true;
8 |
9 | double screenHeight;
10 | List infos = List();
11 | List followed = List();
12 | TabController controller;
13 | MainInfo mainInfo;
14 |
15 | Reply reply;
16 |
17 | RecommendProvider() {
18 | controller = TabController(vsync: this, length: 2);
19 | mainInfo = MainInfo(
20 | avatarUrl:
21 | "https://pic2.zhimg.com/v2-a88cd7618933272ca681f86398e6240d_xll.jpg",
22 | content:
23 | "奥斯卡答复哈士大夫哈师大发输电和健康阿萨德鸿福路口氨基酸的鸿福路口啊,奥斯卡答复哈士大夫哈师大发输电和健康阿萨德鸿福路口氨基酸的鸿福路口啊",
24 | favCount: 109,
25 | replyCount: 212,
26 | shareCount: 317,
27 | userName: "马有发",
28 | videoPath: "lib/images/pingguo.jpeg",
29 | desc: "马友发做的一个有意思的模拟抖音的小App,用的Flutter哦~",
30 | ifFaved: false);
31 |
32 | reply = Reply(
33 | ifFaved: true,
34 | afterReplies: List(),
35 | replyContent: "真可爱,真好看,真厉害~真可爱,真好看,真厉害~",
36 | replyMakerAvatar:
37 | "https://pic2.zhimg.com/v2-a88cd7618933272ca681f86398e6240d_xll.jpg",
38 | replyMakerName: "ABC",
39 | whenReplied: "3小时前");
40 |
41 | infos.add(MainInfo(
42 | avatarUrl:
43 | "https://pic2.zhimg.com/v2-a88cd7618933272ca681f86398e6240d_xll.jpg",
44 | content: "弗兰克斯代理费绿色出行女郎自行车卡水电费卡;双列的会计法第十六届法律深刻江东父老;看氨基酸的;联发科",
45 | favCount: 219,
46 | replyCount: 329,
47 | shareCount: 1222,
48 | userName: "范德彪",
49 | videoPath: "lib/images/sky.jpg",
50 | desc: "这个天空的图有点好看",
51 | ifFaved: true));
52 | infos.add(MainInfo(
53 | avatarUrl:
54 | "https://pic2.zhimg.com/v2-a88cd7618933272ca681f86398e6240d_xll.jpg",
55 | content: "弗兰克斯代理费绿色出行女郎自行车卡水电费卡;双列的会计法第十六届法律深刻江东父老;看氨基酸的;联发科",
56 | favCount: 119,
57 | replyCount: 189,
58 | shareCount: 262,
59 | userName: "马大帅",
60 | videoPath: "lib/images/temple.jpg",
61 | desc: "我喜欢拜佛",
62 | ifFaved: true));
63 |
64 | infos.add(MainInfo(
65 | avatarUrl:
66 | "https://pic2.zhimg.com/v2-a88cd7618933272ca681f86398e6240d_xll.jpg",
67 | content: "弗兰克斯代理费绿色出行女郎自行车卡水电费卡;双列的会计法第十六届法律深刻江东父老;看氨基酸的;联发科",
68 | favCount: 98,
69 | replyCount: 222,
70 | shareCount: 1983,
71 | userName: "ABC",
72 | videoPath: "lib/images/woman.jpg",
73 | desc: "黑色女人有黑色的美",
74 | ifFaved: true));
75 |
76 | followed.add(MainInfo(
77 | avatarUrl:
78 | "https://pic2.zhimg.com/v2-a88cd7618933272ca681f86398e6240d_xll.jpg",
79 | content: "弗兰克斯代理费绿色出行女郎自行车卡水电费卡;双列的会计法第十六届法律深刻江东父老;看氨基酸的;联发科",
80 | favCount: 219,
81 | replyCount: 329,
82 | shareCount: 1222,
83 | userName: "范德彪",
84 | videoPath: "lib/images/whitehouse.jpg",
85 | desc: "这个天空的图有点好看",
86 | ifFaved: true));
87 | followed.add(MainInfo(
88 | avatarUrl:
89 | "https://pic2.zhimg.com/v2-a88cd7618933272ca681f86398e6240d_xll.jpg",
90 | content: "弗兰克斯代理费绿色出行女郎自行车卡水电费卡;双列的会计法第十六届法律深刻江东父老;看氨基酸的;联发科",
91 | favCount: 119,
92 | replyCount: 189,
93 | shareCount: 262,
94 | userName: "马大帅",
95 | videoPath: "lib/images/waterdrop.jpg",
96 | desc: "我喜欢拜佛",
97 | ifFaved: true));
98 |
99 | followed.add(MainInfo(
100 | avatarUrl:
101 | "https://pic2.zhimg.com/v2-a88cd7618933272ca681f86398e6240d_xll.jpg",
102 | content: "弗兰克斯代理费绿色出行女郎自行车卡水电费卡;双列的会计法第十六届法律深刻江东父老;看氨基酸的;联发科",
103 | favCount: 98,
104 | replyCount: 222,
105 | shareCount: 1983,
106 | userName: "ABC",
107 | videoPath: "lib/images/woman2.jpg",
108 | desc: "黑色女人有黑色的美",
109 | ifFaved: true));
110 | }
111 |
112 | setScreenHeight(height) {
113 | screenHeight = height;
114 | notifyListeners();
115 | }
116 |
117 | setTabController(ctrl) {
118 | controller = ctrl;
119 | // notifyListeners();
120 | }
121 |
122 | hideBottomBar() {
123 | ifShowBottom = false;
124 | notifyListeners();
125 | }
126 |
127 | tapFav() {
128 | mainInfo.ifFaved = !mainInfo.ifFaved;
129 | if (mainInfo.ifFaved) {
130 | mainInfo.favCount += 1;
131 | } else {
132 | mainInfo.favCount -= 1;
133 | }
134 | notifyListeners();
135 | }
136 |
137 | @override
138 | Widget build(BuildContext context) {
139 | // TODO: implement build
140 | return null;
141 | }
142 | }
143 |
144 | class MainInfo {
145 | String avatarUrl;
146 | String userName;
147 | String content;
148 | int favCount;
149 | int replyCount;
150 | int shareCount;
151 | String videoPath;
152 | String desc;
153 | bool ifFaved;
154 |
155 | MainInfo(
156 | {this.avatarUrl,
157 | this.content,
158 | this.favCount,
159 | this.replyCount,
160 | this.shareCount,
161 | this.userName,
162 | this.videoPath,
163 | this.desc,
164 | this.ifFaved});
165 | }
166 |
167 | class Reply {
168 | String replyMakerName;
169 | String replyMakerAvatar;
170 | String replyContent;
171 | String whenReplied;
172 | bool ifFaved;
173 | List afterReplies;
174 |
175 | Reply(
176 | {this.ifFaved,
177 | this.afterReplies,
178 | this.replyContent,
179 | this.replyMakerAvatar,
180 | this.replyMakerName,
181 | this.whenReplied});
182 | }
183 |
--------------------------------------------------------------------------------
/lib/utils.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:typed_data';
3 | import 'dart:ui';
4 |
5 | import 'package:camera/camera.dart';
6 | import 'package:firebase_ml_vision/firebase_ml_vision.dart';
7 | import 'package:flutter/foundation.dart';
8 |
9 | typedef HandleDetection = Future Function(FirebaseVisionImage image);
10 |
11 | Future getCamera(CameraLensDirection dir) async {
12 | return await availableCameras().then(
13 | (List cameras) => cameras.firstWhere(
14 | (CameraDescription camera) => camera.lensDirection == dir,
15 | ),
16 | );
17 | }
18 |
19 | Uint8List concatenatePlanes(List planes) {
20 | final WriteBuffer allBytes = WriteBuffer();
21 | planes.forEach((Plane plane) => allBytes.putUint8List(plane.bytes));
22 | return allBytes.done().buffer.asUint8List();
23 | }
24 |
25 | FirebaseVisionImageMetadata buildMetaData(
26 | CameraImage image,
27 | ImageRotation rotation,
28 | ) {
29 | return FirebaseVisionImageMetadata(
30 | rawFormat: image.format.raw,
31 | size: Size(image.width.toDouble(), image.height.toDouble()),
32 | rotation: rotation,
33 | planeData: image.planes.map(
34 | (Plane plane) {
35 | return FirebaseVisionImagePlaneMetadata(
36 | bytesPerRow: plane.bytesPerRow,
37 | height: plane.height,
38 | width: plane.width,
39 | );
40 | },
41 | ).toList(),
42 | );
43 | }
44 |
45 | Future detect(
46 | CameraImage image,
47 | HandleDetection handleDetection,
48 | ImageRotation rotation,
49 | ) async {
50 | return handleDetection(
51 | FirebaseVisionImage.fromBytes(
52 | concatenatePlanes(image.planes),
53 | buildMetaData(image, rotation),
54 | ),
55 | );
56 | }
57 |
58 | ImageRotation rotationIntToImageRotation(int rotation) {
59 | switch (rotation) {
60 | case 0:
61 | return ImageRotation.rotation0;
62 | case 90:
63 | return ImageRotation.rotation90;
64 | case 180:
65 | return ImageRotation.rotation180;
66 | default:
67 | assert(rotation == 270);
68 | return ImageRotation.rotation270;
69 | }
70 | }
--------------------------------------------------------------------------------
/lib/widgets/BottomBar.dart:
--------------------------------------------------------------------------------
1 | import 'package:douyin_demo/main.dart';
2 | import 'package:douyin_demo/pages/CameraPage/CameraMain.dart';
3 | import 'package:douyin_demo/pages/FaceDetect/FaceDetection.dart';
4 | import 'package:douyin_demo/pages/loadData/loadData.dart';
5 | import 'package:douyin_demo/pages/sameCity/SameCityPage.dart';
6 | import 'package:douyin_demo/pages/selfHome/HomePage.dart';
7 | import 'package:douyin_demo/providers/CameraProvider.dart';
8 | import 'package:douyin_demo/providers/PostsGalleryProvider.dart';
9 | import 'package:douyin_demo/providers/RecommendProvider.dart';
10 | import 'package:flutter/material.dart';
11 | import 'package:provider/provider.dart';
12 |
13 | // class BtmBar extends StatelessWidget {
14 | // const BtmBar({Key key}) : super(key: key);
15 |
16 | // @override
17 | // Widget build(BuildContext context) {
18 | // // RecommendProvider provider = Provider.of(context);
19 | // return Container(
20 | // child: Row(
21 | // mainAxisAlignment: MainAxisAlignment.spaceAround,
22 | // children: [
23 | // getBtmTextWidget("首页", true),
24 | // getBtmTextWidget("同城", false),
25 | // AddIcon(),
26 | // getBtmTextWidget("消息", false),
27 | // getBtmTextWidget("我", false),
28 | // ],
29 | // ),
30 | // );
31 | // }
32 | // }
33 |
34 | class BtmBar extends StatefulWidget {
35 | BtmBar({Key key, this.selectIndex}) : super(key: key);
36 | final int selectIndex;
37 |
38 | _BtmBarState createState() => _BtmBarState();
39 | }
40 |
41 | class _BtmBarState extends State {
42 | List selected = List();
43 | List selectItems = List();
44 | @override
45 | void initState() {
46 | super.initState();
47 | for (var i = 0; i < 4; i++) {
48 | selected.add(false);
49 | }
50 | selected[widget.selectIndex] = true;
51 | }
52 |
53 | @override
54 | void dispose() {
55 | // _controller.dispose();
56 | super.dispose();
57 | }
58 |
59 | tapItem(index) {
60 | // selected=List();
61 | // for (var i = 0; i < 4; i++) {
62 | // selected.add(false);
63 | // }
64 | // selected[index]=true;
65 | // setState(() {
66 |
67 | // selected=selected;
68 | // });
69 | switch (index) {
70 | // case 0:
71 | // Navigator.pushAndRemoveUntil(
72 | // context,
73 | // MaterialPageRoute(
74 | // builder: (context) => MyHomePage(
75 | // selIndex: index,
76 | // )),
77 | // ModalRoute.withName("/Home"));
78 | // break;
79 | case 1:
80 | Navigator.pushAndRemoveUntil(
81 | context,
82 | MaterialPageRoute(
83 | builder: (context) => MultiProvider(
84 | providers: [
85 | ChangeNotifierProvider(
86 | builder: (context) => PostsGalleryProvider(),
87 | )
88 | ],
89 | child: SameCityMain(
90 | selIndex: index,
91 | ))),
92 | ModalRoute.withName("/sameCity"));
93 | break;
94 | case 2:
95 | Navigator.pushAndRemoveUntil(
96 | context,
97 | MaterialPageRoute(
98 | builder: (context) => SelfHomePage()),
99 | ModalRoute.withName("/selfHome"));
100 | break;
101 | case 3:
102 | Navigator.of(context).push(new MaterialPageRoute(
103 | builder: (BuildContext context) {
104 | return MultiProvider(
105 | providers: [
106 | ChangeNotifierProvider(
107 | builder: (_) => CameraProvider(),
108 | )
109 | ],
110 | child: CameraPage(
111 | // rpx: MediaQuery.of(context).size.width / 750,
112 | )
113 | );
114 | },
115 | fullscreenDialog: true
116 | ));
117 | break;
118 | default:
119 | break;
120 | }
121 | }
122 |
123 | @override
124 | Widget build(BuildContext context) {
125 | // RecommendProvider provider = Provider.of(context);
126 | double rpx = MediaQuery.of(context).size.width / 750;
127 | return Container(
128 | child: Row(
129 | mainAxisAlignment: MainAxisAlignment.spaceAround,
130 | children: [
131 | Expanded(
132 | flex: 1,
133 | child: getBtmTextWidget("首页", selected[0], () {
134 | tapItem(0);
135 | }, rpx)),
136 | Expanded(
137 | flex: 1,
138 | child: getBtmTextWidget("同城", selected[1], () {
139 | tapItem(1);
140 | }, rpx)),
141 | Expanded(flex: 1, child: AddIcon(tapItem:(){ tapItem(3); },)),
142 | Expanded(
143 | flex: 1,
144 | child: getBtmTextWidget("消息", selected[2], () {
145 | tapItem(2);
146 | }, rpx)),
147 | Expanded(
148 | flex: 1,
149 | child: getBtmTextWidget("我", selected[3], () {
150 | tapItem(3);
151 | }, rpx)),
152 | ],
153 | ),
154 | );
155 | }
156 | }
157 |
158 | getBtmTextWidget(String content, bool ifSelected, tapFunc, double rpx) {
159 | return FlatButton(
160 | onPressed: () {
161 | tapFunc();
162 | },
163 | child: Text("$content",
164 | style: ifSelected
165 | ? TextStyle(
166 | fontSize: 30 * rpx,
167 | color: Colors.white,
168 | fontWeight: FontWeight.w900)
169 | : TextStyle(
170 | fontSize: 30 * rpx,
171 | color: Colors.grey[600],
172 | fontWeight: FontWeight.w900)));
173 | }
174 |
175 | class AddIcon extends StatelessWidget {
176 | const AddIcon({Key key,@required this.tapItem}) : super(key: key);
177 | final VoidCallback tapItem;
178 | @override
179 | Widget build(BuildContext context) {
180 | double rpx = MediaQuery.of(context).size.width / 750;
181 | double iconHeight = 55 * rpx;
182 | double totalWidth = 90 * rpx;
183 | double eachSide = 5 * rpx;
184 | return Container(
185 | // decoration: BoxDecoration(),
186 | padding: EdgeInsets.symmetric(horizontal: 30 * rpx),
187 | height: iconHeight,
188 | width: 150 * rpx,
189 | child: FlatButton(
190 | padding: EdgeInsets.all(0),
191 | onPressed: (){tapItem();},
192 | child: Stack(
193 | children: [
194 | Positioned(
195 | height: iconHeight,
196 | width: totalWidth - eachSide,
197 | child: Container(
198 | decoration: BoxDecoration(
199 | color: Colors.cyan, borderRadius: BorderRadius.circular(10)),
200 | ),
201 | ),
202 | Positioned(
203 | height: iconHeight,
204 | width: totalWidth - eachSide,
205 | right: 0,
206 | child: Container(
207 | decoration: BoxDecoration(
208 | color: Colors.redAccent,
209 | borderRadius: BorderRadius.circular(10)),
210 | ),
211 | ),
212 | Positioned(
213 | height: iconHeight,
214 | width: totalWidth - eachSide * 2,
215 | right: eachSide,
216 | child: Container(
217 | decoration: BoxDecoration(
218 | color: Colors.white, borderRadius: BorderRadius.circular(10)),
219 | child: Icon(Icons.add),
220 | ),
221 | ),
222 | ],
223 | )
224 | ),
225 | );
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/lib/widgets/FavAnimation.dart:
--------------------------------------------------------------------------------
1 | // import 'package:flutter/material.dart';
2 |
3 | // class AnimateFav extends StatefulWidget {
4 | // AnimateFav({Key key, this.size}) : super(key: key);
5 | // final double size;
6 |
7 | // _AnimateFavState createState() => _AnimateFavState();
8 | // }
9 |
10 | // class _AnimateFavState extends State
11 | // with TickerProviderStateMixin {
12 | // AnimationController _controller_1;
13 | // AnimationController _controller_2;
14 | // Animation _animation_1;
15 | // Animation _animation_2;
16 | // Animation curAnimation;
17 | // double rpx;
18 | // @override
19 | // void initState() {
20 | // super.initState();
21 |
22 | // _controller_1 =
23 | // AnimationController(vsync: this, duration: Duration(milliseconds: 300));
24 | // _controller_2 =
25 | // AnimationController(vsync: this, duration: Duration(milliseconds: 200));
26 | // _animation_1 = Tween(begin: 0.0, end: 1.3).animate(_controller_1)
27 | // ..addStatusListener((status) {
28 | // if (status == AnimationStatus.completed) {
29 | // _controller_2.forward(from: 0);
30 | // setState(() {
31 | // curAnimation = _animation_2;
32 | // });
33 | // }
34 | // })
35 | // ..addListener(() {
36 | // setState(() {});
37 | // });
38 | // _animation_2 = Tween(begin: 1.3, end: 1.0).animate(_controller_2)
39 | // ..addListener(() {
40 | // setState(() {});
41 | // });
42 | // curAnimation = _animation_1;
43 | // _controller_1.forward(from: 0);
44 | // }
45 |
46 | // @override
47 | // Widget build(BuildContext context) {
48 | // rpx = MediaQuery.of(context).size.width / 750;
49 | // return Center(
50 | // child: Icon(
51 | // Icons.favorite,
52 | // size: widget.size * curAnimation.value,
53 | // color: Colors.redAccent,
54 | // ));
55 | // }
56 | // }
57 |
58 | // class AnimatedUnFav extends StatefulWidget {
59 | // AnimatedUnFav({Key key,@required this.size}) : super(key: key);
60 | // final double size;
61 | // _AnimatedUnFavState createState() => _AnimatedUnFavState();
62 | // }
63 |
64 | // class _AnimatedUnFavState extends State with TickerProviderStateMixin {
65 | // AnimationController _controller_1;
66 | // AnimationController _controller_2;
67 | // Animation _animation_1;
68 | // Animation _animation_2;
69 | // Animation curAnimation;
70 | // Color curColor;
71 | // @override
72 | // void initState() {
73 | // super.initState();
74 | // curColor=Colors.redAccent;
75 | // _controller_1 =
76 | // AnimationController(vsync: this, duration: Duration(milliseconds: 100));
77 | // _controller_2 =
78 | // AnimationController(vsync: this, duration: Duration(milliseconds: 100));
79 | // _animation_1 = Tween(begin: 1.0, end: 1.2).animate(_controller_1)
80 | // ..addStatusListener((status) {
81 | // if (status == AnimationStatus.completed) {
82 | // _controller_2.forward(from: 0);
83 | // setState(() {
84 | // curAnimation = _animation_2;
85 | // curColor=Colors.grey[100];
86 | // });
87 | // }
88 | // })
89 | // ..addListener(() {
90 | // setState(() {});
91 | // });
92 | // _animation_2 = Tween(begin: 1.2, end: 1.0).animate(_controller_2)
93 | // ..addListener(() {
94 | // setState(() {});
95 | // });
96 | // curAnimation = _animation_1;
97 | // _controller_1.forward(from: 0);
98 | // }
99 |
100 | // @override
101 | // Widget build(BuildContext context) {
102 | // // rpx = MediaQuery.of(context).size.width / 750;
103 | // return Center(
104 | // child: Icon(
105 | // Icons.favorite,
106 | // size: widget.size * curAnimation.value,
107 | // color: curColor,
108 | // ));
109 | // }
110 | // }
111 |
112 | import 'dart:async';
113 |
114 | import 'package:douyin_demo/providers/RecommendProvider.dart';
115 | import 'package:flutter/material.dart';
116 | // import 'package:provider/provider.dart';
117 |
118 | // class AnimatePositiveIcon extends StatefulWidget {
119 | // AnimatePositiveIcon({Key key, @required this.size, this.callback})
120 | // : super(key: key);
121 | // final double size;
122 | // final VoidCallback callback;
123 | // _AnimatePositiveIconState createState() => _AnimatePositiveIconState();
124 | // }
125 |
126 | // class _AnimatePositiveIconState extends State
127 | // with TickerProviderStateMixin {
128 | // AnimationController _controller1;
129 | // AnimationController _controller2;
130 | // AnimationController _controller3;
131 |
132 | // Animation _animation1;
133 | // Animation _animation2;
134 | // Animation _animation3;
135 |
136 | // Animation curAnimation;
137 |
138 | // Color curColor;
139 |
140 | // @override
141 | // void initState() {
142 | // super.initState();
143 | // _controller1 =
144 | // AnimationController(vsync: this, duration: Duration(milliseconds: 150));
145 | // _controller2 =
146 | // AnimationController(vsync: this, duration: Duration(milliseconds: 200));
147 | // _controller3 =
148 | // AnimationController(vsync: this, duration: Duration(milliseconds: 60));
149 |
150 | // curColor = Colors.grey[100];
151 | // _animation1 = Tween(begin: 1.0, end: 0.0).animate(_controller1)
152 | // ..addListener(() {
153 | // setState(() {});
154 | // })
155 | // ..addStatusListener((status) {
156 | // if (status == AnimationStatus.completed) {
157 | // _controller2.forward(from: 0);
158 | // curAnimation = _animation2;
159 | // curColor = Colors.redAccent;
160 | // }
161 | // });
162 |
163 | // _animation2 = Tween(begin: 0.0, end: 1.2).animate(_controller2)
164 | // ..addListener(() {
165 | // setState(() {});
166 | // })
167 | // ..addStatusListener((status) {
168 | // if (status == AnimationStatus.completed) {
169 | // _controller3.forward(from: 0);
170 | // curAnimation = _animation3;
171 | // }
172 | // });
173 |
174 | // _animation3 = Tween(begin: 1.2, end: 1.0).animate(_controller3)
175 | // ..addListener(() {
176 | // setState(() {});
177 | // })
178 | // ..addStatusListener((status) {
179 | // if (status == AnimationStatus.completed && widget.callback != null) {
180 | // widget.callback();
181 | // }
182 | // });
183 | // // _controller1.forward(from: 0).then((_) {
184 | // // _controller2.forward(from: 0).then((_){
185 | // // _controller3.forward(from: 0);
186 | // // });
187 | // // });
188 | // curAnimation = _animation1;
189 | // _controller1.forward(from: 0);
190 | // }
191 |
192 | // @override
193 | // Widget build(BuildContext context) {
194 | // return Container(
195 | // child: Icon(
196 | // Icons.favorite,
197 | // size: widget.size * curAnimation.value,
198 | // color: curColor,
199 | // ),
200 | // );
201 | // }
202 | // }
203 |
204 | // class AnimateNegtiveIcon extends StatefulWidget {
205 | // AnimateNegtiveIcon(
206 | // {Key key,
207 | // @required this.size,
208 | // @required this.icon,
209 | // @required this.startColor,
210 | // @required this.endColor,
211 | // this.callback})
212 | // : super(key: key);
213 | // final double size;
214 | // final IconData icon;
215 | // final VoidCallback callback;
216 | // final Color startColor;
217 | // final Color endColor;
218 | // _AnimateNegtiveIconState createState() => _AnimateNegtiveIconState();
219 | // }
220 |
221 | // class _AnimateNegtiveIconState extends State
222 | // with TickerProviderStateMixin {
223 | // AnimationController _controller1;
224 | // AnimationController _controller2;
225 |
226 | // Animation _animation1;
227 | // Animation _animation2;
228 |
229 | // Animation curAnimation;
230 |
231 | // Color curColor;
232 |
233 | // @override
234 | // void initState() {
235 | // super.initState();
236 | // _controller1 =
237 | // AnimationController(vsync: this, duration: Duration(milliseconds: 200));
238 | // _controller2 =
239 | // AnimationController(vsync: this, duration: Duration(milliseconds: 200));
240 |
241 | // curColor = widget.startColor;
242 | // _animation1 = Tween(begin: 1.0, end: 1.2).animate(_controller1)
243 | // ..addListener(() {
244 | // setState(() {});
245 | // })
246 | // ..addStatusListener((status) {
247 | // if (status == AnimationStatus.completed) {
248 | // _controller2.forward(from: 0);
249 | // curAnimation = _animation2;
250 | // curColor = widget.endColor;
251 | // }
252 | // });
253 |
254 | // _animation2 = Tween(begin: 1.2, end: 1.0).animate(_controller2)
255 | // ..addListener(() {
256 | // setState(() {});
257 | // })
258 | // ..addStatusListener((status) {
259 | // if (status == AnimationStatus.completed && widget.callback != null) {
260 | // Timer(Duration(milliseconds: 100), () {
261 | // widget.callback();
262 | // });
263 | // }
264 | // });
265 | // // _controller1.forward(from: 0).then((_) {
266 | // // _controller2.forward(from: 0).then((_){
267 | // // _controller3.forward(from: 0);
268 | // // });
269 | // // });
270 | // curAnimation = _animation1;
271 | // }
272 |
273 | // @override
274 | // Widget build(BuildContext context) {
275 | // return IconButton(
276 | // padding: EdgeInsets.all(0),
277 | // onPressed: () {
278 | // _controller1.forward(from: 0);
279 | // },
280 | // icon: Icon(
281 | // widget.icon,
282 | // semanticLabel: "label",
283 | // size: widget.size * curAnimation.value,
284 | // color: curColor,
285 | // ));
286 | // }
287 | // }
288 |
289 | class AnimatedIconWidget extends StatefulWidget {
290 | AnimatedIconWidget(
291 | {Key key,
292 | @required this.animationList,
293 | @required this.icon,
294 | @required this.size,
295 | this.callback,
296 | this.callbackDelay,
297 | this.provider})
298 | : super(key: key);
299 | final List animationList;
300 | final IconData icon;
301 | final VoidCallback callback;
302 | final double size;
303 | final RecommendProvider provider;
304 | final Duration callbackDelay;
305 | _AnimatedIconWidgetState createState() => _AnimatedIconWidgetState();
306 | }
307 |
308 | class _AnimatedIconWidgetState extends State
309 | with TickerProviderStateMixin {
310 | List anis = List();
311 | List controllers = List();
312 | List> animations = List>();
313 | Animation curAnim;
314 | Color curColor;
315 | int curIndex = 0;
316 | List ifAdded = List();
317 | double curSize;
318 | bool ifInit = true;
319 |
320 | loopAnimation(index) {
321 | curColor = curColor == null ? anis.first.color : curColor;
322 | if (index < controllers.length - 1) {
323 | if (!ifAdded[index]) {
324 | animations[index] = animations[index]
325 | ..addStatusListener((status) {
326 | if (status == AnimationStatus.completed) {
327 | curAnim = animations[index + 1];
328 | curColor = anis[index + 1].color;
329 |
330 | controllers[index + 1].forward(from: 0);
331 | loopAnimation(index + 1);
332 | }
333 | })
334 | ..addListener(() {
335 | setState(() {});
336 | });
337 | ifAdded[index] = true;
338 | }
339 | } else if (index == controllers.length - 1) {
340 | if (!ifAdded[index]) {
341 | animations[index] = animations[index]
342 | ..addStatusListener((status) {
343 | curColor = anis[index].color;
344 | if (status == AnimationStatus.completed) {
345 | if (widget.callback != null) {
346 | if (widget.callbackDelay == null) {
347 | widget.callback();
348 | } else {
349 | Timer(widget.callbackDelay, () {
350 | widget.callback();
351 | });
352 | }
353 | }
354 | }
355 | })
356 | ..addListener(() {
357 | setState(() {});
358 | });
359 | ifAdded[index] = true;
360 | }
361 | }
362 | }
363 |
364 | @override
365 | void initState() {
366 | super.initState();
367 | anis = widget.animationList;
368 |
369 | List.generate(anis.length, (index) {
370 | var curAni = anis[index];
371 | ifAdded.add(false);
372 | controllers.add(
373 | AnimationController(vsync: this, duration: anis[index].duration));
374 | animations.add(Tween(begin: curAni.start, end: curAni.end)
375 | .animate(controllers[index]));
376 | });
377 | curAnim = animations.first;
378 | loopAnimation(0);
379 | }
380 |
381 | @override
382 | Widget build(BuildContext context) {
383 | return IconButton(
384 | padding: EdgeInsets.all(0),
385 | onPressed: () {
386 | controllers.first.forward(from: 0);
387 | },
388 | icon: Icon(
389 | widget.icon,
390 | size: widget.size * curAnim.value,
391 | color: curColor,
392 | ),
393 | );
394 | }
395 | }
396 |
397 | class IconAnimationStage {
398 | double start;
399 | double end;
400 | Color color;
401 | Duration duration;
402 |
403 | IconAnimationStage({this.color, this.duration, this.end, this.start});
404 | }
405 |
--------------------------------------------------------------------------------
/lib/widgets/WebRequest.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:shared_preferences/shared_preferences.dart';
4 |
5 | class WebRequest extends Object {
6 | //
7 | bool ifPrd;
8 | bool ifIos;
9 | Future generate(String path, Map params) async {
10 | final prefs = await SharedPreferences.getInstance();
11 | String hosts;
12 | String scheme;
13 | int ports;
14 |
15 | if (prefs.getBool("ifPrd")) {
16 | hosts = prefs.getString('urlPath_p');
17 | scheme = prefs.getString('scheme_p');
18 | ports = prefs.getInt('ports_p');
19 | } else {
20 | if (prefs.getBool("ifIOS")) {
21 | hosts = prefs.getString('urlPath_ios_d');
22 | scheme = prefs.getString('scheme_ios_d');
23 | ports = prefs.getInt('ports_ios_d');
24 | } else {
25 | hosts = prefs.getString('urlPath_and_d');
26 | scheme = prefs.getString('scheme_and_d');
27 | ports = prefs.getInt('ports_and_d');
28 | }
29 | }
30 |
31 | if(prefs.getBool("ifReal_d")){
32 | hosts = prefs.getString('urlPath_real_d');
33 | scheme = prefs.getString('scheme_real_d');
34 | ports = prefs.getInt('ports_real_d');
35 | }
36 | Uri url = Uri(
37 | scheme: scheme, //http https
38 | host: hosts,
39 | port: ports,
40 | path: path,
41 | queryParameters: params);
42 | return url;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | after_layout:
5 | dependency: "direct main"
6 | description:
7 | name: after_layout
8 | url: "https://pub.flutter-io.cn"
9 | source: hosted
10 | version: "1.0.7+2"
11 | analyzer:
12 | dependency: transitive
13 | description:
14 | name: analyzer
15 | url: "https://pub.flutter-io.cn"
16 | source: hosted
17 | version: "0.38.4"
18 | archive:
19 | dependency: transitive
20 | description:
21 | name: archive
22 | url: "https://pub.flutter-io.cn"
23 | source: hosted
24 | version: "2.0.11"
25 | args:
26 | dependency: transitive
27 | description:
28 | name: args
29 | url: "https://pub.flutter-io.cn"
30 | source: hosted
31 | version: "1.5.2"
32 | async:
33 | dependency: transitive
34 | description:
35 | name: async
36 | url: "https://pub.flutter-io.cn"
37 | source: hosted
38 | version: "2.4.0"
39 | boolean_selector:
40 | dependency: transitive
41 | description:
42 | name: boolean_selector
43 | url: "https://pub.flutter-io.cn"
44 | source: hosted
45 | version: "1.0.5"
46 | build:
47 | dependency: transitive
48 | description:
49 | name: build
50 | url: "https://pub.flutter-io.cn"
51 | source: hosted
52 | version: "1.2.0"
53 | build_config:
54 | dependency: transitive
55 | description:
56 | name: build_config
57 | url: "https://pub.flutter-io.cn"
58 | source: hosted
59 | version: "0.4.1+1"
60 | build_daemon:
61 | dependency: transitive
62 | description:
63 | name: build_daemon
64 | url: "https://pub.flutter-io.cn"
65 | source: hosted
66 | version: "2.1.0"
67 | build_resolvers:
68 | dependency: transitive
69 | description:
70 | name: build_resolvers
71 | url: "https://pub.flutter-io.cn"
72 | source: hosted
73 | version: "1.1.1"
74 | build_runner:
75 | dependency: "direct dev"
76 | description:
77 | name: build_runner
78 | url: "https://pub.flutter-io.cn"
79 | source: hosted
80 | version: "1.7.1"
81 | build_runner_core:
82 | dependency: transitive
83 | description:
84 | name: build_runner_core
85 | url: "https://pub.flutter-io.cn"
86 | source: hosted
87 | version: "4.1.0"
88 | built_collection:
89 | dependency: transitive
90 | description:
91 | name: built_collection
92 | url: "https://pub.flutter-io.cn"
93 | source: hosted
94 | version: "4.2.2"
95 | built_value:
96 | dependency: transitive
97 | description:
98 | name: built_value
99 | url: "https://pub.flutter-io.cn"
100 | source: hosted
101 | version: "6.7.1"
102 | camera:
103 | dependency: "direct main"
104 | description:
105 | name: camera
106 | url: "https://pub.flutter-io.cn"
107 | source: hosted
108 | version: "0.5.6"
109 | charcode:
110 | dependency: transitive
111 | description:
112 | name: charcode
113 | url: "https://pub.flutter-io.cn"
114 | source: hosted
115 | version: "1.1.2"
116 | checked_yaml:
117 | dependency: transitive
118 | description:
119 | name: checked_yaml
120 | url: "https://pub.flutter-io.cn"
121 | source: hosted
122 | version: "1.0.2"
123 | code_builder:
124 | dependency: transitive
125 | description:
126 | name: code_builder
127 | url: "https://pub.flutter-io.cn"
128 | source: hosted
129 | version: "3.2.0"
130 | collection:
131 | dependency: transitive
132 | description:
133 | name: collection
134 | url: "https://pub.flutter-io.cn"
135 | source: hosted
136 | version: "1.14.11"
137 | convert:
138 | dependency: transitive
139 | description:
140 | name: convert
141 | url: "https://pub.flutter-io.cn"
142 | source: hosted
143 | version: "2.1.1"
144 | crypto:
145 | dependency: transitive
146 | description:
147 | name: crypto
148 | url: "https://pub.flutter-io.cn"
149 | source: hosted
150 | version: "2.1.3"
151 | csslib:
152 | dependency: transitive
153 | description:
154 | name: csslib
155 | url: "https://pub.flutter-io.cn"
156 | source: hosted
157 | version: "0.16.1"
158 | cupertino_icons:
159 | dependency: "direct main"
160 | description:
161 | name: cupertino_icons
162 | url: "https://pub.flutter-io.cn"
163 | source: hosted
164 | version: "0.1.2"
165 | dart_style:
166 | dependency: transitive
167 | description:
168 | name: dart_style
169 | url: "https://pub.flutter-io.cn"
170 | source: hosted
171 | version: "1.3.1"
172 | firebase_ml_vision:
173 | dependency: "direct main"
174 | description:
175 | name: firebase_ml_vision
176 | url: "https://pub.flutter-io.cn"
177 | source: hosted
178 | version: "0.9.2+2"
179 | fixnum:
180 | dependency: transitive
181 | description:
182 | name: fixnum
183 | url: "https://pub.flutter-io.cn"
184 | source: hosted
185 | version: "0.10.9"
186 | flutter:
187 | dependency: "direct main"
188 | description: flutter
189 | source: sdk
190 | version: "0.0.0"
191 | flutter_page_indicator:
192 | dependency: transitive
193 | description:
194 | name: flutter_page_indicator
195 | url: "https://pub.flutter-io.cn"
196 | source: hosted
197 | version: "0.0.3"
198 | flutter_swiper:
199 | dependency: "direct main"
200 | description:
201 | name: flutter_swiper
202 | url: "https://pub.flutter-io.cn"
203 | source: hosted
204 | version: "1.1.6"
205 | flutter_test:
206 | dependency: "direct dev"
207 | description: flutter
208 | source: sdk
209 | version: "0.0.0"
210 | front_end:
211 | dependency: transitive
212 | description:
213 | name: front_end
214 | url: "https://pub.flutter-io.cn"
215 | source: hosted
216 | version: "0.1.26"
217 | glob:
218 | dependency: transitive
219 | description:
220 | name: glob
221 | url: "https://pub.flutter-io.cn"
222 | source: hosted
223 | version: "1.1.7"
224 | graphs:
225 | dependency: transitive
226 | description:
227 | name: graphs
228 | url: "https://pub.flutter-io.cn"
229 | source: hosted
230 | version: "0.2.0"
231 | html:
232 | dependency: transitive
233 | description:
234 | name: html
235 | url: "https://pub.flutter-io.cn"
236 | source: hosted
237 | version: "0.14.0+3"
238 | http:
239 | dependency: transitive
240 | description:
241 | name: http
242 | url: "https://pub.flutter-io.cn"
243 | source: hosted
244 | version: "0.12.0+2"
245 | http_multi_server:
246 | dependency: transitive
247 | description:
248 | name: http_multi_server
249 | url: "https://pub.flutter-io.cn"
250 | source: hosted
251 | version: "2.1.0"
252 | http_parser:
253 | dependency: transitive
254 | description:
255 | name: http_parser
256 | url: "https://pub.flutter-io.cn"
257 | source: hosted
258 | version: "3.1.3"
259 | image:
260 | dependency: transitive
261 | description:
262 | name: image
263 | url: "https://pub.flutter-io.cn"
264 | source: hosted
265 | version: "2.1.4"
266 | image_gallery_saver:
267 | dependency: "direct main"
268 | description:
269 | name: image_gallery_saver
270 | url: "https://pub.flutter-io.cn"
271 | source: hosted
272 | version: "1.2.2"
273 | image_picker:
274 | dependency: "direct main"
275 | description:
276 | name: image_picker
277 | url: "https://pub.flutter-io.cn"
278 | source: hosted
279 | version: "0.6.1+8"
280 | image_picker_saver:
281 | dependency: "direct main"
282 | description:
283 | name: image_picker_saver
284 | url: "https://pub.flutter-io.cn"
285 | source: hosted
286 | version: "0.3.0"
287 | io:
288 | dependency: transitive
289 | description:
290 | name: io
291 | url: "https://pub.flutter-io.cn"
292 | source: hosted
293 | version: "0.3.3"
294 | js:
295 | dependency: transitive
296 | description:
297 | name: js
298 | url: "https://pub.flutter-io.cn"
299 | source: hosted
300 | version: "0.6.1+1"
301 | json_annotation:
302 | dependency: "direct main"
303 | description:
304 | name: json_annotation
305 | url: "https://pub.flutter-io.cn"
306 | source: hosted
307 | version: "3.0.0"
308 | json_serializable:
309 | dependency: "direct dev"
310 | description:
311 | name: json_serializable
312 | url: "https://pub.flutter-io.cn"
313 | source: hosted
314 | version: "3.2.2"
315 | kernel:
316 | dependency: transitive
317 | description:
318 | name: kernel
319 | url: "https://pub.flutter-io.cn"
320 | source: hosted
321 | version: "0.3.26"
322 | logging:
323 | dependency: transitive
324 | description:
325 | name: logging
326 | url: "https://pub.flutter-io.cn"
327 | source: hosted
328 | version: "0.11.3+2"
329 | lpinyin:
330 | dependency: "direct main"
331 | description:
332 | name: lpinyin
333 | url: "https://pub.flutter-io.cn"
334 | source: hosted
335 | version: "1.0.7"
336 | marquee:
337 | dependency: "direct main"
338 | description:
339 | name: marquee
340 | url: "https://pub.flutter-io.cn"
341 | source: hosted
342 | version: "1.3.0"
343 | marquee_flutter:
344 | dependency: "direct main"
345 | description:
346 | name: marquee_flutter
347 | url: "https://pub.flutter-io.cn"
348 | source: hosted
349 | version: "0.1.4"
350 | matcher:
351 | dependency: transitive
352 | description:
353 | name: matcher
354 | url: "https://pub.flutter-io.cn"
355 | source: hosted
356 | version: "0.12.6"
357 | meta:
358 | dependency: transitive
359 | description:
360 | name: meta
361 | url: "https://pub.flutter-io.cn"
362 | source: hosted
363 | version: "1.1.8"
364 | mime:
365 | dependency: transitive
366 | description:
367 | name: mime
368 | url: "https://pub.flutter-io.cn"
369 | source: hosted
370 | version: "0.9.6+3"
371 | package_config:
372 | dependency: transitive
373 | description:
374 | name: package_config
375 | url: "https://pub.flutter-io.cn"
376 | source: hosted
377 | version: "1.1.0"
378 | package_resolver:
379 | dependency: transitive
380 | description:
381 | name: package_resolver
382 | url: "https://pub.flutter-io.cn"
383 | source: hosted
384 | version: "1.0.10"
385 | path:
386 | dependency: "direct main"
387 | description:
388 | name: path
389 | url: "https://pub.flutter-io.cn"
390 | source: hosted
391 | version: "1.6.4"
392 | path_provider:
393 | dependency: "direct main"
394 | description:
395 | name: path_provider
396 | url: "https://pub.flutter-io.cn"
397 | source: hosted
398 | version: "1.3.1"
399 | pedantic:
400 | dependency: transitive
401 | description:
402 | name: pedantic
403 | url: "https://pub.flutter-io.cn"
404 | source: hosted
405 | version: "1.8.0+1"
406 | petitparser:
407 | dependency: transitive
408 | description:
409 | name: petitparser
410 | url: "https://pub.flutter-io.cn"
411 | source: hosted
412 | version: "2.4.0"
413 | platform:
414 | dependency: transitive
415 | description:
416 | name: platform
417 | url: "https://pub.flutter-io.cn"
418 | source: hosted
419 | version: "2.2.1"
420 | pool:
421 | dependency: transitive
422 | description:
423 | name: pool
424 | url: "https://pub.flutter-io.cn"
425 | source: hosted
426 | version: "1.4.0"
427 | provider:
428 | dependency: "direct main"
429 | description:
430 | name: provider
431 | url: "https://pub.flutter-io.cn"
432 | source: hosted
433 | version: "3.1.0"
434 | pub_semver:
435 | dependency: transitive
436 | description:
437 | name: pub_semver
438 | url: "https://pub.flutter-io.cn"
439 | source: hosted
440 | version: "1.4.2"
441 | pubspec_parse:
442 | dependency: transitive
443 | description:
444 | name: pubspec_parse
445 | url: "https://pub.flutter-io.cn"
446 | source: hosted
447 | version: "0.1.5"
448 | quiver:
449 | dependency: transitive
450 | description:
451 | name: quiver
452 | url: "https://pub.flutter-io.cn"
453 | source: hosted
454 | version: "2.0.5"
455 | shared_preferences:
456 | dependency: "direct main"
457 | description:
458 | name: shared_preferences
459 | url: "https://pub.flutter-io.cn"
460 | source: hosted
461 | version: "0.5.3+4"
462 | shelf:
463 | dependency: transitive
464 | description:
465 | name: shelf
466 | url: "https://pub.flutter-io.cn"
467 | source: hosted
468 | version: "0.7.5"
469 | shelf_web_socket:
470 | dependency: transitive
471 | description:
472 | name: shelf_web_socket
473 | url: "https://pub.flutter-io.cn"
474 | source: hosted
475 | version: "0.2.3"
476 | sky_engine:
477 | dependency: transitive
478 | description: flutter
479 | source: sdk
480 | version: "0.0.99"
481 | source_gen:
482 | dependency: transitive
483 | description:
484 | name: source_gen
485 | url: "https://pub.flutter-io.cn"
486 | source: hosted
487 | version: "0.9.4+5"
488 | source_span:
489 | dependency: transitive
490 | description:
491 | name: source_span
492 | url: "https://pub.flutter-io.cn"
493 | source: hosted
494 | version: "1.5.5"
495 | stack_trace:
496 | dependency: transitive
497 | description:
498 | name: stack_trace
499 | url: "https://pub.flutter-io.cn"
500 | source: hosted
501 | version: "1.9.3"
502 | sticky_headers:
503 | dependency: "direct main"
504 | description:
505 | name: sticky_headers
506 | url: "https://pub.flutter-io.cn"
507 | source: hosted
508 | version: "0.1.8"
509 | stream_channel:
510 | dependency: transitive
511 | description:
512 | name: stream_channel
513 | url: "https://pub.flutter-io.cn"
514 | source: hosted
515 | version: "2.0.0"
516 | stream_transform:
517 | dependency: transitive
518 | description:
519 | name: stream_transform
520 | url: "https://pub.flutter-io.cn"
521 | source: hosted
522 | version: "0.0.19"
523 | stretchy_header:
524 | dependency: "direct main"
525 | description:
526 | name: stretchy_header
527 | url: "https://pub.flutter-io.cn"
528 | source: hosted
529 | version: "1.0.5"
530 | string_scanner:
531 | dependency: transitive
532 | description:
533 | name: string_scanner
534 | url: "https://pub.flutter-io.cn"
535 | source: hosted
536 | version: "1.0.5"
537 | term_glyph:
538 | dependency: transitive
539 | description:
540 | name: term_glyph
541 | url: "https://pub.flutter-io.cn"
542 | source: hosted
543 | version: "1.1.0"
544 | test_api:
545 | dependency: transitive
546 | description:
547 | name: test_api
548 | url: "https://pub.flutter-io.cn"
549 | source: hosted
550 | version: "0.2.11"
551 | timing:
552 | dependency: transitive
553 | description:
554 | name: timing
555 | url: "https://pub.flutter-io.cn"
556 | source: hosted
557 | version: "0.1.1+2"
558 | transformer_page_view:
559 | dependency: transitive
560 | description:
561 | name: transformer_page_view
562 | url: "https://pub.flutter-io.cn"
563 | source: hosted
564 | version: "0.1.6"
565 | typed_data:
566 | dependency: transitive
567 | description:
568 | name: typed_data
569 | url: "https://pub.flutter-io.cn"
570 | source: hosted
571 | version: "1.1.6"
572 | uuid:
573 | dependency: "direct main"
574 | description:
575 | name: uuid
576 | url: "https://pub.flutter-io.cn"
577 | source: hosted
578 | version: "2.0.2"
579 | vector_math:
580 | dependency: transitive
581 | description:
582 | name: vector_math
583 | url: "https://pub.flutter-io.cn"
584 | source: hosted
585 | version: "2.0.8"
586 | video_player:
587 | dependency: "direct main"
588 | description:
589 | name: video_player
590 | url: "https://pub.flutter-io.cn"
591 | source: hosted
592 | version: "0.10.2+1"
593 | watcher:
594 | dependency: transitive
595 | description:
596 | name: watcher
597 | url: "https://pub.flutter-io.cn"
598 | source: hosted
599 | version: "0.9.7+12"
600 | web_socket_channel:
601 | dependency: transitive
602 | description:
603 | name: web_socket_channel
604 | url: "https://pub.flutter-io.cn"
605 | source: hosted
606 | version: "1.0.15"
607 | xml:
608 | dependency: transitive
609 | description:
610 | name: xml
611 | url: "https://pub.flutter-io.cn"
612 | source: hosted
613 | version: "3.5.0"
614 | yaml:
615 | dependency: transitive
616 | description:
617 | name: yaml
618 | url: "https://pub.flutter-io.cn"
619 | source: hosted
620 | version: "2.2.0"
621 | sdks:
622 | dart: ">=2.4.0 <3.0.0"
623 | flutter: ">=1.6.7 <2.0.0"
624 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: douyin_demo
2 | description: A new Flutter project.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # In Android, build-name is used as versionName while build-number used as versionCode.
10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
12 | # Read more about iOS versioning at
13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
14 | version: 1.0.0+1
15 |
16 | environment:
17 | sdk: ">=2.1.0 <3.0.0"
18 |
19 | dependencies:
20 | flutter:
21 | sdk: flutter
22 |
23 | # The following adds the Cupertino Icons font to your application.
24 | # Use with the CupertinoIcons class for iOS style icons.
25 | cupertino_icons: ^0.1.2
26 | marquee:
27 | video_player:
28 | marquee_flutter:
29 | provider:
30 | lpinyin:
31 | sticky_headers:
32 | shared_preferences: ^0.5.3
33 | json_annotation:
34 | flutter_swiper:
35 | stretchy_header:
36 | after_layout:
37 | camera:
38 | path_provider:
39 | path:
40 | uuid:
41 | image_picker_saver:
42 | image_gallery_saver:
43 | firebase_ml_vision:
44 | image_picker:
45 |
46 | dev_dependencies:
47 | flutter_test:
48 | sdk: flutter
49 | build_runner:
50 | json_serializable:
51 |
52 |
53 | # For information on the generic Dart part of this file, see the
54 | # following page: https://dart.dev/tools/pub/pubspec
55 |
56 | # The following section is specific to Flutter.
57 | flutter:
58 |
59 | # The following line ensures that the Material Icons font is
60 | # included with your application, so that you can use the icons in
61 | # the material Icons class.
62 | uses-material-design: true
63 |
64 | # To add assets to your application, add an assets section, like this:
65 | assets:
66 | - lib/images/pingguo.jpeg
67 | - lib/images/sky.jpg
68 | - lib/images/temple.jpg
69 | - lib/images/zhifei.jpg
70 | - lib/images/woman.jpg
71 | - lib/images/woman2.jpg
72 | - lib/images/whitehouse.jpg
73 | - lib/images/waterdrop.jpg
74 | # - lib/images/aaa.png
75 | # - images/a_dot_ham.jpeg
76 |
77 | # An image asset can refer to one or more resolution-specific "variants", see
78 | # https://flutter.dev/assets-and-images/#resolution-aware.
79 |
80 | # For details regarding adding assets from package dependencies, see
81 | # https://flutter.dev/assets-and-images/#from-packages
82 |
83 | # To add custom fonts to your application, add a fonts section here,
84 | # in this "flutter" section. Each entry in this list should have a
85 | # "family" key with the font family name, and a "fonts" key with a
86 | # list giving the asset and other descriptors for the font. For
87 | # example:
88 | # fonts:
89 | # - family: Schyler
90 | # fonts:
91 | # - asset: fonts/Schyler-Regular.ttf
92 | # - asset: fonts/Schyler-Italic.ttf
93 | # style: italic
94 | # - family: Trajan Pro
95 | # fonts:
96 | # - asset: fonts/TrajanPro.ttf
97 | # - asset: fonts/TrajanPro_Bold.ttf
98 | # weight: 700
99 | #
100 | # For details regarding fonts from package dependencies,
101 | # see https://flutter.dev/custom-fonts/#from-packages
102 |
--------------------------------------------------------------------------------
/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:douyin_demo/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 |
--------------------------------------------------------------------------------