├── .gitignore
├── .metadata
├── README.MD
├── android
├── .project
├── .settings
│ └── org.eclipse.buildship.core.prefs
├── app
│ ├── .classpath
│ ├── .project
│ ├── .settings
│ │ └── org.eclipse.buildship.core.prefs
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── tbcontact
│ │ │ └── MainActivity.java
│ │ └── 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
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── images
├── code.png
├── contact_list_normal.png
├── contact_list_pressed.png
├── find_normal.png
├── find_pressed.png
├── icon_addfriend.png
├── icon_bottle.png
├── icon_friends.png
├── icon_game.png
├── icon_groupchat.png
├── icon_link.png
├── icon_look.png
├── icon_me_card.png
├── icon_me_collect.png
├── icon_me_money.png
├── icon_me_photo.png
├── icon_me_setting.png
├── icon_me_smile.png
├── icon_menu_addfriend.png
├── icon_menu_group.png
├── icon_menu_scan.png
├── icon_near.png
├── icon_public.png
├── icon_scan.png
├── icon_search.png
├── icon_shake.png
├── icon_shop.png
├── loading.jpg
├── login_logo.png
├── profile_normal.png
├── profile_pressed.png
├── tutu.png
├── weixin_normal.png
└── weixin_pressed.png
├── ios
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ └── contents.xcworkspacedata
└── Runner
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── main.m
├── lib
├── app.dart
├── common
│ ├── appconst.dart
│ ├── application.dart
│ ├── phoneslider.dart
│ ├── theme.dart
│ └── touch_callback.dart
├── contacts
│ ├── contact_detail.dart
│ ├── contact_header.dart
│ ├── contact_item.dart
│ ├── contact_vo.dart
│ ├── contacts.dart
│ ├── topcontact.dart
│ └── topcontact_vo.dart
├── conversations
│ ├── conversation_vo.dart
│ ├── converstation.dart
│ ├── converstation_item.dart
│ ├── message.dart
│ ├── message_item.dart
│ └── message_vo.dart
├── generated
│ └── i18n.dart
├── guide.dart
├── login
│ └── login.dart
├── main.dart
├── news
│ ├── banner.dart
│ ├── banner_vo.dart
│ └── news.dart
├── routes.dart
└── search.dart
├── pubspec.yaml
└── res
└── values
└── strings_en.arb
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.lock
4 | *.log
5 | *.pyc
6 | *.swp
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # Visual Studio Code related
20 | .vscode/
21 |
22 | # Flutter/Dart/Pub related
23 | **/doc/api/
24 | .dart_tool/
25 | .flutter-plugins
26 | .packages
27 | .pub-cache/
28 | .pub/
29 | build/
30 |
31 | # Android related
32 | **/android/**/gradle-wrapper.jar
33 | **/android/.gradle
34 | **/android/captures/
35 | **/android/gradlew
36 | **/android/gradlew.bat
37 | **/android/local.properties
38 | **/android/**/GeneratedPluginRegistrant.java
39 |
40 | # iOS/XCode related
41 | **/ios/**/*.mode1v3
42 | **/ios/**/*.mode2v3
43 | **/ios/**/*.moved-aside
44 | **/ios/**/*.pbxuser
45 | **/ios/**/*.perspectivev3
46 | **/ios/**/*sync/
47 | **/ios/**/.sconsign.dblite
48 | **/ios/**/.tags*
49 | **/ios/**/.vagrant/
50 | **/ios/**/DerivedData/
51 | **/ios/**/Icon?
52 | **/ios/**/Pods/
53 | **/ios/**/.symlinks/
54 | **/ios/**/profile
55 | **/ios/**/xcuserdata
56 | **/ios/.generated/
57 | **/ios/Flutter/App.framework
58 | **/ios/Flutter/Flutter.framework
59 | **/ios/Flutter/Generated.xcconfig
60 | **/ios/Flutter/app.flx
61 | **/ios/Flutter/app.zip
62 | **/ios/Flutter/flutter_assets/
63 | **/ios/ServiceDefinitions.json
64 | **/ios/Runner/GeneratedPluginRegistrant.*
65 |
66 | # Exceptions to above rules.
67 | !**/ios/**/default.mode1v3
68 | !**/ios/**/default.mode2v3
69 | !**/ios/**/default.pbxuser
70 | !**/ios/**/default.perspectivev3
71 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
72 |
--------------------------------------------------------------------------------
/.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: 5391447fae6209bb21a89e6a5a6583cac1af9b4b
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | ### 项目说明
2 |
3 | > 本实例使用Flutter + Jpush基本完成了一个类似微信的客户端,本来打算作为正式项目开发, 但是由于后期工作原因,没有时间进一步处理,因此后期可能有时间进行完善或者重构
4 |
5 |
--------------------------------------------------------------------------------
/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 | arguments=
2 | auto.sync=false
3 | build.scans.enabled=false
4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
5 | connection.project.dir=
6 | eclipse.preferences.version=1
7 | gradle.user.home=D\:/InstallSoft/gradle-4.9
8 | java.home=
9 | jvm.arguments=
10 | offline.mode=false
11 | override.workspace.settings=true
12 | show.console.view=true
13 | show.executions.view=true
14 |
--------------------------------------------------------------------------------
/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 from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 |
27 | android {
28 | compileSdkVersion 27
29 |
30 | lintOptions {
31 | disable 'InvalidPackage'
32 | }
33 |
34 | defaultConfig {
35 | applicationId "com.github.halower.tbcontact"
36 | minSdkVersion 16
37 | targetSdkVersion 27
38 | versionCode flutterVersionCode.toInteger()
39 | versionName flutterVersionName
40 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
41 |
42 | ndk {
43 | //选择要添加的对应cpu类型的.so库。
44 | abiFilters 'armeabi', 'armeabi-v7a', 'armeabi-v8a','x86', 'x86_64', 'mips', 'mips64'
45 | // 还可以添加 'x86', 'x86_64', 'mips', 'mips64'
46 | }
47 |
48 | manifestPlaceholders = [
49 | JPUSH_PKGNAME : applicationId,
50 | JPUSH_APPKEY : "b9924d36aca80e7b64e49c34", //JPush上注册的包名对应的appkey.
51 | JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可.
52 | ]
53 | }
54 |
55 | buildTypes {
56 | release {
57 | // TODO: Add your own signing config for the release build.
58 | // Signing with the debug keys for now, so `flutter run --release` works.
59 | signingConfig signingConfigs.debug
60 | }
61 | }
62 | }
63 |
64 | flutter {
65 | source '../..'
66 | }
67 |
68 | dependencies {
69 | testImplementation 'junit:junit:4.12'
70 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
71 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
72 | }
73 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
15 |
19 |
26 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/example/tbcontact/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.tbcontact;
2 |
3 | import android.os.Bundle;
4 | import io.flutter.app.FlutterActivity;
5 | import io.flutter.plugins.GeneratedPluginRegistrant;
6 |
7 | public class MainActivity extends FlutterActivity {
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.2.1'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
--------------------------------------------------------------------------------
/android/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 |
--------------------------------------------------------------------------------
/images/code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/code.png
--------------------------------------------------------------------------------
/images/contact_list_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/contact_list_normal.png
--------------------------------------------------------------------------------
/images/contact_list_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/contact_list_pressed.png
--------------------------------------------------------------------------------
/images/find_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/find_normal.png
--------------------------------------------------------------------------------
/images/find_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/find_pressed.png
--------------------------------------------------------------------------------
/images/icon_addfriend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_addfriend.png
--------------------------------------------------------------------------------
/images/icon_bottle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_bottle.png
--------------------------------------------------------------------------------
/images/icon_friends.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_friends.png
--------------------------------------------------------------------------------
/images/icon_game.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_game.png
--------------------------------------------------------------------------------
/images/icon_groupchat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_groupchat.png
--------------------------------------------------------------------------------
/images/icon_link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_link.png
--------------------------------------------------------------------------------
/images/icon_look.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_look.png
--------------------------------------------------------------------------------
/images/icon_me_card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_me_card.png
--------------------------------------------------------------------------------
/images/icon_me_collect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_me_collect.png
--------------------------------------------------------------------------------
/images/icon_me_money.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_me_money.png
--------------------------------------------------------------------------------
/images/icon_me_photo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_me_photo.png
--------------------------------------------------------------------------------
/images/icon_me_setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_me_setting.png
--------------------------------------------------------------------------------
/images/icon_me_smile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_me_smile.png
--------------------------------------------------------------------------------
/images/icon_menu_addfriend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_menu_addfriend.png
--------------------------------------------------------------------------------
/images/icon_menu_group.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_menu_group.png
--------------------------------------------------------------------------------
/images/icon_menu_scan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_menu_scan.png
--------------------------------------------------------------------------------
/images/icon_near.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_near.png
--------------------------------------------------------------------------------
/images/icon_public.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_public.png
--------------------------------------------------------------------------------
/images/icon_scan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_scan.png
--------------------------------------------------------------------------------
/images/icon_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_search.png
--------------------------------------------------------------------------------
/images/icon_shake.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_shake.png
--------------------------------------------------------------------------------
/images/icon_shop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/icon_shop.png
--------------------------------------------------------------------------------
/images/loading.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/loading.jpg
--------------------------------------------------------------------------------
/images/login_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/login_logo.png
--------------------------------------------------------------------------------
/images/profile_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/profile_normal.png
--------------------------------------------------------------------------------
/images/profile_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/profile_pressed.png
--------------------------------------------------------------------------------
/images/tutu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/tutu.png
--------------------------------------------------------------------------------
/images/weixin_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/weixin_normal.png
--------------------------------------------------------------------------------
/images/weixin_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/images/weixin_pressed.png
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.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 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
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 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
17 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
18 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
19 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
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 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
44 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
45 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
47 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
48 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
49 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
50 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
51 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
52 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
53 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
54 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
55 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
56 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
57 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
58 | /* End PBXFileReference section */
59 |
60 | /* Begin PBXFrameworksBuildPhase section */
61 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
62 | isa = PBXFrameworksBuildPhase;
63 | buildActionMask = 2147483647;
64 | files = (
65 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
66 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
67 | );
68 | runOnlyForDeploymentPostprocessing = 0;
69 | };
70 | /* End PBXFrameworksBuildPhase section */
71 |
72 | /* Begin PBXGroup section */
73 | 9740EEB11CF90186004384FC /* Flutter */ = {
74 | isa = PBXGroup;
75 | children = (
76 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
77 | 3B80C3931E831B6300D905FE /* App.framework */,
78 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
79 | 9740EEBA1CF902C7004384FC /* Flutter.framework */,
80 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
81 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
82 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
83 | );
84 | name = Flutter;
85 | sourceTree = "";
86 | };
87 | 97C146E51CF9000F007C117D = {
88 | isa = PBXGroup;
89 | children = (
90 | 9740EEB11CF90186004384FC /* Flutter */,
91 | 97C146F01CF9000F007C117D /* Runner */,
92 | 97C146EF1CF9000F007C117D /* Products */,
93 | CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
94 | );
95 | sourceTree = "";
96 | };
97 | 97C146EF1CF9000F007C117D /* Products */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 97C146EE1CF9000F007C117D /* Runner.app */,
101 | );
102 | name = Products;
103 | sourceTree = "";
104 | };
105 | 97C146F01CF9000F007C117D /* Runner */ = {
106 | isa = PBXGroup;
107 | children = (
108 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
109 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
110 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
111 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
112 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
113 | 97C147021CF9000F007C117D /* Info.plist */,
114 | 97C146F11CF9000F007C117D /* Supporting Files */,
115 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
116 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
117 | );
118 | path = Runner;
119 | sourceTree = "";
120 | };
121 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
122 | isa = PBXGroup;
123 | children = (
124 | 97C146F21CF9000F007C117D /* main.m */,
125 | );
126 | name = "Supporting Files";
127 | sourceTree = "";
128 | };
129 | /* End PBXGroup section */
130 |
131 | /* Begin PBXNativeTarget section */
132 | 97C146ED1CF9000F007C117D /* Runner */ = {
133 | isa = PBXNativeTarget;
134 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
135 | buildPhases = (
136 | 9740EEB61CF901F6004384FC /* Run Script */,
137 | 97C146EA1CF9000F007C117D /* Sources */,
138 | 97C146EB1CF9000F007C117D /* Frameworks */,
139 | 97C146EC1CF9000F007C117D /* Resources */,
140 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
141 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
142 | );
143 | buildRules = (
144 | );
145 | dependencies = (
146 | );
147 | name = Runner;
148 | productName = Runner;
149 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
150 | productType = "com.apple.product-type.application";
151 | };
152 | /* End PBXNativeTarget section */
153 |
154 | /* Begin PBXProject section */
155 | 97C146E61CF9000F007C117D /* Project object */ = {
156 | isa = PBXProject;
157 | attributes = {
158 | LastUpgradeCheck = 0910;
159 | ORGANIZATIONNAME = "The Chromium Authors";
160 | TargetAttributes = {
161 | 97C146ED1CF9000F007C117D = {
162 | CreatedOnToolsVersion = 7.3.1;
163 | };
164 | };
165 | };
166 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
167 | compatibilityVersion = "Xcode 3.2";
168 | developmentRegion = English;
169 | hasScannedForEncodings = 0;
170 | knownRegions = (
171 | en,
172 | Base,
173 | );
174 | mainGroup = 97C146E51CF9000F007C117D;
175 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
176 | projectDirPath = "";
177 | projectRoot = "";
178 | targets = (
179 | 97C146ED1CF9000F007C117D /* Runner */,
180 | );
181 | };
182 | /* End PBXProject section */
183 |
184 | /* Begin PBXResourcesBuildPhase section */
185 | 97C146EC1CF9000F007C117D /* Resources */ = {
186 | isa = PBXResourcesBuildPhase;
187 | buildActionMask = 2147483647;
188 | files = (
189 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
190 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
191 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
192 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
193 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
194 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
195 | );
196 | runOnlyForDeploymentPostprocessing = 0;
197 | };
198 | /* End PBXResourcesBuildPhase section */
199 |
200 | /* Begin PBXShellScriptBuildPhase section */
201 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
202 | isa = PBXShellScriptBuildPhase;
203 | buildActionMask = 2147483647;
204 | files = (
205 | );
206 | inputPaths = (
207 | );
208 | name = "Thin Binary";
209 | outputPaths = (
210 | );
211 | runOnlyForDeploymentPostprocessing = 0;
212 | shellPath = /bin/sh;
213 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
214 | };
215 | 9740EEB61CF901F6004384FC /* Run Script */ = {
216 | isa = PBXShellScriptBuildPhase;
217 | buildActionMask = 2147483647;
218 | files = (
219 | );
220 | inputPaths = (
221 | );
222 | name = "Run Script";
223 | outputPaths = (
224 | );
225 | runOnlyForDeploymentPostprocessing = 0;
226 | shellPath = /bin/sh;
227 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
228 | };
229 | /* End PBXShellScriptBuildPhase section */
230 |
231 | /* Begin PBXSourcesBuildPhase section */
232 | 97C146EA1CF9000F007C117D /* Sources */ = {
233 | isa = PBXSourcesBuildPhase;
234 | buildActionMask = 2147483647;
235 | files = (
236 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
237 | 97C146F31CF9000F007C117D /* main.m in Sources */,
238 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
239 | );
240 | runOnlyForDeploymentPostprocessing = 0;
241 | };
242 | /* End PBXSourcesBuildPhase section */
243 |
244 | /* Begin PBXVariantGroup section */
245 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
246 | isa = PBXVariantGroup;
247 | children = (
248 | 97C146FB1CF9000F007C117D /* Base */,
249 | );
250 | name = Main.storyboard;
251 | sourceTree = "";
252 | };
253 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
254 | isa = PBXVariantGroup;
255 | children = (
256 | 97C147001CF9000F007C117D /* Base */,
257 | );
258 | name = LaunchScreen.storyboard;
259 | sourceTree = "";
260 | };
261 | /* End PBXVariantGroup section */
262 |
263 | /* Begin XCBuildConfiguration section */
264 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
265 | isa = XCBuildConfiguration;
266 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
267 | buildSettings = {
268 | ALWAYS_SEARCH_USER_PATHS = NO;
269 | CLANG_ANALYZER_NONNULL = YES;
270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
271 | CLANG_CXX_LIBRARY = "libc++";
272 | CLANG_ENABLE_MODULES = YES;
273 | CLANG_ENABLE_OBJC_ARC = YES;
274 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
275 | CLANG_WARN_BOOL_CONVERSION = YES;
276 | CLANG_WARN_COMMA = YES;
277 | CLANG_WARN_CONSTANT_CONVERSION = YES;
278 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
279 | CLANG_WARN_EMPTY_BODY = YES;
280 | CLANG_WARN_ENUM_CONVERSION = YES;
281 | CLANG_WARN_INFINITE_RECURSION = YES;
282 | CLANG_WARN_INT_CONVERSION = YES;
283 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
284 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
286 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
287 | CLANG_WARN_STRICT_PROTOTYPES = YES;
288 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
289 | CLANG_WARN_UNREACHABLE_CODE = YES;
290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
291 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
292 | COPY_PHASE_STRIP = NO;
293 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
294 | ENABLE_NS_ASSERTIONS = NO;
295 | ENABLE_STRICT_OBJC_MSGSEND = YES;
296 | GCC_C_LANGUAGE_STANDARD = gnu99;
297 | GCC_NO_COMMON_BLOCKS = YES;
298 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
299 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
300 | GCC_WARN_UNDECLARED_SELECTOR = YES;
301 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
302 | GCC_WARN_UNUSED_FUNCTION = YES;
303 | GCC_WARN_UNUSED_VARIABLE = YES;
304 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
305 | MTL_ENABLE_DEBUG_INFO = NO;
306 | SDKROOT = iphoneos;
307 | TARGETED_DEVICE_FAMILY = "1,2";
308 | VALIDATE_PRODUCT = YES;
309 | };
310 | name = Profile;
311 | };
312 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
313 | isa = XCBuildConfiguration;
314 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
315 | buildSettings = {
316 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
317 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
318 | DEVELOPMENT_TEAM = S8QB4VV633;
319 | ENABLE_BITCODE = NO;
320 | FRAMEWORK_SEARCH_PATHS = (
321 | "$(inherited)",
322 | "$(PROJECT_DIR)/Flutter",
323 | );
324 | INFOPLIST_FILE = Runner/Info.plist;
325 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
326 | LIBRARY_SEARCH_PATHS = (
327 | "$(inherited)",
328 | "$(PROJECT_DIR)/Flutter",
329 | );
330 | PRODUCT_BUNDLE_IDENTIFIER = com.example.tbcontact;
331 | PRODUCT_NAME = "$(TARGET_NAME)";
332 | VERSIONING_SYSTEM = "apple-generic";
333 | };
334 | name = Profile;
335 | };
336 | 97C147031CF9000F007C117D /* Debug */ = {
337 | isa = XCBuildConfiguration;
338 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
339 | buildSettings = {
340 | ALWAYS_SEARCH_USER_PATHS = NO;
341 | CLANG_ANALYZER_NONNULL = YES;
342 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
343 | CLANG_CXX_LIBRARY = "libc++";
344 | CLANG_ENABLE_MODULES = YES;
345 | CLANG_ENABLE_OBJC_ARC = YES;
346 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
347 | CLANG_WARN_BOOL_CONVERSION = YES;
348 | CLANG_WARN_COMMA = YES;
349 | CLANG_WARN_CONSTANT_CONVERSION = YES;
350 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
351 | CLANG_WARN_EMPTY_BODY = YES;
352 | CLANG_WARN_ENUM_CONVERSION = YES;
353 | CLANG_WARN_INFINITE_RECURSION = YES;
354 | CLANG_WARN_INT_CONVERSION = YES;
355 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
356 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
357 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
358 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
359 | CLANG_WARN_STRICT_PROTOTYPES = YES;
360 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
361 | CLANG_WARN_UNREACHABLE_CODE = YES;
362 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
363 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
364 | COPY_PHASE_STRIP = NO;
365 | DEBUG_INFORMATION_FORMAT = dwarf;
366 | ENABLE_STRICT_OBJC_MSGSEND = YES;
367 | ENABLE_TESTABILITY = YES;
368 | GCC_C_LANGUAGE_STANDARD = gnu99;
369 | GCC_DYNAMIC_NO_PIC = NO;
370 | GCC_NO_COMMON_BLOCKS = YES;
371 | GCC_OPTIMIZATION_LEVEL = 0;
372 | GCC_PREPROCESSOR_DEFINITIONS = (
373 | "DEBUG=1",
374 | "$(inherited)",
375 | );
376 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
377 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
378 | GCC_WARN_UNDECLARED_SELECTOR = YES;
379 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
380 | GCC_WARN_UNUSED_FUNCTION = YES;
381 | GCC_WARN_UNUSED_VARIABLE = YES;
382 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
383 | MTL_ENABLE_DEBUG_INFO = YES;
384 | ONLY_ACTIVE_ARCH = YES;
385 | SDKROOT = iphoneos;
386 | TARGETED_DEVICE_FAMILY = "1,2";
387 | };
388 | name = Debug;
389 | };
390 | 97C147041CF9000F007C117D /* Release */ = {
391 | isa = XCBuildConfiguration;
392 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
393 | buildSettings = {
394 | ALWAYS_SEARCH_USER_PATHS = NO;
395 | CLANG_ANALYZER_NONNULL = YES;
396 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
397 | CLANG_CXX_LIBRARY = "libc++";
398 | CLANG_ENABLE_MODULES = YES;
399 | CLANG_ENABLE_OBJC_ARC = YES;
400 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
401 | CLANG_WARN_BOOL_CONVERSION = YES;
402 | CLANG_WARN_COMMA = YES;
403 | CLANG_WARN_CONSTANT_CONVERSION = YES;
404 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
405 | CLANG_WARN_EMPTY_BODY = YES;
406 | CLANG_WARN_ENUM_CONVERSION = YES;
407 | CLANG_WARN_INFINITE_RECURSION = YES;
408 | CLANG_WARN_INT_CONVERSION = YES;
409 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
410 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
411 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
412 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
413 | CLANG_WARN_STRICT_PROTOTYPES = YES;
414 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
415 | CLANG_WARN_UNREACHABLE_CODE = YES;
416 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
417 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
418 | COPY_PHASE_STRIP = NO;
419 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
420 | ENABLE_NS_ASSERTIONS = NO;
421 | ENABLE_STRICT_OBJC_MSGSEND = YES;
422 | GCC_C_LANGUAGE_STANDARD = gnu99;
423 | GCC_NO_COMMON_BLOCKS = YES;
424 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
425 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
426 | GCC_WARN_UNDECLARED_SELECTOR = YES;
427 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
428 | GCC_WARN_UNUSED_FUNCTION = YES;
429 | GCC_WARN_UNUSED_VARIABLE = YES;
430 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
431 | MTL_ENABLE_DEBUG_INFO = NO;
432 | SDKROOT = iphoneos;
433 | TARGETED_DEVICE_FAMILY = "1,2";
434 | VALIDATE_PRODUCT = YES;
435 | };
436 | name = Release;
437 | };
438 | 97C147061CF9000F007C117D /* Debug */ = {
439 | isa = XCBuildConfiguration;
440 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
441 | buildSettings = {
442 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
443 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
444 | ENABLE_BITCODE = NO;
445 | FRAMEWORK_SEARCH_PATHS = (
446 | "$(inherited)",
447 | "$(PROJECT_DIR)/Flutter",
448 | );
449 | INFOPLIST_FILE = Runner/Info.plist;
450 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
451 | LIBRARY_SEARCH_PATHS = (
452 | "$(inherited)",
453 | "$(PROJECT_DIR)/Flutter",
454 | );
455 | PRODUCT_BUNDLE_IDENTIFIER = com.example.tbcontact;
456 | PRODUCT_NAME = "$(TARGET_NAME)";
457 | VERSIONING_SYSTEM = "apple-generic";
458 | };
459 | name = Debug;
460 | };
461 | 97C147071CF9000F007C117D /* Release */ = {
462 | isa = XCBuildConfiguration;
463 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
464 | buildSettings = {
465 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
466 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
467 | ENABLE_BITCODE = NO;
468 | FRAMEWORK_SEARCH_PATHS = (
469 | "$(inherited)",
470 | "$(PROJECT_DIR)/Flutter",
471 | );
472 | INFOPLIST_FILE = Runner/Info.plist;
473 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
474 | LIBRARY_SEARCH_PATHS = (
475 | "$(inherited)",
476 | "$(PROJECT_DIR)/Flutter",
477 | );
478 | PRODUCT_BUNDLE_IDENTIFIER = com.example.tbcontact;
479 | PRODUCT_NAME = "$(TARGET_NAME)";
480 | VERSIONING_SYSTEM = "apple-generic";
481 | };
482 | name = Release;
483 | };
484 | /* End XCBuildConfiguration section */
485 |
486 | /* Begin XCConfigurationList section */
487 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
488 | isa = XCConfigurationList;
489 | buildConfigurations = (
490 | 97C147031CF9000F007C117D /* Debug */,
491 | 97C147041CF9000F007C117D /* Release */,
492 | 249021D3217E4FDB00AE95B9 /* Profile */,
493 | );
494 | defaultConfigurationIsVisible = 0;
495 | defaultConfigurationName = Release;
496 | };
497 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
498 | isa = XCConfigurationList;
499 | buildConfigurations = (
500 | 97C147061CF9000F007C117D /* Debug */,
501 | 97C147071CF9000F007C117D /* Release */,
502 | 249021D4217E4FDB00AE95B9 /* Profile */,
503 | );
504 | defaultConfigurationIsVisible = 0;
505 | defaultConfigurationName = Release;
506 | };
507 | /* End XCConfigurationList section */
508 | };
509 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
510 | }
511 |
--------------------------------------------------------------------------------
/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 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
56 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
75 |
77 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/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/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halower/flutter-chart-app/8ba96ddc8776ff37590ed9e5664393710ef41583/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | tbcontact
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/lib/app.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'package:tbcontact/contacts/contacts.dart';
4 | import 'package:tbcontact/conversations/converstation.dart';
5 | import 'package:tbcontact/news/news.dart';
6 |
7 |
8 | enum ItemType { GroupChat, AddFriends, QrCode, Payments, Help}
9 |
10 |
11 | class App extends StatefulWidget {
12 | _AppState createState() => _AppState();
13 | }
14 |
15 | class _AppState extends State {
16 | var _currentIndex = 0;
17 | ConverstationPage chatPage;
18 | Contacts contacts;
19 | News news;
20 | currentPage(){
21 | switch (_currentIndex) {
22 | case 0:
23 | if(chatPage == null){
24 | chatPage = new ConverstationPage();
25 | }
26 | return chatPage;
27 | case 1:
28 | if(contacts == null){
29 | contacts = new Contacts();
30 | }
31 | return contacts;
32 | case 2:
33 | if(news == null){
34 | news = new News();
35 | }
36 | return news;
37 | // case 3:
38 | // if(me == null){
39 | // me = new Personal();
40 | // }
41 | // return me;
42 | // default;
43 | }
44 | }
45 |
46 | @override
47 | Widget build(BuildContext context) {
48 | return Scaffold(
49 | appBar: AppBar(
50 | title: Text('拉萨海关通讯录'),
51 | actions: [
52 | GestureDetector(
53 | onTap: (){
54 | Navigator.pushNamed(context, 'search');
55 | },
56 | child: Icon(
57 | Icons.search,
58 | ),
59 | ),
60 | Padding(
61 | padding: const EdgeInsets.only(left: 30.0,right: 20.0),
62 | child: GestureDetector(
63 | child: Icon(Icons.add),
64 | onTap: (){
65 | showMenu(context: context,
66 | position: RelativeRect.fromLTRB(500.0, 76.0, 10.0, 0.0),
67 | items: [
68 | _popupMenuItem('帮助与反馈',icon: Icons.email),
69 | ],
70 | );
71 | },
72 | ),
73 | ),
74 | ],
75 | ),
76 | bottomNavigationBar: new BottomNavigationBar(
77 | type: BottomNavigationBarType.fixed,
78 | currentIndex: _currentIndex,
79 | onTap: ((index) {
80 | setState(() {
81 | _currentIndex = index;
82 | });
83 | }),
84 | items: [
85 | new BottomNavigationBarItem(
86 | title: new Text(
87 | '消息',
88 | style: TextStyle(
89 | color: _currentIndex == 0
90 | ? Color(0xFF46c01b)
91 | : Color(0xff999999)),
92 | ),
93 | icon: _currentIndex == 0
94 | ? Image.asset(
95 | 'images/weixin_pressed.png',
96 | width: 32.0,
97 | height: 28.0,
98 | )
99 | : Image.asset(
100 | 'images/weixin_normal.png',
101 | width: 32.0,
102 | height: 28.0,
103 | )),
104 | new BottomNavigationBarItem(
105 | title: new Text(
106 | '通讯录',
107 | style: TextStyle(
108 | color: _currentIndex == 1
109 | ? Color(0xFF46c01b)
110 | : Color(0xff999999)),
111 | ),
112 | icon: _currentIndex == 1
113 | ? Image.asset(
114 | 'images/contact_list_pressed.png',
115 | width: 32.0,
116 | height: 28.0,
117 | )
118 | : Image.asset(
119 | 'images/contact_list_normal.png',
120 | width: 32.0,
121 | height: 28.0,
122 | )),
123 | new BottomNavigationBarItem(
124 | title: new Text(
125 | '发现',
126 | style: TextStyle(
127 | color: _currentIndex == 2
128 | ? Color(0xFF46c01b)
129 | : Color(0xff999999)),
130 | ),
131 | icon: _currentIndex == 2
132 | ? Image.asset(
133 | 'images/find_pressed.png',
134 | width: 32.0,
135 | height: 28.0,
136 | )
137 | : Image.asset(
138 | 'images/find_normal.png',
139 | width: 32.0,
140 | height: 28.0,
141 | )),
142 | new BottomNavigationBarItem(
143 | title: new Text(
144 | '我',
145 | style: TextStyle(
146 | color: _currentIndex == 3
147 | ? Color(0xFF46c01b)
148 | : Color(0xff999999)),
149 | ),
150 | icon: _currentIndex == 3
151 | ? Image.asset(
152 | 'images/profile_pressed.png',
153 | width: 32.0,
154 | height: 28.0,
155 | )
156 | : Image.asset(
157 | 'images/profile_normal.png',
158 | width: 32.0,
159 | height: 28.0,
160 | )),
161 | ],
162 | ),
163 | body: currentPage(),
164 | );
165 | }
166 |
167 | _popupMenuItem(String title, {String imagePath,IconData icon}){
168 | return PopupMenuItem(
169 | child: Row(
170 | children: [
171 | imagePath != null
172 | ? Image.asset(
173 | imagePath,
174 | width: 32.0,
175 | height: 32.0,
176 | ): SizedBox(
177 | width: 32.0,
178 | height: 32.0,
179 | child: Icon(
180 | icon,
181 | color: Colors.white,
182 | ),
183 | ),
184 | Container(
185 | padding: const EdgeInsets.only(left: 20.0),
186 | child: Text(
187 | title,
188 | style: TextStyle(color: Colors.white),
189 | ),
190 | ),
191 | ],
192 | ),
193 | );
194 | }
195 |
196 | }
--------------------------------------------------------------------------------
/lib/common/appconst.dart:
--------------------------------------------------------------------------------
1 | class AppConst {
2 | static String host = "http://192.168.52.1:1337";
3 | static String defaultAvatar = "${AppConst.host}/uploads/0f636bc4ba684346ab10976f70f8751d.png";
4 | static String converstationUrl = "${AppConst.host}/converstations";
5 | static String messageUrl = '${AppConst.host}/messages';
6 | static String contactUrl = '${AppConst.host}/contacts';
7 | static String topcontactUrl = '${AppConst.host}/topcontacts';
8 | static String bannerUrl = '${AppConst.host}/banners';
9 | }
10 |
--------------------------------------------------------------------------------
/lib/common/application.dart:
--------------------------------------------------------------------------------
1 | class Application {
2 | static String loginUserName;
3 | static String loginUserNickName;
4 | static String loginUserAvatarUrl='';
5 | static String kAppkey = '';
6 | static bool enableIM = false;
7 | static String loginUserId;
8 | }
--------------------------------------------------------------------------------
/lib/common/phoneslider.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_slidable/flutter_slidable.dart';
3 | import 'package:url_launcher/url_launcher.dart';
4 |
5 | class PhoneSlider extends StatelessWidget {
6 | final Widget child;
7 | final String number;
8 |
9 | const PhoneSlider({Key key, this.number, this.child}) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return (number == null || number.isEmpty ) ? child: Slidable(
14 | delegate: new SlidableDrawerDelegate(),
15 | actionExtentRatio: 0.25,
16 | child: child,
17 |
18 | secondaryActions: [
19 | new IconSlideAction(
20 | caption: '发送短信',
21 | color: Colors.black45,
22 | icon: Icons.email,
23 | onTap: () async {
24 | var url = 'sms:' + number;
25 | await launch(url);
26 | },
27 | ),
28 | new IconSlideAction(
29 | caption: '拨打电话',
30 | color: Colors.blue,
31 | icon: Icons.phone,
32 | onTap:() async {
33 | var url = 'tel:' + number;
34 | await launch(url);
35 | },
36 | ),
37 | ]);
38 | }
39 | }
--------------------------------------------------------------------------------
/lib/common/theme.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 | import 'package:flutter/material.dart';
3 |
4 | class LayoutColors {
5 |
6 | const LayoutColors();
7 |
8 | static const Color loginGradientStart = Colors.blueAccent;
9 | static const Color loginGradientEnd = Colors.lightBlueAccent;
10 |
11 | static const primaryGradient = const LinearGradient(
12 | colors: const [loginGradientStart, loginGradientEnd],
13 | stops: const [0.0, 1.0],
14 | begin: Alignment.topCenter,
15 | end: Alignment.bottomCenter,
16 | );
17 | }
--------------------------------------------------------------------------------
/lib/common/touch_callback.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 |
4 | class TouchCallBack extends StatefulWidget{
5 | final Widget child;
6 | final VoidCallback onPressed;
7 | final VoidCallback onDoublePressed;
8 | final bool isfeed;
9 | final Color background;
10 | TouchCallBack({Key key,
11 | @required this.child,
12 | @required this.onPressed,
13 | this.onDoublePressed,
14 | this.isfeed:true,
15 | this.background:const Color(0xffd8d8d8),
16 | }):super(key:key);
17 | _TouchCallBackState createState() => _TouchCallBackState();
18 | }
19 |
20 | class _TouchCallBackState extends State {
21 | Color color = Colors.transparent;
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | return GestureDetector(
26 | child: Container(
27 | color: color,
28 | child: widget.child,
29 | ),
30 | onTap: widget.onPressed,
31 | onDoubleTap: widget.onDoublePressed,
32 | onPanDown: (d) {
33 | if(widget.isfeed == false) return;
34 | setState(() {
35 | color = widget.background;
36 | });
37 | },
38 | onTapUp: (d) {
39 | setState(() {
40 | color = Colors.transparent;
41 | });
42 | },
43 | onPanCancel: () {
44 | setState(() {
45 | color = Colors.transparent;
46 | });
47 | },
48 | );
49 | }
50 | }
--------------------------------------------------------------------------------
/lib/contacts/contact_detail.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:tbcontact/common/appconst.dart';
4 | import 'package:tbcontact/common/application.dart';
5 | import 'package:tbcontact/common/phoneslider.dart';
6 | import 'package:tbcontact/common/touch_callback.dart';
7 | import 'package:tbcontact/contacts/contact_vo.dart';
8 | import 'package:flushbar/flushbar.dart';
9 | import 'package:tbcontact/contacts/topcontact_vo.dart';
10 |
11 | class ContactDetail extends StatefulWidget {
12 | final ContactVO contactVo;
13 | final bool fromTopContact;
14 | const ContactDetail({
15 | Key key,
16 | this.fromTopContact,
17 | this.contactVo,
18 | }) : super(key: key);
19 | _ContactDetailState createState() => _ContactDetailState();
20 | }
21 |
22 | class _ContactDetailState extends State {
23 | bool isaTopContact = false;
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | return Scaffold(
28 | appBar: AppBar(
29 | leading: TouchCallBack(
30 | isfeed: false,
31 | onPressed: () {
32 | Navigator.pop(context);
33 | },
34 | child: Container(
35 | height: 45.0,
36 | margin: const EdgeInsets.only(left: 12.0, right: 10.0),
37 | child: Icon(
38 | Icons.chevron_left,
39 | color: Colors.grey[500],
40 | ),
41 | ),
42 | ),
43 | elevation:
44 | Theme.of(context).platform == TargetPlatform.iOS ? 0.0 : 4.0,
45 | title: Text(widget.contactVo.userName + '信息'),
46 | ),
47 | body: ListView(
48 | children: [
49 | Container(
50 | height: 80.0,
51 | decoration: BoxDecoration(
52 | color: Colors.white,
53 | border: Border(
54 | bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9))),
55 | ),
56 | child: Row(
57 | children: [
58 | Expanded(
59 | child: Container(
60 | padding: EdgeInsets.only(left: 10.0),
61 | child: Text(
62 | '头像',
63 | style: TextStyle(fontSize: 18.0),
64 | ),
65 | ),
66 | ),
67 | Container(
68 | padding: EdgeInsets.only(right: 10.0),
69 | child: Image.network(
70 | widget.contactVo.avatarUrl.isEmpty
71 | ? AppConst.defaultAvatar
72 | : widget.contactVo.avatarUrl,
73 | width: 50.0,
74 | height: 50.0,
75 | scale: 0.9,
76 | ),
77 | )
78 | ],
79 | ),
80 | ),
81 | Container(
82 | height: 60.0,
83 | decoration: BoxDecoration(
84 | color: Colors.white,
85 | border: Border(
86 | bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9))),
87 | ),
88 | child: Row(
89 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
90 | children: [
91 | Container(
92 | padding: EdgeInsets.only(left: 10.0),
93 | child: Text(
94 | '姓名',
95 | style: TextStyle(fontSize: 18.0),
96 | ),
97 | ),
98 | Container(
99 | padding: EdgeInsets.only(right: 10.0),
100 | child: Text(
101 | widget.contactVo.userName,
102 | style: TextStyle(fontSize: 18.0),
103 | ),
104 | )
105 | ],
106 | ),
107 | ),
108 | Container(
109 | height: 60.0,
110 | decoration: BoxDecoration(
111 | color: Colors.white,
112 | border: Border(
113 | bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9))),
114 | ),
115 | child: Row(
116 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
117 | children: [
118 | Container(
119 | padding: EdgeInsets.only(left: 10.0),
120 | child: Text(
121 | '部门',
122 | style: TextStyle(fontSize: 18.0),
123 | ),
124 | ),
125 | Container(
126 | padding: EdgeInsets.only(right: 10.0),
127 | child: Text(
128 | widget.contactVo.department,
129 | style: TextStyle(fontSize: 18.0),
130 | ),
131 | )
132 | ],
133 | ),
134 | ),
135 | Container(
136 | height: 60.0,
137 | decoration: BoxDecoration(
138 | color: Colors.white,
139 | border: Border(
140 | bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9))),
141 | ),
142 | child: Row(
143 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
144 | children: [
145 | Container(
146 | padding: EdgeInsets.only(left: 10.0),
147 | child: Text(
148 | '科室',
149 | style: TextStyle(fontSize: 18.0),
150 | ),
151 | ),
152 | Container(
153 | padding: EdgeInsets.only(right: 10.0),
154 | child: Text(
155 | widget.contactVo.subDepartment,
156 | style: TextStyle(fontSize: 18.0),
157 | ),
158 | )
159 | ],
160 | ),
161 | ),
162 | Container(
163 | height: 60.0,
164 | decoration: BoxDecoration(
165 | color: Colors.white,
166 | border: Border(
167 | bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9))),
168 | ),
169 | child: Row(
170 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
171 | children: [
172 | Container(
173 | padding: EdgeInsets.only(left: 10.0),
174 | child: Text(
175 | '职务',
176 | style: TextStyle(fontSize: 18.0),
177 | ),
178 | ),
179 | Container(
180 | padding: EdgeInsets.only(right: 10.0),
181 | child: Text(
182 | widget.contactVo.position,
183 | style: TextStyle(fontSize: 18.0),
184 | ),
185 | )
186 | ],
187 | ),
188 | ),
189 | PhoneSlider(
190 | number: widget.contactVo.officePhone,
191 | child: Container(
192 | height: 60.0,
193 | decoration: BoxDecoration(
194 | color: Colors.white,
195 | border: Border(
196 | bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9))),
197 | ),
198 | child: Row(
199 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
200 | children: [
201 | Container(
202 | padding: EdgeInsets.only(left: 10.0),
203 | child: Text(
204 | '办公电话',
205 | style: TextStyle(fontSize: 18.0),
206 | ),
207 | ),
208 | Container(
209 | padding: EdgeInsets.only(right: 10.0),
210 | child: Text(
211 | widget.contactVo.officePhone,
212 | style: TextStyle(fontSize: 18.0),
213 | ),
214 | )
215 | ],
216 | ),
217 | ),
218 | ),
219 | PhoneSlider(
220 | number: widget.contactVo.shortPhone,
221 | child: Container(
222 | height: 60.0,
223 | decoration: BoxDecoration(
224 | color: Colors.white,
225 | border: Border(
226 | bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9))),
227 | ),
228 | child: Row(
229 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
230 | children: [
231 | Container(
232 | padding: EdgeInsets.only(left: 10.0),
233 | child: Text(
234 | '短号码',
235 | style: TextStyle(fontSize: 18.0),
236 | ),
237 | ),
238 | Container(
239 | padding: EdgeInsets.only(right: 10.0),
240 | child: Text(
241 | widget.contactVo.shortPhone ?? '--',
242 | style: TextStyle(fontSize: 18.0),
243 | ),
244 | )
245 | ],
246 | ),
247 | ),
248 | ),
249 | PhoneSlider(
250 | number: widget.contactVo.homePhone,
251 | child: Container(
252 | height: 60.0,
253 | decoration: BoxDecoration(
254 | color: Colors.white,
255 | border: Border(
256 | bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9))),
257 | ),
258 | child: Row(
259 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
260 | children: [
261 | Container(
262 | padding: EdgeInsets.only(left: 10.0),
263 | child: Text(
264 | '住宅电话',
265 | style: TextStyle(fontSize: 18.0),
266 | ),
267 | ),
268 | Container(
269 | padding: EdgeInsets.only(right: 10.0),
270 | child: Text(
271 | widget.contactVo.homePhone,
272 | style: TextStyle(fontSize: 18.0),
273 | ),
274 | )
275 | ],
276 | ),
277 | ),
278 | ),
279 | Container(
280 | height: 60.0,
281 | decoration: BoxDecoration(
282 | color: Colors.white,
283 | border: Border(
284 | bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9))),
285 | ),
286 | child: Row(
287 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
288 | children: [
289 | Container(
290 | padding: EdgeInsets.only(left: 10.0),
291 | child: Text(
292 | '房间号',
293 | style: TextStyle(fontSize: 18.0),
294 | ),
295 | ),
296 | Container(
297 | padding: EdgeInsets.only(right: 10.0),
298 | child: Text(
299 | widget.contactVo.roomNumber,
300 | style: TextStyle(fontSize: 18.0),
301 | ),
302 | ),
303 | ],
304 | ),
305 | ),
306 | Container(
307 | height: 60.0,
308 | decoration: BoxDecoration(
309 | color: Colors.white,
310 | border: Border(
311 | bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9))),
312 | ),
313 | child: Row(
314 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
315 | children: [
316 | Container(
317 | padding: EdgeInsets.only(left: 10.0),
318 | child: Text(
319 | '居住地',
320 | style: TextStyle(fontSize: 18.0),
321 | ),
322 | ),
323 | Container(
324 | padding: EdgeInsets.only(right: 10.0),
325 | child: Text(
326 | widget.contactVo.address,
327 | style: TextStyle(fontSize: 18.0),
328 | ),
329 | ),
330 | ],
331 | ),
332 | )
333 | ],
334 | ),
335 | floatingActionButton: (!widget.fromTopContact)
336 | ? new FloatingActionButton(
337 | backgroundColor: Theme.of(context).primaryColor,
338 | foregroundColor: isaTopContact ? Colors.redAccent : null,
339 | onPressed: () async {
340 | if (isaTopContact) {
341 | Flushbar(
342 | flushbarPosition: FlushbarPosition.TOP,
343 | shadowColor: Colors.blue[800],
344 | duration: Duration(seconds: 3),
345 | isDismissible: false,
346 | icon: Icon(
347 | Icons.warning,
348 | color: Colors.yellowAccent,
349 | ),
350 | titleText: new Text(
351 | "操作提醒",
352 | style: TextStyle(
353 | fontWeight: FontWeight.bold,
354 | fontSize: 20.0,
355 | color: Colors.yellow[600],
356 | ),
357 | ),
358 | mainButton: FlatButton(
359 | onPressed: () async {
360 | var dio = new Dio();
361 | var res = await dio.get(
362 | "${AppConst.topcontactUrl}?UserId=${Application.loginUserId}&TopContactId=${widget.contactVo.id}");
363 | if (res.data.length > 0) {
364 | var tc = TopContactVO.fromJson(res.data[0]);
365 | await dio
366 | .delete("${AppConst.topcontactUrl}/${tc.id}");
367 | setState(() {
368 | isaTopContact = false;
369 | });
370 | }
371 | },
372 | child: Text(
373 | "确定",
374 | style: TextStyle(color: Colors.white),
375 | ),
376 | ),
377 | messageText: new Text(
378 | "你确定从常用联系人列表中移除此联系人?",
379 | style: TextStyle(
380 | fontSize: 18.0,
381 | color: Colors.white,
382 | fontFamily: "ShadowsIntoLightTwo"),
383 | ),
384 | )..show(context);
385 | } else {
386 | var dio = new Dio();
387 | await dio.post("${AppConst.topcontactUrl}", data: {
388 | "UserId": Application.loginUserId,
389 | "TopContactId": widget.contactVo.id
390 | });
391 | Flushbar(
392 | backgroundGradient: new LinearGradient(
393 | colors: [Colors.blueGrey, Colors.black]),
394 | isDismissible: false,
395 | duration: Duration(seconds: 2),
396 | icon: Icon(
397 | Icons.check,
398 | color: Colors.greenAccent,
399 | ),
400 | )
401 | ..title = "添加成功"
402 | ..message = "该联系人已经成功添加到常用联系人列表"
403 | ..backgroundColor = Colors.red
404 | ..shadowColor = Colors.blue[800]
405 | ..show(context);
406 |
407 | setState(() {
408 | isaTopContact = true;
409 | });
410 | }
411 | },
412 | tooltip: '收藏',
413 | child: new Icon(
414 | Icons.favorite,
415 | ),
416 | )
417 | : null);
418 | }
419 |
420 | checkTopContact() async {
421 | var dio = new Dio();
422 | var userRes = await dio.get(
423 | "${AppConst.topcontactUrl}?UserId=${Application.loginUserId}&TopContactId=${widget.contactVo.id}");
424 | setState(() {
425 | isaTopContact = userRes.data.length > 0;
426 | });
427 | }
428 |
429 | @override
430 | void initState() {
431 | super.initState();
432 | checkTopContact();
433 | }
434 | }
435 |
--------------------------------------------------------------------------------
/lib/contacts/contact_header.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import './contact_item.dart';
3 |
4 | class ContactHeader extends StatelessWidget {
5 | @override
6 | Widget build(BuildContext context) {
7 | return Column(children: [
8 | ContactItem(isHeader: true, titleName:'关内通知',imageName:'images/icon_public.png'),
9 | ContactItem(isHeader: true, titleName:'常用联系人',imageName:'images/icon_groupchat.png'),
10 | ],);
11 | }
12 | }
--------------------------------------------------------------------------------
/lib/contacts/contact_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:tbcontact/contacts/contact_detail.dart';
3 | import 'package:tbcontact/contacts/contact_vo.dart';
4 | import 'package:tbcontact/conversations/message.dart';
5 | import '../common/touch_callback.dart';
6 | class ContactItem extends StatelessWidget {
7 | final ContactVO item;
8 | final String titleName;
9 | final String imageName;
10 | final bool isHeader;
11 | final bool fromTopContact;
12 | ContactItem({this.item, this.isHeader = false, this.titleName, this.imageName, this.fromTopContact= false});
13 | @override
14 | Widget build(BuildContext context) {
15 | return Container(
16 | decoration: BoxDecoration(
17 | color: Colors.white,
18 | border: Border(bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9))),
19 | ),
20 | height: 64.0,
21 | child: TouchCallBack(
22 | onPressed: () {
23 | if (isHeader)
24 | Navigator.pushNamed(context, 'topcontact');
25 | else
26 | Navigator.of(context).push(new MaterialPageRoute(builder: (_) {return new ContactDetail(contactVo: item, fromTopContact: fromTopContact);}));
27 | },
28 | onDoublePressed: () async {
29 | if (isHeader) return;
30 | Navigator.of(context).push(new MaterialPageRoute(builder: (_)
31 | {return new Message(username: item.mobilePhone, nickName: item.userName, avatarUrl: item.avatarUrl);}));
32 | },
33 | child: Row(
34 | crossAxisAlignment: CrossAxisAlignment.center,
35 | children: [
36 | Container(
37 | margin: const EdgeInsets.only(left: 13.0, right: 13.0),
38 | child: isHeader?Image.asset(imageName,width: 48.0, height: 48.0,scale: 0.9,)
39 | :Image.network(item.avatarUrl,width: 48.0, height: 48.0,scale: 0.9,),
40 | ),
41 | isHeader?
42 | Container(
43 | margin: const EdgeInsets.only(left: 12.0),
44 | child: Text(
45 | titleName == null ? item.userName ?? '--':titleName,
46 | style: TextStyle(fontSize: 18.0,color: Color(0xFF353535)),
47 | maxLines: 1,
48 | )
49 | ,):
50 | Expanded(
51 | child: Column(
52 | mainAxisAlignment: MainAxisAlignment.center,
53 | crossAxisAlignment: CrossAxisAlignment.start,
54 | children: [
55 | Text(
56 | item.userName,
57 | style: TextStyle(fontSize: 16.0,color: Color(0xFF353535)),
58 | maxLines: 1,
59 | ),
60 | Padding(
61 | padding: const EdgeInsets.only(top:8.0),
62 | ),
63 | Text(
64 | item.department + ((item.subDepartment!="" && item.subDepartment!=null)? '-' + item.subDepartment : ''),
65 | style: TextStyle(fontSize: 14.0,color: Color(0xFFa9a9a9)),
66 | maxLines: 1,
67 | overflow: TextOverflow.ellipsis,
68 | ),
69 | ],
70 | ),
71 | ),
72 | ],
73 | ),
74 | ),
75 | );
76 | }
77 | }
--------------------------------------------------------------------------------
/lib/contacts/contact_vo.dart:
--------------------------------------------------------------------------------
1 | import 'package:azlistview/azlistview.dart';
2 | import 'package:json_annotation/json_annotation.dart';
3 |
4 | @JsonSerializable(nullable: false)
5 | class ContactVO extends ISuspensionBean{
6 | String id;
7 | String userName ;
8 | String department ;
9 | String position ;
10 | String officePhone ;
11 | String mobilePhone ;
12 | String roomNumber ;
13 | String shortPhone ;
14 | String homePhone ;
15 | String address ;
16 | String password ;
17 | String subDepartment ;
18 | String avatarUrl ;
19 | String namePinyin;
20 | String tagIndex;
21 |
22 | ContactVO({this.id,this.userName, this.department, this.position, this.officePhone, this.mobilePhone,
23 | this.roomNumber, this.shortPhone, this.homePhone,
24 | this.address, this.password, this.subDepartment, this.avatarUrl, this.namePinyin, this.tagIndex});
25 |
26 | factory ContactVO.fromJson(Map json) => _$ContactVOFromJson(json);
27 | Map toJson() => _$ContactVoToJson(this);
28 | @override
29 | String getSuspensionTag() => tagIndex;
30 | }
31 |
32 | ContactVO _$ContactVOFromJson(Map json) {
33 | return ContactVO(
34 | id: json['id']as String,
35 | userName: json['UserName']as String,
36 | department: json['Department'] as String,
37 | subDepartment:json['SubDepartment']as String,
38 | position: json['Position'] as String,
39 | officePhone: json['OfficePhone'] as String,
40 | mobilePhone: json['MobilePhone'] as String,
41 | shortPhone: json['ShortPhone'] as String,
42 | homePhone:json['HomePhone']as String,
43 | roomNumber: json['RoomNumber'] as String,
44 | address:json['Address'] as String,
45 | avatarUrl: json['AvatarUrl'] as String
46 | );
47 | }
48 |
49 | Map _$ContactVoToJson(ContactVO instance) => {
50 | 'UserName': instance.userName,
51 | 'Department': instance.department,
52 | 'SubDepartment': instance.subDepartment,
53 | 'Position':instance.position,
54 | 'OfficePhone': instance.officePhone,
55 | 'MobilePhone': instance.mobilePhone,
56 | 'ShortPhone': instance.shortPhone,
57 | 'HomePhone': instance.homePhone,
58 | 'RoomNumber': instance.roomNumber,
59 | 'Address': instance.address,
60 | 'AvatarUrl': instance.avatarUrl
61 | };
62 |
--------------------------------------------------------------------------------
/lib/contacts/contacts.dart:
--------------------------------------------------------------------------------
1 | import 'package:azlistview/azlistview.dart';
2 | import 'package:dio/dio.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:lpinyin/lpinyin.dart';
5 | import 'package:tbcontact/common/appconst.dart';
6 | import 'package:tbcontact/contacts/contact_header.dart';
7 | import 'package:tbcontact/contacts/contact_item.dart';
8 | import 'package:tbcontact/contacts/contact_vo.dart';
9 |
10 | class Contacts extends StatefulWidget {
11 | _ContactsState createState() => _ContactsState();
12 | }
13 |
14 | class _ContactsState extends State {
15 | List _contacts = List();
16 | int _suspensionHeight = 40;
17 | int _itemHeight = 60;
18 |
19 | void loadData() async {
20 | var dio = new Dio();
21 | var response = await dio.get("${AppConst.contactUrl}?_limit=600");
22 | for (var item in response.data) {
23 | var co= ContactVO.fromJson(item);
24 | if(co.avatarUrl.isEmpty) {
25 | co.avatarUrl=AppConst.defaultAvatar;
26 | }
27 | _contacts.add(co);
28 | }
29 | _handleList(_contacts);
30 | setState(() {});
31 | }
32 |
33 | @override
34 | void initState() {
35 | super.initState();
36 | loadData();
37 | }
38 |
39 | void _handleList(List contactData) {
40 | if (contactData == null || contactData.isEmpty) return;
41 | for (var item in contactData) {
42 | String pinyin = PinyinHelper.getPinyinE(item.userName);
43 | String tag = pinyin.substring(0, 1).toUpperCase();
44 | item.namePinyin = pinyin;
45 | if (RegExp("[A-Z]").hasMatch(tag)) {
46 | item.tagIndex = tag;
47 | } else {
48 | item.tagIndex = "#";
49 | }
50 | }
51 | SuspensionUtil.sortListBySuspensionTag(contactData);
52 | }
53 |
54 |
55 |
56 | Widget _buildListItem(ContactVO model) {
57 | String susTag = model.getSuspensionTag();
58 | return Column(
59 | children: [
60 | Offstage(
61 | offstage: model.isShowSuspension != true,
62 | child: _buildSusWidget(susTag),
63 | ),
64 | ContactItem(item:model,titleName: model.userName, imageName: model.avatarUrl)
65 | ],
66 | );
67 | }
68 |
69 | Widget _buildSusWidget(String susTag) {
70 | return Container(
71 | padding: EdgeInsets.symmetric(horizontal: 15.0),
72 | height: _suspensionHeight.toDouble(),
73 | width: double.infinity,
74 | alignment: Alignment.centerLeft,
75 | child: Row(
76 | children: [
77 | Text(
78 | '$susTag',
79 | textScaleFactor: 1.2,
80 | ),
81 | Expanded(
82 | child: Divider(
83 | height: .0,
84 | indent: 10.0,
85 | ))
86 | ],
87 | ),
88 | );
89 | }
90 |
91 | @override
92 | Widget build(BuildContext context) {
93 | return AzListView(
94 | data: _contacts,
95 | itemBuilder: (context, model) => _buildListItem(model),
96 | isUseRealIndex: true,
97 | itemHeight: _itemHeight,
98 | suspensionHeight: _suspensionHeight,
99 | header: AzListViewHeader(
100 | height: 130,
101 | builder: (context) {
102 | return ContactHeader();
103 | }),
104 | );
105 | }
106 | }
--------------------------------------------------------------------------------
/lib/contacts/topcontact.dart:
--------------------------------------------------------------------------------
1 | import 'package:azlistview/azlistview.dart';
2 | import 'package:dio/dio.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:lpinyin/lpinyin.dart';
5 | import 'package:tbcontact/common/appconst.dart';
6 | import 'package:tbcontact/common/application.dart';
7 | import 'package:tbcontact/common/touch_callback.dart';
8 | import 'package:tbcontact/contacts/contact_item.dart';
9 | import 'package:tbcontact/contacts/contact_vo.dart';
10 | import 'package:tbcontact/contacts/topcontact_vo.dart';
11 |
12 | class TopContacts extends StatefulWidget {
13 | _TopContactsState createState() => _TopContactsState();
14 | }
15 |
16 | class _TopContactsState extends State {
17 | List _contacts = [];
18 | List _topContacts = [];
19 | int _suspensionHeight = 40;
20 | int _itemHeight = 60;
21 |
22 | void loadData() async {
23 | var dio = new Dio();
24 | List topcontactIds = [];
25 | var topcRes = await dio.get(
26 | "${AppConst.topcontactUrl}?UserId=${Application.loginUserId}&_limit=600");
27 | for (var tcJson in topcRes.data) {
28 | topcontactIds.add(TopContactVO.fromJson(tcJson).topcontactId);
29 | }
30 | if (topcontactIds.length == 0) {
31 | _handleList(_contacts);
32 | setState(() {});
33 | return;
34 | }
35 | var response = await dio.get("${AppConst.contactUrl}?_limit=600");
36 | for (var item in response.data) {
37 | var co = ContactVO.fromJson(item);
38 | if (co.avatarUrl.isEmpty) {
39 | co.avatarUrl = AppConst.defaultAvatar;
40 | }
41 | _contacts.add(co);
42 | }
43 | for (var item in _contacts) {
44 | if (topcontactIds.contains(item.id)) _topContacts.add(item);
45 | }
46 | _handleList(_topContacts);
47 | setState(() {});
48 | }
49 |
50 | @override
51 | void initState() {
52 | loadData();
53 | super.initState();
54 | }
55 |
56 | void _handleList(List contactData) {
57 | if (contactData == null || contactData.isEmpty) return;
58 | for (var item in contactData) {
59 | String pinyin = PinyinHelper.getPinyinE(item.userName);
60 | String tag = pinyin.substring(0, 1).toUpperCase();
61 | item.namePinyin = pinyin;
62 | if (RegExp("[A-Z]").hasMatch(tag)) {
63 | item.tagIndex = tag;
64 | } else {
65 | item.tagIndex = "#";
66 | }
67 | }
68 | SuspensionUtil.sortListBySuspensionTag(contactData);
69 | }
70 |
71 | Widget _buildListItem(ContactVO model) {
72 | String susTag = model.getSuspensionTag();
73 | return Column(
74 | children: [
75 | Offstage(
76 | offstage: model.isShowSuspension != true,
77 | child: _buildSusWidget(susTag),
78 | ),
79 | ContactItem(item: model, titleName: model.userName, imageName: model.avatarUrl, fromTopContact: true)
80 | ],
81 | );
82 | }
83 |
84 | Widget _buildSusWidget(String susTag) {
85 | return Container(
86 | padding: EdgeInsets.symmetric(horizontal: 15.0),
87 | height: _suspensionHeight.toDouble(),
88 | width: double.infinity,
89 | alignment: Alignment.centerLeft,
90 | child: Row(
91 | children: [
92 | Text(
93 | '$susTag',
94 | textScaleFactor: 1.2,
95 | ),
96 | Expanded(
97 | child: Divider(
98 | height: .0,
99 | indent: 10.0,
100 | ))
101 | ],
102 | ),
103 | );
104 | }
105 |
106 | @override
107 | Widget build(BuildContext context) {
108 | return Scaffold(
109 | appBar: AppBar(
110 | leading: TouchCallBack(
111 | isfeed: false,
112 | onPressed: () {
113 | Navigator.pop(context);
114 | },
115 | child: Container(
116 | height: 45.0,
117 | margin: const EdgeInsets.only(left: 12.0, right: 10.0),
118 | child: Icon(
119 | Icons.chevron_left,
120 | color: Colors.grey[500],
121 | ),
122 | ),
123 | ),
124 | elevation: Theme.of(context).platform == TargetPlatform.iOS ? 0.0 : 4.0,
125 | title: Text('常用联系人'),
126 | ),
127 | body: _topContacts.length == 0
128 | ? Center(
129 | child: Text('暂无常用联系人数据'),
130 | )
131 | : AzListView(
132 | data: _topContacts,
133 | itemBuilder: (context, model) => _buildListItem(model),
134 | isUseRealIndex: true,
135 | itemHeight: _itemHeight,
136 | suspensionHeight: _suspensionHeight),
137 | );
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/lib/contacts/topcontact_vo.dart:
--------------------------------------------------------------------------------
1 | import 'package:azlistview/azlistview.dart';
2 | import 'package:json_annotation/json_annotation.dart';
3 |
4 | @JsonSerializable(nullable: false)
5 | class TopContactVO extends ISuspensionBean{
6 | final String id;
7 | final String userId;
8 | final String topcontactId;
9 | String tagIndex;
10 |
11 | TopContactVO({this.id, this.userId, this.topcontactId, this.tagIndex});
12 |
13 | factory TopContactVO.fromJson(Map json) => _$TopContactVOFromJson(json);
14 | Map toJson() => _$TopContactVOToJson(this);
15 | @override
16 | String getSuspensionTag() => tagIndex;
17 | }
18 |
19 | TopContactVO _$TopContactVOFromJson(Map json) {
20 | return TopContactVO(
21 | id: json['id']as String,
22 | userId: json['UserId']as String,
23 | topcontactId: json['TopContactId'] as String,
24 | );
25 | }
26 |
27 | Map _$TopContactVOToJson(TopContactVO instance) => {
28 | 'UserId': instance.userId,
29 | 'TopContactId': instance.topcontactId,
30 | };
--------------------------------------------------------------------------------
/lib/conversations/conversation_vo.dart:
--------------------------------------------------------------------------------
1 | class ConverstationVO {
2 | final String id;
3 | //当前登录用户
4 | final String loginUser;
5 |
6 | //会话标识
7 | final String sessionId;
8 |
9 | final String nickName;
10 | //会话者头像
11 | String avatarUrl;
12 | //----------------以下更新-----------------
13 | //最后发送内容
14 | final String text;
15 |
16 | //最后发送时间
17 | final DateTime time;
18 |
19 | ConverstationVO(
20 | {
21 | this.id,
22 | this.loginUser,
23 | this.avatarUrl,
24 | this.sessionId,
25 | this.text,
26 | this.time, this.nickName});
27 |
28 |
29 | Map toJson() => _$ConverstationVoToJson(this);
30 | factory ConverstationVO.fromJson(Map json) => _$ConverstationVOFromJson(json);
31 | }
32 |
33 | ConverstationVO _$ConverstationVOFromJson(Map json) {
34 | return ConverstationVO(
35 | id: json['id'] as String,
36 | loginUser: json['LoginUser'] as String,
37 | nickName: json['NickName'] as String,
38 | sessionId: json['SessionId'] as String,
39 | text: json['Text'] as String,
40 | time: DateTime.parse(json['Time']),
41 | avatarUrl: json['AvatarUrl'] as String,
42 | );
43 | }
44 |
45 | Map _$ConverstationVoToJson(ConverstationVO instance) =>
46 | {
47 | 'LoginUser': instance.loginUser,
48 | 'SessionId': instance.sessionId,
49 | 'Text': instance.text,
50 | 'Time': instance.time.toIso8601String(),
51 | 'AvatarUrl': instance.avatarUrl,
52 | 'NickName': instance.nickName
53 | };
54 |
--------------------------------------------------------------------------------
/lib/conversations/converstation.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:tbcontact/common/appconst.dart';
4 | import 'package:tbcontact/common/application.dart';
5 | import 'package:tbcontact/conversations/conversation_vo.dart';
6 | import 'package:tbcontact/conversations/converstation_item.dart';
7 |
8 | class ConverstationPage extends StatefulWidget{
9 | @override
10 | ConverstationPageState createState() => new ConverstationPageState();
11 | }
12 |
13 | class ConverstationPageState extends State{
14 | final List _localConverstations = [];
15 | @override
16 | void initState() {
17 | super.initState();
18 | loadConversations();
19 | }
20 |
21 | loadConversations() async {
22 | var res = await Dio().get("${AppConst.converstationUrl}?LoginUser=${Application.loginUserName}");
23 | for(var con in res.data) {
24 | var conObj = ConverstationVO.fromJson(con);
25 | setState(() {
26 | _localConverstations.add(conObj);
27 | });
28 | }
29 | }
30 | @override
31 | Widget build(BuildContext context) {
32 | return Scaffold(
33 | body: ListView.builder(
34 | itemCount: _localConverstations.length,
35 | itemBuilder: (BuildContext context, int index){
36 | return new ConversationItem(_localConverstations[index]);
37 | }
38 | ),
39 | );
40 | }
41 | }
--------------------------------------------------------------------------------
/lib/conversations/converstation_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:common_utils/common_utils.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:tbcontact/conversations/conversation_vo.dart';
4 | import 'package:tbcontact/conversations/message.dart';
5 | import '../common/touch_callback.dart';
6 |
7 |
8 | class ConversationItem extends StatelessWidget {
9 | final ConverstationVO converstation;
10 | ConversationItem(this.converstation);
11 | @override
12 | Widget build(BuildContext context) {
13 | return Container(
14 | decoration: BoxDecoration(
15 | color: Colors.white,
16 | border: Border(bottom: BorderSide(width: 0.5,color: Color(0xFFd9d9d9))),
17 | ),
18 | height: 64.0,
19 | child: TouchCallBack(
20 | onPressed: (){
21 | Navigator.of(context).push(new MaterialPageRoute(builder: (_)
22 | {return new Message(username: converstation.sessionId, nickName: converstation.nickName, avatarUrl: converstation.avatarUrl);}));
23 | },
24 | child: Row(
25 | crossAxisAlignment: CrossAxisAlignment.center,
26 | children: [
27 | Container(
28 | margin: const EdgeInsets.only(left: 13.0, right: 13.0),
29 | child: Image.network(converstation.avatarUrl, width: 48.0, height: 48.0,),
30 | ),
31 | Expanded(
32 | child: Column(
33 | mainAxisAlignment: MainAxisAlignment.center,
34 | crossAxisAlignment: CrossAxisAlignment.start,
35 | children: [
36 | Text(
37 | converstation.nickName,
38 | style: TextStyle(fontSize: 16.0,color: Color(0xFF353535)),
39 | maxLines: 1,
40 | ),
41 | Padding(
42 | padding: const EdgeInsets.only(top:8.0),
43 | ),
44 | Text(
45 | converstation.text,
46 | style: TextStyle(fontSize: 14.0,color: Color(0xFFa9a9a9)),
47 | maxLines: 1,
48 | overflow: TextOverflow.ellipsis,
49 | ),
50 | ],
51 | ),
52 | ),
53 | Container(
54 | alignment: AlignmentDirectional.topStart,
55 | margin: const EdgeInsets.only(right: 12.0,top: 12.0),
56 | child: Text(
57 | TimelineUtil.formatByDateTime(converstation.time.add(Duration(hours: 8)), locale: 'zh', dayFormat:DayFormat.Simple),
58 | style: TextStyle(fontSize: 14.0,color: Color(0xFFa9a9a9)),
59 | ),
60 | ),
61 | ],
62 | ),
63 | )
64 | ,);
65 | }
66 | }
--------------------------------------------------------------------------------
/lib/conversations/message.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:jmessage_flutter/jmessage_flutter.dart';
4 | import 'package:tbcontact/common/application.dart';
5 | import 'package:tbcontact/common/touch_callback.dart';
6 | import 'package:tbcontact/conversations/conversation_vo.dart';
7 | import 'package:tbcontact/conversations/message_item.dart';
8 | import 'package:tbcontact/conversations/message_vo.dart';
9 | import '../common/appconst.dart';
10 | class Message extends StatefulWidget {
11 | final String nickName;
12 | final String username;
13 | final String avatarUrl;
14 | const Message({Key key, this.nickName, this.username, this.avatarUrl}) : super(key:
15 | key);
16 | _MessageState createState() => _MessageState();
17 | }
18 |
19 | class _MessageState extends State {
20 | @override
21 | void initState() {
22 | super.initState();
23 | loadCurrentSessionData();
24 | addListener();
25 | }
26 |
27 | void addListener() async {
28 | JmessageFlutter jmessage =new JmessageFlutter();
29 | jmessage.addReceiveMessageListener((msg) async {
30 | var dio = new Dio();
31 | var res = await dio.get('${AppConst.converstationUrl}?LoginUser=${Application.loginUserName}&SessionId=${widget.username}');
32 | // 查看是否已经存在会话,就创建消息
33 | if(res.data.length==0) {
34 | ConverstationVO conversation = new ConverstationVO(
35 | loginUser: Application.loginUserName,
36 | nickName: widget.nickName,
37 | sessionId: widget.username,
38 | avatarUrl: widget.avatarUrl.isEmpty? AppConst.defaultAvatar:widget.avatarUrl,
39 | text: msg.text,
40 | time: DateTime.now()
41 | );
42 | await dio.post(AppConst.converstationUrl,data: conversation.toJson());
43 | }
44 | MessageVO message = new MessageVO(
45 | loginUser: Application.loginUserName,
46 | sessionId: widget.username,
47 | sender: widget.username,
48 | avatarUrl: widget.avatarUrl.isEmpty? AppConst.defaultAvatar:widget.avatarUrl,
49 | nickName: widget.nickName,
50 | text: msg.text,
51 | time: DateTime.now()
52 | );
53 | await dio.post(AppConst.messageUrl,data: message.toJson());
54 | var messageItem = new MessageItem(conversation: message,);
55 | //更新会话
56 | var cons = ConverstationVO.fromJson(res.data[0]);
57 | await dio.put('${AppConst.converstationUrl}/${cons.id}', data: {
58 | 'Text': msg.text,
59 | 'Time': DateTime.now().toIso8601String()
60 | });
61 | setState(() {
62 | _messageItems.insert(0, messageItem);
63 | });
64 | });
65 | }
66 |
67 | final TextEditingController _chatController = new TextEditingController();
68 | final List _messageItems = [];
69 |
70 | loadCurrentSessionData() async {
71 | //网络请求
72 | Dio dio = new Dio();
73 | var res = await dio.get('${AppConst.messageUrl}?LoginUser=${Application.loginUserName}&SessionId=${widget.username}&_limit=60');
74 | for(var item in res.data) {
75 | var conversation = MessageVO.fromJson(item);
76 | if(conversation.avatarUrl.isEmpty) {
77 | conversation.avatarUrl = AppConst.defaultAvatar;
78 | }
79 | var messageItem = new MessageItem(conversation: conversation,);
80 | setState(() {
81 | _messageItems.insert(0, messageItem);
82 | });
83 | }
84 | }
85 |
86 | // 发送消息
87 | Future _handleSubmit(String text) async {
88 | _chatController.clear();
89 | final JMSingle targetType = JMSingle.fromJson({
90 | 'username': widget.username,
91 | 'nickname': widget.nickName,
92 | 'appKey': Application.kAppkey
93 | });
94 |
95 | var res = await Dio().get('${AppConst.converstationUrl}?LoginUser=${Application.loginUserName}&SessionId=${widget.username}');
96 | // 查看是否已经存在会话,就创建消息
97 | if(res.data.length == 0) {
98 | ConverstationVO conversation = new ConverstationVO(
99 | loginUser: Application.loginUserName,
100 | nickName: widget.nickName,
101 | sessionId: widget.username,
102 | avatarUrl: widget.avatarUrl.isEmpty? AppConst.defaultAvatar:widget.avatarUrl,
103 | text: text,
104 | time: DateTime.now()
105 | );
106 | await Dio().post(AppConst.converstationUrl,data: conversation.toJson());
107 | }
108 | //存储当前消息
109 | MessageVO message = new MessageVO(
110 | loginUser: Application.loginUserName,
111 | sessionId: widget.username,
112 | sender: Application.loginUserName,
113 | avatarUrl: Application.loginUserAvatarUrl.isEmpty? AppConst.defaultAvatar: Application.loginUserAvatarUrl,
114 | nickName: Application.loginUserNickName,
115 | text: text,
116 | time: DateTime.now()
117 | );
118 | await Dio().post(AppConst.messageUrl,data: message.toJson());
119 | var url ='${AppConst.converstationUrl}?LoginUser=${widget.username}&SessionId=${Application.loginUserName}';
120 | var anotherRes = await Dio().get(url);
121 | if(anotherRes.data.length==0) {
122 | //存储对方会话
123 | ConverstationVO conversation = new ConverstationVO(
124 | loginUser: widget.username,
125 | nickName: Application.loginUserNickName,
126 | sessionId: Application.loginUserName,
127 | avatarUrl: widget.avatarUrl.isEmpty? AppConst.defaultAvatar:widget.avatarUrl,
128 | text: text,
129 | time: DateTime.now()
130 | );
131 | await Dio().post(AppConst.converstationUrl,data: conversation.toJson());
132 | }
133 | //存储对方消息
134 | MessageVO anotherMessage = new MessageVO(
135 | loginUser: widget.username,
136 | sessionId: Application.loginUserName,
137 | sender: Application.loginUserName,
138 | avatarUrl: Application.loginUserAvatarUrl.isEmpty? AppConst.defaultAvatar: Application.loginUserAvatarUrl,
139 | nickName: Application.loginUserNickName,
140 | text: text,
141 | time: DateTime.now()
142 | );
143 | await Dio().post(AppConst.messageUrl,data: anotherMessage.toJson());
144 |
145 | bool canUpdate = res.data.length!=0 && anotherRes.data.length!=0;
146 | if(canUpdate) {
147 | var cons = ConverstationVO.fromJson(res.data[0]);
148 | //更新当前会话
149 | await Dio().put('${AppConst.converstationUrl}/${cons.id}', data: {
150 | 'Text': text,
151 | 'Time': DateTime.now().toIso8601String()
152 | });
153 | var anotherCons = ConverstationVO.fromJson(anotherRes.data[0]);
154 | //更新对方会话
155 | await Dio().put('${AppConst.converstationUrl}/${anotherCons.id}', data: {
156 | 'Text': text,
157 | 'Time': DateTime.now().toIso8601String()
158 | });
159 | }
160 | var messageItem = new MessageItem(conversation: message,);
161 | setState(() {
162 | _messageItems.insert(0, messageItem);
163 | });
164 | if(Application.enableIM) {
165 | JmessageFlutter jMessage = new JmessageFlutter();
166 | jMessage.sendTextMessage(type: targetType, text: text);
167 | }
168 | }
169 |
170 | Widget _chatEnvironment() {
171 | return new Container(
172 | margin: const EdgeInsets.symmetric(horizontal: 8.0),
173 | child: new Row(
174 | children: [
175 | new Flexible(
176 | child: new TextField(
177 | decoration: InputDecoration(
178 | fillColor: Colors.black26,
179 | filled: true,
180 | hintText: '请输入...',
181 | hintStyle: TextStyle(color: Colors.white)),
182 | controller: _chatController,
183 | onSubmitted: _handleSubmit,
184 | style: TextStyle(fontSize: 16.0, color: Colors.white),
185 | ),
186 | ),
187 | new Container(
188 | margin: const EdgeInsets.symmetric(horizontal: 4.0),
189 | child: new IconButton(
190 | icon: new Icon(
191 | Icons.send,
192 | color: Colors.white,
193 | ),
194 | onPressed: () => _handleSubmit(_chatController.text),
195 | ),
196 | )
197 | ],
198 | ),
199 | );
200 | }
201 |
202 | @override
203 | Widget build(BuildContext context) {
204 | return Scaffold(
205 | appBar: AppBar(
206 | leading: TouchCallBack(
207 | isfeed: false,
208 | onPressed: () {
209 | Navigator.pop(context);
210 | FocusScope.of(context).requestFocus(FocusNode());
211 | },
212 | child: Container(
213 | height: 45.0,
214 | margin: const EdgeInsets.only(left: 12.0, right: 10.0),
215 | child: Icon(
216 | Icons.chevron_left,
217 | color: Colors.grey[500],
218 | ),
219 | ),
220 | ),
221 | elevation: Theme.of(context).platform == TargetPlatform.iOS ? 0.0 : 4.0,
222 | title: Text(widget.nickName),
223 | ),
224 | body: new Column(
225 | children: [
226 | new Flexible(
227 | child: ListView.builder(
228 | padding: new EdgeInsets.all(8.0),
229 | reverse: true,
230 | itemBuilder: (_, int index) => _messageItems[index],
231 | itemCount: _messageItems.length,
232 | ),
233 | ),
234 | new Divider(
235 | height: 1.0,
236 | ),
237 | new Container(
238 | decoration: new BoxDecoration(
239 | color: Theme.of(context).cardColor,
240 | ),
241 | child: _chatEnvironment(),
242 | )
243 | ],
244 | ),
245 | );
246 | }
247 | }
248 |
--------------------------------------------------------------------------------
/lib/conversations/message_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:tbcontact/common/application.dart';
3 | import 'package:tbcontact/conversations/message_vo.dart';
4 |
5 |
6 | class MessageItem extends StatelessWidget {
7 | final MessageVO conversation;
8 |
9 | const MessageItem({Key key, this.conversation}) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return new Container(
14 | margin: const EdgeInsets.symmetric(vertical: 10.0),
15 | child: conversation.sender == Application.loginUserName ? new Row(
16 | crossAxisAlignment: CrossAxisAlignment.start,
17 | children: [
18 | new Container(
19 | margin: const EdgeInsets.only(right: 16.0),
20 | child: Image.network(conversation.avatarUrl,
21 | width: 50.0,
22 | height: 50.0,
23 | scale: 0.9,
24 | ),
25 | ),
26 | new Expanded(
27 | child: new Column(
28 | crossAxisAlignment: CrossAxisAlignment.start,
29 | children: [
30 | new Text(conversation.nickName, style: TextStyle(fontSize: 12.0,
31 | color: Colors
32 | .grey)),
33 | new Container(
34 | margin: const EdgeInsets.only(top: 5.0),
35 | child: new Text(conversation.text,
36 | style: TextStyle(fontSize: 16.0, color: Colors.black87),
37 | ),
38 | )
39 | ],
40 | ),
41 | )
42 | ],
43 | ): new Row(
44 | mainAxisAlignment: MainAxisAlignment.end,
45 | crossAxisAlignment: CrossAxisAlignment.end,
46 | children: [
47 | new Expanded(
48 | child: new Column(
49 | crossAxisAlignment: CrossAxisAlignment.end,
50 | children: [
51 | new Text(conversation.nickName, style: TextStyle(fontSize: 12.0,color: Colors.grey)),
52 | new Container(
53 | margin: const EdgeInsets.only(top: 5.0),
54 | child: new Text(conversation.text
55 | ,style: TextStyle(fontSize: 16.0, color: Colors.black87),
56 | ),
57 | )
58 | ],
59 | ),
60 | ),
61 | new Container(
62 | margin: const EdgeInsets.only(right: 16.0),
63 | child: Image.network(conversation.avatarUrl,
64 | width: 50.0,
65 | height: 50.0,
66 | scale: 0.9,
67 | ),
68 | ),
69 | ],
70 | )
71 | );
72 | }
73 | }
--------------------------------------------------------------------------------
/lib/conversations/message_vo.dart:
--------------------------------------------------------------------------------
1 | class MessageVO {
2 | //当前登录用户
3 | final String loginUser;
4 |
5 | //会话标识
6 | final String sessionId;
7 |
8 | //发送者标识
9 | final String sender;
10 |
11 | //发送者头像
12 | String avatarUrl;
13 |
14 | //发送者昵称
15 | final String nickName;
16 |
17 | //发送内容
18 | final String text;
19 |
20 | //发送时间
21 | final DateTime time;
22 |
23 | MessageVO(
24 | {this.loginUser,
25 | this.sender,
26 | this.nickName,
27 | this.avatarUrl,
28 | this.sessionId,
29 | this.text,
30 | this.time});
31 |
32 |
33 | Map toJson() => _$MessageVoToJson(this);
34 | factory MessageVO.fromJson(Map json) => _$MessageVoFromJson(json);
35 | }
36 |
37 | MessageVO _$MessageVoFromJson(Map json) {
38 | return MessageVO(
39 | loginUser: json['LoginUser'] as String,
40 | sessionId: json['SessionId'] as String,
41 | sender: json['Sender'] as String,
42 | nickName: json['NickName'] as String,
43 | text: json['Text'] as String,
44 | time: DateTime.parse(json['Time']),
45 | avatarUrl: json['AvatarUrl'] as String,
46 | );
47 | }
48 |
49 | Map _$MessageVoToJson(MessageVO instance) =>
50 | {
51 | 'LoginUser': instance.loginUser,
52 | 'SessionId': instance.sessionId,
53 | 'Sender': instance.sender,
54 | 'NickName': instance.nickName,
55 | 'Text': instance.text,
56 | 'Time': instance.time.toIso8601String(),
57 | 'AvatarUrl': instance.avatarUrl
58 | };
59 |
--------------------------------------------------------------------------------
/lib/generated/i18n.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'dart:async';
3 |
4 | import 'package:flutter/foundation.dart';
5 | import 'package:flutter/material.dart';
6 | // ignore_for_file: non_constant_identifier_names
7 | // ignore_for_file: camel_case_types
8 | // ignore_for_file: prefer_single_quotes
9 |
10 | //This file is automatically generated. DO NOT EDIT, all your changes would be lost.
11 |
12 | class S implements WidgetsLocalizations {
13 | const S();
14 |
15 | static const GeneratedLocalizationsDelegate delegate =
16 | const GeneratedLocalizationsDelegate();
17 |
18 | static S of(BuildContext context) =>
19 | Localizations.of(context, WidgetsLocalizations);
20 |
21 | @override
22 | TextDirection get textDirection => TextDirection.ltr;
23 |
24 | }
25 |
26 | class en extends S {
27 | const en();
28 | }
29 |
30 |
31 | class GeneratedLocalizationsDelegate extends LocalizationsDelegate {
32 | const GeneratedLocalizationsDelegate();
33 |
34 | List get supportedLocales {
35 | return const [
36 |
37 | const Locale("en", ""),
38 |
39 | ];
40 | }
41 |
42 | LocaleResolutionCallback resolution({Locale fallback}) {
43 | return (Locale locale, Iterable supported) {
44 | final Locale languageLocale = new Locale(locale.languageCode, "");
45 | if (supported.contains(locale))
46 | return locale;
47 | else if (supported.contains(languageLocale))
48 | return languageLocale;
49 | else {
50 | final Locale fallbackLocale = fallback ?? supported.first;
51 | return fallbackLocale;
52 | }
53 | };
54 | }
55 |
56 | @override
57 | Future load(Locale locale) {
58 | final String lang = getLang(locale);
59 | switch (lang) {
60 |
61 | case "en":
62 | return new SynchronousFuture(const en());
63 |
64 | default:
65 | return new SynchronousFuture(const S());
66 | }
67 | }
68 |
69 | @override
70 | bool isSupported(Locale locale) => supportedLocales.contains(locale);
71 |
72 | @override
73 | bool shouldReload(GeneratedLocalizationsDelegate old) => false;
74 | }
75 |
76 | String getLang(Locale l) => l.countryCode != null && l.countryCode.isEmpty
77 | ? l.languageCode
78 | : l.toString();
79 |
--------------------------------------------------------------------------------
/lib/guide.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:tbcontact/login/Login.dart';
3 |
4 | class GuidePage extends StatefulWidget {
5 | @override
6 | _GuidePageState createState() => _GuidePageState();
7 | }
8 |
9 | class _GuidePageState extends State
10 | with SingleTickerProviderStateMixin {
11 | AnimationController _controller;
12 | Animation _animation;
13 |
14 | @override
15 | void initState() {
16 | super.initState();
17 | _controller = AnimationController(
18 | vsync: this,
19 | duration: Duration(milliseconds: 3000));
20 | _animation = Tween(begin: 0.0, end: 1.0).animate(_controller);
21 |
22 | _animation.addStatusListener((status) {
23 | if (status == AnimationStatus.completed) {
24 | Navigator.of(context).pushAndRemoveUntil(
25 | MaterialPageRoute(builder: (context) => Login()),
26 | (route) => route == null);
27 | }
28 | });
29 | _controller.forward();
30 | }
31 |
32 | @override
33 | void dispose() {
34 | _controller.dispose();
35 | super.dispose();
36 | }
37 |
38 | @override
39 | Widget build(BuildContext context) {
40 | return FadeTransition(
41 | opacity: _animation,
42 | child: Image.asset(
43 | "images/loading.jpg",
44 | scale: 2.0,
45 | fit: BoxFit.cover,
46 | ),
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/login/login.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:jmessage_flutter/jmessage_flutter.dart';
3 | import 'package:tbcontact/common/appconst.dart';
4 | import 'package:tbcontact/common/application.dart';
5 | import 'package:tbcontact/contacts/contact_vo.dart';
6 |
7 | import '../common/theme.dart' as Theme;
8 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
9 | import 'package:flutter/material.dart';
10 | import 'package:flutter/services.dart';
11 |
12 | class Login extends StatefulWidget {
13 | Login({Key key}) : super(key: key);
14 |
15 | @override
16 | _LoginState createState() => new _LoginState();
17 | }
18 |
19 | class _LoginState extends State with SingleTickerProviderStateMixin {
20 |
21 | final GlobalKey _scaffoldKey = new GlobalKey();
22 |
23 | final FocusNode myFocusNodeEmailLogin = FocusNode();
24 | final FocusNode myFocusNodePasswordLogin = FocusNode();
25 |
26 | final FocusNode myFocusNodePassword = FocusNode();
27 | final FocusNode myFocusNodeEmail = FocusNode();
28 | final FocusNode myFocusNodeName = FocusNode();
29 |
30 | TextEditingController loginEmailController = new TextEditingController();
31 | TextEditingController loginPasswordController = new TextEditingController();
32 |
33 | bool _obscureTextLogin = true;
34 |
35 | TextEditingController signupEmailController = new TextEditingController();
36 | TextEditingController signupNameController = new TextEditingController();
37 | TextEditingController signupPasswordController = new TextEditingController();
38 | TextEditingController signupConfirmPasswordController = new TextEditingController();
39 |
40 | PageController _pageController;
41 |
42 | Color left = Colors.black;
43 | Color right = Colors.white;
44 |
45 | @override
46 | Widget build(BuildContext context) {
47 | return new Scaffold(
48 | resizeToAvoidBottomPadding:false,
49 | key: _scaffoldKey,
50 | body: NotificationListener(
51 | onNotification: (overscroll) {
52 | overscroll.disallowGlow();
53 | },
54 | child: SingleChildScrollView(
55 | child: Container(
56 | width: MediaQuery.of(context).size.width,
57 | height: MediaQuery.of(context).size.height >= 775.0
58 | ? MediaQuery.of(context).size.height: 775.0,
59 | decoration: new BoxDecoration(
60 | gradient: new LinearGradient(
61 | colors: [
62 | // Theme.Colors.loginGradientStart,
63 | Colors.blue,
64 | Colors.lightBlue
65 | // Theme.Colors.loginGradientEnd
66 | ],
67 | begin: const FractionalOffset(0.0, 0.0),
68 | end: const FractionalOffset(1.0, 1.0),
69 | stops: [0.0, 1.0],
70 | tileMode: TileMode.clamp),
71 | ),
72 | child: Column(
73 | mainAxisSize: MainAxisSize.max,
74 | children: [
75 | Padding(
76 | padding: EdgeInsets.only(top: 75.0),
77 | child: new Image.asset('images/login_logo.png',
78 | width: 250.0,
79 | height: 191.0,
80 | fit: BoxFit.fill
81 | ),
82 | ),
83 | Expanded(
84 | flex: 2,
85 | child: PageView(
86 | controller: _pageController,
87 | onPageChanged: (i) {
88 | if (i == 0) {
89 | setState(() {
90 | right = Colors.white;
91 | left = Colors.black;
92 | });
93 | } else if (i == 1) {
94 | setState(() {
95 | right = Colors.black;
96 | left = Colors.white;
97 | });
98 | }
99 | },
100 | children: [
101 | new ConstrainedBox(
102 | constraints: const BoxConstraints.expand(),
103 | child: _buildSignIn(context),
104 | ),
105 | ],
106 | ),
107 | ),
108 | ],
109 | ),
110 | ),
111 | ),
112 | ),
113 | );
114 | }
115 |
116 | @override
117 | void dispose() {
118 | myFocusNodePassword.dispose();
119 | myFocusNodeEmail.dispose();
120 | myFocusNodeName.dispose();
121 | _pageController?.dispose();
122 | super.dispose();
123 | }
124 |
125 | @override
126 | void initState() {
127 | super.initState();
128 | JmessageFlutter jmessage = new JmessageFlutter();
129 | jmessage..setDebugMode(enable: true);
130 | jmessage.init(appkey: Application.kAppkey, isOpenMessageRoaming: false);
131 | SystemChrome.setPreferredOrientations([
132 | DeviceOrientation.portraitUp,
133 | DeviceOrientation.portraitDown,
134 | ]);
135 |
136 | _pageController = PageController();
137 | }
138 |
139 | void showInSnackBar(String value) {
140 | FocusScope.of(context).requestFocus(new FocusNode());
141 | _scaffoldKey.currentState?.removeCurrentSnackBar();
142 | _scaffoldKey.currentState.showSnackBar(new SnackBar(
143 | content: new Text(
144 | value,
145 | textAlign: TextAlign.center,
146 | style: TextStyle(
147 | color: Colors.white,
148 | fontSize: 16.0,
149 | fontFamily: "WorkSansSemiBold"),
150 | ),
151 | backgroundColor: Colors.redAccent,
152 | duration: Duration(seconds: 3),
153 | ));
154 | }
155 |
156 | Widget _buildSignIn(BuildContext context) {
157 | return Container(
158 | padding: EdgeInsets.only(top: 23.0),
159 | child: Column(
160 | children: [
161 | Stack(
162 | alignment: Alignment.topCenter,
163 | overflow: Overflow.visible,
164 | children: [
165 | Card(
166 | elevation: 2.0,
167 | color: Colors.white,
168 | shape: RoundedRectangleBorder(
169 | borderRadius: BorderRadius.circular(8.0),
170 | ),
171 | child: Container(
172 | width: 300.0,
173 | height: 190.0,
174 | child: Column(
175 | children: [
176 | Padding(
177 | padding: EdgeInsets.only(
178 | top: 20.0, bottom: 20.0, left: 25.0, right: 25.0),
179 | child: TextField(
180 | focusNode: myFocusNodeEmailLogin,
181 | controller: loginEmailController,
182 | keyboardType: TextInputType.emailAddress,
183 | style: TextStyle(
184 | fontFamily: "WorkSansSemiBold",
185 | fontSize: 16.0,
186 | color: Colors.black),
187 | decoration: InputDecoration(
188 | border: InputBorder.none,
189 | icon: Icon(
190 | FontAwesomeIcons.envelope,
191 | color: Colors.black,
192 | size: 22.0,
193 | ),
194 | hintText: "账号/邮箱",
195 | hintStyle: TextStyle(
196 | fontFamily: "WorkSansSemiBold", fontSize: 17.0),
197 | ),
198 | ),
199 | ),
200 | Container(
201 | width: 250.0,
202 | height: 1.0,
203 | color: Colors.grey[400],
204 | ),
205 | Padding(
206 | padding: EdgeInsets.only(
207 | top: 20.0, bottom: 20.0, left: 25.0, right: 25.0),
208 | child: TextField(
209 | focusNode: myFocusNodePasswordLogin,
210 | controller: loginPasswordController,
211 | obscureText: _obscureTextLogin,
212 | style: TextStyle(
213 | fontFamily: "WorkSansSemiBold",
214 | fontSize: 16.0,
215 | color: Colors.black),
216 | decoration: InputDecoration(
217 | border: InputBorder.none,
218 | icon: Icon(
219 | FontAwesomeIcons.lock,
220 | size: 22.0,
221 | color: Colors.black,
222 | ),
223 | hintText: "密码",
224 | hintStyle: TextStyle(
225 | fontFamily: "WorkSansSemiBold", fontSize: 17.0),
226 | suffixIcon: GestureDetector(
227 | onTap: _toggleLogin,
228 | child: Icon(
229 | FontAwesomeIcons.eye,
230 | size: 15.0,
231 | color: Colors.black,
232 | ),
233 | ),
234 | ),
235 | ),
236 | ),
237 | ],
238 | ),
239 | ),
240 | ),
241 | Container(
242 | margin: EdgeInsets.only(top: 170.0),
243 | decoration: new BoxDecoration(
244 | borderRadius: BorderRadius.all(Radius.circular(5.0)),
245 | boxShadow: [
246 | BoxShadow(
247 | color: Theme.LayoutColors.loginGradientStart,
248 | offset: Offset(1.0, 6.0),
249 | blurRadius: 20.0,
250 | ),
251 | BoxShadow(
252 | color: Theme.LayoutColors.loginGradientEnd,
253 | offset: Offset(1.0, 6.0),
254 | blurRadius: 20.0,
255 | ),
256 | ],
257 | gradient: new LinearGradient(
258 | colors: [
259 | Theme.LayoutColors.loginGradientEnd,
260 | Theme.LayoutColors.loginGradientStart
261 | ],
262 | begin: const FractionalOffset(0.2, 0.2),
263 | end: const FractionalOffset(1.0, 1.0),
264 | stops: [0.0, 1.0],
265 | tileMode: TileMode.clamp),
266 | ),
267 | child: MaterialButton(
268 | highlightColor: Colors.transparent,
269 | splashColor: Theme.LayoutColors.loginGradientEnd,
270 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5.0))),
271 | child: Padding(
272 | padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 42.0),
273 | child: Text(
274 | "登录",
275 | style: TextStyle(
276 | color: Colors.white,
277 | fontSize: 25.0,
278 | fontFamily: "WorkSansBold"),
279 | ),
280 | ),
281 | onPressed: () async {
282 | if(loginEmailController.text.isEmpty || loginPasswordController.text.isEmpty) {
283 | showInSnackBar("用户名或者密码错误");
284 | return;
285 | }
286 | var dio = new Dio();
287 | var response = await dio.get("${AppConst.contactUrl}?MobilePhone=" +loginEmailController.text + "&Password=" + loginPasswordController.text);
288 | if(response.data.length!=0){
289 | var loginUser= ContactVO.fromJson(response.data[0]);
290 | Application.loginUserName =loginUser.mobilePhone;
291 | Application.loginUserNickName=loginUser.userName;
292 | Application.loginUserAvatarUrl=loginUser.avatarUrl;
293 | Application.loginUserId = loginUser.id;
294 | JmessageFlutter jmessage = new JmessageFlutter();
295 | await jmessage.login(username: loginUser.mobilePhone, password: loginPasswordController.text);
296 | Navigator.of(context).pushReplacementNamed("app");
297 | }
298 | else {
299 | showInSnackBar("用户名或者密码错误");
300 | }
301 |
302 | }),
303 | ),
304 | ],
305 | ),
306 | Padding(
307 | padding: EdgeInsets.only(top: 10.0),
308 | child: FlatButton(
309 | onPressed: () {},
310 | child: Text(
311 | "忘记密码?",
312 | style: TextStyle(
313 | decoration: TextDecoration.underline,
314 | color: Colors.white,
315 | fontSize: 16.0,
316 | fontFamily: "WorkSansMedium"),
317 | )),
318 | ),
319 | ],
320 | ),
321 | );
322 | }
323 |
324 |
325 |
326 | void _toggleLogin() {
327 | setState(() {
328 | _obscureTextLogin = !_obscureTextLogin;
329 | });
330 | }
331 | }
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:tbcontact/guide.dart';
3 | import 'package:tbcontact/routes.dart';
4 | void main() => runApp(MaterialApp(
5 | debugShowCheckedModeBanner:false,
6 | title:'tbchat',
7 | theme: mDefaultTheme,
8 | routes:routes,
9 | home: new GuidePage(),
10 | ));
11 |
12 |
13 | final ThemeData mDefaultTheme = new ThemeData(
14 | primaryColor: Color(0xff303030),
15 | scaffoldBackgroundColor: Color(0xFFebebeb),
16 | cardColor: Color(0xff393a3f),
17 | );
--------------------------------------------------------------------------------
/lib/news/banner.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:transparent_image/transparent_image.dart';
5 |
6 | const MAX_COUNT = 0x7fffffff;
7 |
8 | ///
9 | /// Item的点击事件
10 | ///
11 | typedef void OnBannerItemClick(int position, BannerItem entity);
12 |
13 | ///
14 | /// 自定义ViewPager的每个页面显示
15 | ///
16 | typedef Widget CustomBuild(int position, BannerItem entity);
17 |
18 | class BannerWidget extends StatefulWidget {
19 | final double height;
20 | final List datas;
21 | int duration;
22 | double pointRadius;
23 | Color selectedColor;
24 | Color unSelectedColor;
25 | Color textBackgroundColor;
26 | bool isHorizontal;
27 |
28 | OnBannerItemClick bannerPress;
29 | CustomBuild build;
30 |
31 | BannerWidget(double this.height, List this.datas,
32 | {Key key,
33 | int this.duration = 5000,
34 | double this.pointRadius = 3.0,
35 | Color this.selectedColor = Colors.red,
36 | Color this.unSelectedColor = Colors.white,
37 | Color this.textBackgroundColor = const Color(0x99000000),
38 | bool this.isHorizontal = true,
39 | OnBannerItemClick this.bannerPress,
40 | CustomBuild this.build})
41 | : super(key: key);
42 |
43 | @override
44 | BannerState createState() {
45 | return new BannerState();
46 | }
47 | }
48 |
49 | class BannerState extends State {
50 | Timer timer;
51 | int selectedIndex = 0;
52 | PageController controller;
53 |
54 | @override
55 | void initState() {
56 | double current = widget.datas.length > 0
57 | ? (MAX_COUNT / 2) - ((MAX_COUNT / 2) % widget.datas.length)
58 | : 0.0;
59 | controller = PageController(initialPage: current.toInt());
60 | _initPageAutoScroll();
61 | super.initState();
62 | }
63 |
64 | _initPageAutoScroll() {
65 | start();
66 | }
67 |
68 | @override
69 | void didUpdateWidget(BannerWidget oldWidget) {
70 | super.didUpdateWidget(oldWidget);
71 | print('didUpdateWidget----------------------banner');
72 | }
73 |
74 | start() {
75 | stop();
76 | timer = Timer.periodic(Duration(milliseconds: widget.duration), (timer) {
77 | if(widget.datas.length > 0 && controller != null && controller.page != null) {
78 | controller.animateToPage(controller.page.toInt() + 1,
79 | duration: Duration(milliseconds: 300), curve: Curves.linear);
80 | }
81 | });
82 | }
83 |
84 | stop() {
85 | timer?.cancel();
86 | timer = null;
87 | }
88 |
89 | @override
90 | void dispose() {
91 | stop();
92 | super.dispose();
93 | }
94 |
95 | @override
96 | Widget build(BuildContext context) {
97 | return new Container(
98 | height: widget.height,
99 | color: Colors.black12,
100 | child: Stack(
101 | children: [
102 | getViewPager(),
103 | new Align(
104 | alignment: Alignment.bottomCenter,
105 | child: IntrinsicHeight(
106 | child: Container(
107 | padding: EdgeInsets.all(6.0),
108 | color: widget.textBackgroundColor,
109 | child: getBannerTextInfoWidget(),
110 | ),
111 | ),
112 | ),
113 | ],
114 | ),
115 | );
116 | }
117 |
118 | Widget getViewPager() {
119 | return PageView.builder(
120 | itemCount: widget.datas.length > 0 ? MAX_COUNT : 0,
121 | controller: controller,
122 | onPageChanged: onPageChanged,
123 | itemBuilder: (context, index) {
124 | return InkWell(
125 | onTap: () {
126 | if (widget.bannerPress != null)
127 | widget.bannerPress(selectedIndex, widget.datas[selectedIndex]);
128 | },
129 | child: widget.build == null
130 | ? FadeInImage.memoryNetwork(
131 | placeholder: kTransparentImage,
132 | image:
133 | widget.datas[index % widget.datas.length].itemImagePath,
134 | fit: BoxFit.cover)
135 | : widget.build(
136 | index, widget.datas[index % widget.datas.length]));
137 | },
138 | );
139 | }
140 |
141 | Widget getSelectedIndexTextWidget() {
142 | return widget.datas.length > 0 && selectedIndex < widget.datas.length
143 | ? widget.datas[selectedIndex].itemText
144 | : Text('');
145 | }
146 |
147 | Widget getBannerTextInfoWidget() {
148 | if (widget.isHorizontal) {
149 | return Row(
150 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
151 | children: [
152 | new Expanded(
153 | flex: 1,
154 | child: getSelectedIndexTextWidget(),
155 | ),
156 | Expanded(
157 | flex: 0,
158 | child: Row(
159 | mainAxisSize: MainAxisSize.min,
160 | children: circle(),
161 | ),
162 | ),
163 | ],
164 | );
165 | } else {
166 | return new Column(
167 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
168 | children: [
169 | getSelectedIndexTextWidget(),
170 | IntrinsicWidth(
171 | child: Row(
172 | children: circle(),
173 | ),
174 | ),
175 | ],
176 | );
177 | }
178 | }
179 |
180 | List circle() {
181 | List circle = [];
182 | for (var i = 0; i < widget.datas.length; i++) {
183 | circle.add(Container(
184 | margin: EdgeInsets.all(2.0),
185 | width: widget.pointRadius * 2,
186 | height: widget.pointRadius * 2,
187 | decoration: new BoxDecoration(
188 | shape: BoxShape.circle,
189 | color: selectedIndex == i
190 | ? widget.selectedColor
191 | : widget.unSelectedColor,
192 | ),
193 | ));
194 | }
195 | return circle;
196 | }
197 |
198 | onPageChanged(index) {
199 | selectedIndex = index % widget.datas.length;
200 | setState(() {});
201 | }
202 | }
203 |
204 | class BannerItem {
205 | String itemImagePath;
206 | Widget itemText;
207 |
208 | static BannerItem defaultBannerItem(String image, String text) {
209 | BannerItem item = new BannerItem();
210 | item.itemImagePath = image;
211 | Text textWidget = new Text(
212 | text,
213 | softWrap: true,
214 | maxLines: 3,
215 | overflow: TextOverflow.ellipsis,
216 | style: TextStyle(
217 | color: Colors.white, fontSize: 12.0, decoration: TextDecoration.none),
218 | );
219 |
220 | item.itemText = textWidget;
221 |
222 | return item;
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/lib/news/banner_vo.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:json_annotation/json_annotation.dart';
3 |
4 | @JsonSerializable(nullable: false)
5 | class BannerVO {
6 | final String id;
7 | final String imageUrl;
8 | final String redictUrl;
9 |
10 | BannerVO({this.id, this.imageUrl, this.redictUrl});
11 |
12 |
13 | factory BannerVO.fromJson(Map json) => _$BannerVOFromJson(json);
14 | Map toJson() => _$BannerVOToJson(this);
15 | }
16 |
17 | _$BannerVOFromJson(Map json) {
18 | return BannerVO(
19 | id: json['id']as String,
20 | imageUrl: json['ImageUrl']as String,
21 | redictUrl: json['RedictUrl'] as String,
22 | );
23 | }
24 |
25 |
26 | Map _$BannerVOToJson(BannerVO instace) => {
27 | 'id': instace.id,
28 | 'ImageUrl': instace.imageUrl,
29 | 'RedictUrl': instace.redictUrl
30 | };
--------------------------------------------------------------------------------
/lib/news/news.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:tbcontact/news/banner.dart';
3 |
4 | class News extends StatefulWidget {
5 | _NewsState createState() => _NewsState();
6 | }
7 |
8 | class _NewsState extends State {
9 | List bannerList = [];
10 |
11 | @override
12 | void initState() {
13 | BannerItem item = BannerItem.defaultBannerItem(
14 | 'http://192.168.52.1:1337/uploads/58c7bc16c76f46e4acc42f67b579b874.jpg',
15 | '''近日,北大全校教师干部大会刚刚召开,63岁的林建华卸任北大校长;原北大党委书记郝平接替林建华,成为新校长。曾在北京任职多年、去年担任山西高院院长的邱水平回到北大,担任党委书记。图为2018年5月4日,北京大学举行建校120周年纪念大会,时任北京大学校长林建华(右)与时任北京大学党委书记郝平(左)''');
16 | bannerList.add(item);
17 | item = BannerItem.defaultBannerItem(
18 | 'http://192.168.52.1:1337/uploads/9f7e22e6a8d44aeda440b9d83a472001.jpg',
19 | '''邱水平、郝平、林建华均为“老北大人”,都曾离开北大,又重归北大任职。图为2018年5月4日,北京大学举行建校120周年纪念大会,时任北京大学党委书记郝平讲话''');
20 | bannerList.add(item);
21 | item = BannerItem.defaultBannerItem(
22 | 'http://192.168.52.1:1337/uploads/58c7bc16c76f46e4acc42f67b579b874.jpg',
23 | '''此番卸任的林建华,亦是北大出身,历任重庆大学、浙江大学、北京大学三所“双一流”高校校长。图为2018年5月4日,北京大学举行建校120周年纪念大会,时任北京大学校长林建华讲话。''');
24 | bannerList.add(item);
25 | item = BannerItem.defaultBannerItem(
26 | 'http://192.168.52.1:1337/uploads/9f7e22e6a8d44aeda440b9d83a472001.jpg',
27 | '''书记转任校长的郝平,为十九届中央委员会候补委员。从北大毕业后留校,后离开北大,历任北京外国语大学校长、教育部副部长。2016年12月,时隔11年,郝平再回北大,出任北大党委书记。''');
28 | bannerList.add(item);
29 | super.initState();
30 | }
31 |
32 | @override
33 | Widget build(BuildContext context) {
34 | return new Scaffold(
35 | body: Center(
36 | child: Column(
37 | children: [
38 | new BannerWidget(
39 | 180.0,
40 | bannerList,
41 | bannerPress: (pos, item) {
42 | print('第 $pos 点击了');
43 | },
44 | ),
45 | ],
46 | ),
47 | ));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/routes.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:tbcontact/app.dart';
3 | import 'package:tbcontact/contacts/contact_detail.dart';
4 | import 'package:tbcontact/contacts/topcontact.dart';
5 | import 'package:tbcontact/login/Login.dart';
6 | import 'package:tbcontact/search.dart';
7 |
8 | Map routes = {
9 | "login":(BuildContext context) => new Login(),
10 | "app":(BuildContext context) => new App(),
11 | "search":(BuildContext context) => new Search(),
12 | "topcontact":(BuildContext context) => new TopContacts(),
13 | "contactdetail":(BuildContext context) => new ContactDetail(),
14 | };
15 |
16 |
--------------------------------------------------------------------------------
/lib/search.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import './common/touch_callback.dart';
3 |
4 | class Search extends StatefulWidget{
5 | @override
6 | SearchState createState() => new SearchState();
7 | }
8 |
9 | class SearchState extends State {
10 |
11 | FocusNode focusNode = new FocusNode();
12 |
13 | _requestFocus(){
14 | FocusScope.of(context).requestFocus(focusNode);
15 | return focusNode;
16 | }
17 |
18 |
19 | _getText(String text){
20 | return TouchCallBack(
21 | isfeed: false,
22 | onPressed: (){},
23 | child: Text(
24 | text,
25 | style: TextStyle(fontSize: 14.0,color: Color(0xff1aad19)),
26 | ),
27 | );
28 | }
29 |
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 | return Scaffold(
34 | body: Container(
35 | margin: const EdgeInsets.only(top:25.0),
36 | child: Column(
37 | crossAxisAlignment: CrossAxisAlignment.center,
38 | children: [
39 | Stack(
40 | children: [
41 | TouchCallBack(
42 | isfeed: false,
43 | onPressed: (){
44 | Navigator.pop(context);
45 | },
46 | child: Container(
47 | height: 45.0,
48 | margin: const EdgeInsets.only(left: 12.0,right: 10.0),
49 | child: Icon(
50 | Icons.chevron_left,
51 | color: Colors.black,
52 | ),
53 | ),
54 | ),
55 |
56 | Container(
57 | alignment: Alignment.centerLeft,
58 | height: 45.0,
59 | margin: const EdgeInsets.only(left: 50.0,right: 10.0),
60 | decoration: BoxDecoration(
61 | border: Border(bottom: BorderSide(width: 1.0,color: Colors.green)),
62 | ),
63 | child: Row(
64 | crossAxisAlignment: CrossAxisAlignment.center,
65 | children: [
66 | Expanded(
67 | child: TextField(
68 | focusNode: _requestFocus(),
69 | style: TextStyle(
70 | color: Colors.black,
71 | fontSize: 16.0,
72 | ),
73 | onChanged: (String text){},
74 | decoration: InputDecoration(
75 | hintText:'搜索',border: InputBorder.none
76 | ),
77 | ),
78 | ),
79 | Container(
80 | margin: const EdgeInsets.only(right: 10.0),
81 | child: Icon(
82 | Icons.mic,
83 | color: Color(0xffaaaaaa),
84 | ),
85 | ),
86 | ],
87 | ),
88 | ),
89 | ],
90 | ),
91 | Container(
92 | margin:const EdgeInsets.only(top: 50.0),
93 | child: Text(
94 | '搜索指定内容',
95 | style: TextStyle(fontSize: 16.0,color: Color(0xffb5b5b5)),
96 | ),
97 | ),
98 | Padding(
99 | padding: const EdgeInsets.all(30.0),
100 | child: Row(
101 | mainAxisAlignment: MainAxisAlignment.spaceAround,
102 | children: [
103 | _getText('朋友圈'),
104 | _getText('文章'),
105 | _getText('公众号'),
106 | ],
107 | ),
108 | ),
109 | ],
110 | ),
111 | ),
112 | );
113 | }
114 |
115 |
116 | }
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: tbcontact
2 | description: A new Flutter application.
3 |
4 | dependencies:
5 | flutter:
6 | sdk: flutter
7 |
8 | flutter_webview_plugin: ^0.2.1+2
9 | lpinyin: ^1.0.7
10 | azlistview: ^0.1.0
11 | jmessage_flutter: ^0.0.8
12 | json_serializable: ^2.0.1
13 | dio: ^2.0.0
14 | flutter_slidable: ^0.4.9
15 | url_launcher: ^5.0.0
16 | font_awesome_flutter: ^8.2.0
17 | common_utils: ^1.0.9
18 | flushbar: ^1.2.1
19 | transparent_image: ^0.1.0
20 | cached_network_image: ^0.5.1
21 |
22 | dev_dependencies:
23 | flutter_test:
24 | sdk: flutter
25 |
26 |
27 | flutter:
28 |
29 | uses-material-design: true
30 |
31 | assets:
32 |
33 | - images/loading.jpg
34 | - images/login_logo.png
35 |
36 | #4个tab切换图片资源
37 | - images/contact_list_normal.png
38 | - images/contact_list_pressed.png
39 | - images/find_normal.png
40 | - images/find_pressed.png
41 | - images/profile_normal.png
42 | - images/profile_pressed.png
43 | - images/weixin_normal.png
44 | - images/weixin_pressed.png
45 |
46 | #菜单按钮
47 | - images/icon_menu_addfriend.png
48 | - images/icon_menu_group.png
49 | - images/icon_menu_scan.png
50 |
51 | #通讯录图标
52 | - images/icon_addfriend.png
53 | - images/icon_groupchat.png
54 | - images/icon_public.png
55 |
56 |
57 | #发现模块图标
58 | - images/icon_friends.png
59 | - images/icon_scan.png
60 | - images/icon_shake.png
61 | - images/icon_look.png
62 | - images/icon_search.png
63 | - images/icon_near.png
64 | - images/icon_bottle.png
65 | - images/icon_shop.png
66 | - images/icon_game.png
67 | - images/icon_link.png
68 |
69 |
70 | #个人中心模块图标
71 | - images/icon_me_card.png
72 | - images/icon_me_collect.png
73 | - images/icon_me_money.png
74 | - images/icon_me_photo.png
75 | - images/icon_me_setting.png
76 | - images/icon_me_smile.png
77 | - images/code.png
78 | - images/tutu.png
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/res/values/strings_en.arb:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------