├── ios
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── 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-1024x1024@1x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── build
│ └── XCBuildData
│ │ ├── build.db
│ │ ├── 7c3c4c189d1f80b76698c451bd5077cf-desc.xcbuild
│ │ ├── ad56d1583fd8aa8a249efbeeed14e852-desc.xcbuild
│ │ ├── b0a4c8cbd9a8dab09114fb1fa9023628-desc.xcbuild
│ │ ├── eff7d1a8350f5f87a4e980a33ae8d563-desc.xcbuild
│ │ └── BuildDescriptionCacheIndex-616f3cf5e93a195b4151706079281249
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── AppFrameworkInfo.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ └── project.pbxproj
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── .gitignore
├── Podfile.lock
└── Podfile
├── lib
├── app
│ ├── global.dart
│ ├── locator.dart
│ ├── route_names.dart
│ └── navigation_service.dart
├── share
│ ├── my_sliver_appbar_delegate.dart
│ ├── grid_icon.dart
│ ├── icon_add.dart
│ ├── snapping_scroll_physics.dart
│ ├── shared_style.dart
│ ├── text.dart
│ └── route.dart
├── main.dart
├── model
│ ├── topic_model.dart
│ └── user_model.dart
└── screen
│ ├── search_view.dart
│ └── home_view.dart
├── screenshot
└── home.png
├── fonts
├── Nunito-Bold.ttf
├── Nunito-Black.ttf
├── Nunito-Italic.ttf
├── Nunito-Light.ttf
├── Nunito-Regular.ttf
├── Nunito-ExtraBold.ttf
├── Nunito-SemiBold.ttf
├── Nunito-BlackItalic.ttf
├── Nunito-BoldItalic.ttf
├── Nunito-ExtraLight.ttf
├── Nunito-LightItalic.ttf
├── Nunito-SemiBoldItalic.ttf
├── Nunito-ExtraBoldItalic.ttf
└── Nunito-ExtraLightItalic.ttf
├── android
├── gradle.properties
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── 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
│ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ └── values
│ │ │ │ │ └── styles.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── ClubHouseClone
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── .gitignore
├── settings.gradle
└── build.gradle
├── README.md
├── .metadata
├── .gitignore
├── test
└── widget_test.dart
├── pubspec.yaml
└── pubspec.lock
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/lib/app/global.dart:
--------------------------------------------------------------------------------
1 | class Global {
2 | static Future init() async {}
3 | }
4 |
--------------------------------------------------------------------------------
/screenshot/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/screenshot/home.png
--------------------------------------------------------------------------------
/fonts/Nunito-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-Bold.ttf
--------------------------------------------------------------------------------
/fonts/Nunito-Black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-Black.ttf
--------------------------------------------------------------------------------
/fonts/Nunito-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-Italic.ttf
--------------------------------------------------------------------------------
/fonts/Nunito-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-Light.ttf
--------------------------------------------------------------------------------
/fonts/Nunito-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-Regular.ttf
--------------------------------------------------------------------------------
/fonts/Nunito-ExtraBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-ExtraBold.ttf
--------------------------------------------------------------------------------
/fonts/Nunito-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-SemiBold.ttf
--------------------------------------------------------------------------------
/fonts/Nunito-BlackItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-BlackItalic.ttf
--------------------------------------------------------------------------------
/fonts/Nunito-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-BoldItalic.ttf
--------------------------------------------------------------------------------
/fonts/Nunito-ExtraLight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-ExtraLight.ttf
--------------------------------------------------------------------------------
/fonts/Nunito-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-LightItalic.ttf
--------------------------------------------------------------------------------
/fonts/Nunito-SemiBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-SemiBoldItalic.ttf
--------------------------------------------------------------------------------
/ios/build/XCBuildData/build.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/ios/build/XCBuildData/build.db
--------------------------------------------------------------------------------
/fonts/Nunito-ExtraBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-ExtraBoldItalic.ttf
--------------------------------------------------------------------------------
/fonts/Nunito-ExtraLightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/fonts/Nunito-ExtraLightItalic.ttf
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 | android.enableR8=true
5 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ClubHouseClone
2 |
3 | Clubhouse Clone in Flutter
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/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/imchlorine/Flutter-Clubhouse-Clone/HEAD/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/imchlorine/Flutter-Clubhouse-Clone/HEAD/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/imchlorine/Flutter-Clubhouse-Clone/HEAD/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/imchlorine/Flutter-Clubhouse-Clone/HEAD/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/imchlorine/Flutter-Clubhouse-Clone/HEAD/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/imchlorine/Flutter-Clubhouse-Clone/HEAD/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/imchlorine/Flutter-Clubhouse-Clone/HEAD/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/imchlorine/Flutter-Clubhouse-Clone/HEAD/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/imchlorine/Flutter-Clubhouse-Clone/HEAD/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/imchlorine/Flutter-Clubhouse-Clone/HEAD/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/imchlorine/Flutter-Clubhouse-Clone/HEAD/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/imchlorine/Flutter-Clubhouse-Clone/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/build/XCBuildData/7c3c4c189d1f80b76698c451bd5077cf-desc.xcbuild:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/ios/build/XCBuildData/7c3c4c189d1f80b76698c451bd5077cf-desc.xcbuild
--------------------------------------------------------------------------------
/ios/build/XCBuildData/ad56d1583fd8aa8a249efbeeed14e852-desc.xcbuild:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/ios/build/XCBuildData/ad56d1583fd8aa8a249efbeeed14e852-desc.xcbuild
--------------------------------------------------------------------------------
/ios/build/XCBuildData/b0a4c8cbd9a8dab09114fb1fa9023628-desc.xcbuild:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/ios/build/XCBuildData/b0a4c8cbd9a8dab09114fb1fa9023628-desc.xcbuild
--------------------------------------------------------------------------------
/ios/build/XCBuildData/eff7d1a8350f5f87a4e980a33ae8d563-desc.xcbuild:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/ios/build/XCBuildData/eff7d1a8350f5f87a4e980a33ae8d563-desc.xcbuild
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/ClubHouseClone/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.ClubHouseClone
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/ios/build/XCBuildData/BuildDescriptionCacheIndex-616f3cf5e93a195b4151706079281249:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imchlorine/Flutter-Clubhouse-Clone/HEAD/ios/build/XCBuildData/BuildDescriptionCacheIndex-616f3cf5e93a195b4151706079281249
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/lib/app/locator.dart:
--------------------------------------------------------------------------------
1 | import 'package:get_it/get_it.dart';
2 | import 'package:ClubHouseClone/app/navigation_service.dart';
3 |
4 | GetIt locator = GetIt.instance;
5 |
6 | void setupLocator() {
7 | locator.registerLazySingleton(() => NavigationService());
8 | }
9 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
7 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.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: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/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/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/share/my_sliver_appbar_delegate.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | class MySliverAppBarDelegate extends SliverPersistentHeaderDelegate {
4 | final PreferredSize child;
5 |
6 | MySliverAppBarDelegate({this.child});
7 |
8 | @override
9 | Widget build(
10 | BuildContext context, double shrinkOffset, bool overlapsContent) {
11 | return child;
12 | }
13 |
14 | @override
15 | double get maxExtent => child.preferredSize.height;
16 |
17 | @override
18 | double get minExtent => child.preferredSize.height;
19 |
20 | @override
21 | bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
22 | return false;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/share/grid_icon.dart:
--------------------------------------------------------------------------------
1 | import 'package:ClubHouseClone/share/shared_style.dart';
2 | import 'package:flutter/cupertino.dart';
3 |
4 | class GridIcon extends StatefulWidget {
5 | final Function onTap;
6 | const GridIcon({Key key, this.onTap}) : super(key: key);
7 |
8 | @override
9 | GridIconState createState() => GridIconState();
10 | }
11 |
12 | class GridIconState extends State {
13 | bool showGridIcon;
14 | void changeState(value) {
15 | setState(() {
16 | showGridIcon = value;
17 | });
18 | }
19 |
20 | @override
21 | void initState() {
22 | super.initState();
23 | showGridIcon = true;
24 | }
25 |
26 | @override
27 | Widget build(BuildContext context) {
28 | return Visibility(
29 | visible: showGridIcon,
30 | child: GestureDetector(
31 | onTap: widget.onTap,
32 | child: Icon(
33 | CupertinoIcons.circle_grid_3x3_fill,
34 | color: brown,
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Flutter (1.0.0)
3 | - FMDB (2.7.5):
4 | - FMDB/standard (= 2.7.5)
5 | - FMDB/standard (2.7.5)
6 | - path_provider (0.0.1):
7 | - Flutter
8 | - sqflite (0.0.2):
9 | - Flutter
10 | - FMDB (>= 2.7.5)
11 |
12 | DEPENDENCIES:
13 | - Flutter (from `Flutter`)
14 | - path_provider (from `.symlinks/plugins/path_provider/ios`)
15 | - sqflite (from `.symlinks/plugins/sqflite/ios`)
16 |
17 | SPEC REPOS:
18 | trunk:
19 | - FMDB
20 |
21 | EXTERNAL SOURCES:
22 | Flutter:
23 | :path: Flutter
24 | path_provider:
25 | :path: ".symlinks/plugins/path_provider/ios"
26 | sqflite:
27 | :path: ".symlinks/plugins/sqflite/ios"
28 |
29 | SPEC CHECKSUMS:
30 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
31 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
32 | path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
33 | sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
34 |
35 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
36 |
37 | COCOAPODS: 1.10.1
38 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:ClubHouseClone/app/global.dart';
2 | import 'package:ClubHouseClone/app/locator.dart';
3 | import 'package:ClubHouseClone/app/navigation_service.dart';
4 | import 'package:ClubHouseClone/app/route_names.dart';
5 | import 'package:ClubHouseClone/screen/home_view.dart';
6 | import 'package:flutter/cupertino.dart';
7 |
8 |
9 | void main() {
10 | setupLocator();
11 | WidgetsFlutterBinding.ensureInitialized();
12 | Global.init().then((e) => runApp(MyApp()));
13 | }
14 |
15 | class MyApp extends StatelessWidget {
16 | // This widget is the root of your application.
17 | @override
18 | Widget build(BuildContext context) {
19 | return CupertinoApp(
20 | navigatorKey: locator().navigationKey,
21 | theme: CupertinoThemeData(
22 | textTheme: CupertinoTextThemeData(
23 | textStyle: TextStyle(
24 | color: CupertinoColors.black,
25 | fontFamily: 'Nunito',
26 | ),
27 | ),
28 | ),
29 | home: HomeView(),
30 | onGenerateRoute: generateRoute,
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/app/route_names.dart:
--------------------------------------------------------------------------------
1 | import 'package:ClubHouseClone/screen/home_view.dart';
2 | import 'package:ClubHouseClone/screen/search_view.dart';
3 | import 'package:ClubHouseClone/share/route.dart' as route;
4 | import 'package:flutter/cupertino.dart';
5 |
6 | const String RootRoute = "/";
7 | const String HomeViewRoute = "HomeView";
8 | const String SearchViewRoute = "SearchView";
9 |
10 | Route generateRoute(RouteSettings settings) {
11 | switch (settings.name) {
12 | case HomeViewRoute:
13 | return _getPageRouteCupertino(
14 | viewToShow: HomeView(),
15 | );
16 | case SearchViewRoute:
17 | return _getPageRouteCupertino(
18 | viewToShow: SearchView(),
19 | );
20 | default:
21 | return _getPageRouteCupertino(
22 | viewToShow: CupertinoPageScaffold(
23 | child: Center(child: Text('No route defined for ${settings.name}')),
24 | ),
25 | );
26 | }
27 | }
28 |
29 | PageRoute _getPageRouteCupertino({Widget viewToShow}) {
30 | return route.CupertinoPageRoute(
31 | // fullscreenDialog: true,
32 | builder: (_) => viewToShow,
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/lib/app/navigation_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class NavigationService {
4 | GlobalKey _navigationKey = GlobalKey();
5 | GlobalKey get navigationKey => _navigationKey;
6 | pop() {
7 | _navigationKey.currentState.pop();
8 | }
9 |
10 | Future navigateTo(String routeName, {dynamic arguments}) {
11 | return _navigationKey.currentState
12 | .pushNamed(routeName, arguments: arguments);
13 | }
14 |
15 | Future navigateReplace(String routeName, {dynamic arguments}) {
16 | return _navigationKey.currentState
17 | .pushReplacementNamed(routeName, arguments: arguments);
18 | }
19 |
20 | Future popAndPushNamed(String routeName, {dynamic arguments}) {
21 | return _navigationKey.currentState
22 | .popAndPushNamed(routeName, arguments: arguments);
23 | }
24 |
25 | Future pushNamedAndRemoveUntil(String routeName, {dynamic arguments}) {
26 | return _navigationKey.currentState.pushNamedAndRemoveUntil(
27 | routeName, (Route route) => false,
28 | arguments: arguments);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:ClubHouseClone/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/lib/model/topic_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:ClubHouseClone/model/user_model.dart';
2 |
3 | class TopicModel {
4 | final String topicId;
5 | final String clubName;
6 | final String topicTitle;
7 | final List users;
8 | final int audienceNumber;
9 | final int speechNumber;
10 |
11 | TopicModel({
12 | this.topicId,
13 | this.clubName,
14 | this.topicTitle,
15 | this.users,
16 | this.audienceNumber,
17 | this.speechNumber,
18 | });
19 | }
20 |
21 | class TopicModelData {
22 | List topicData = [
23 | TopicModel(
24 | topicId: "1",
25 | clubName: "My club",
26 | topicTitle: "How are you? Welcome to My room, let's have a talk!! ",
27 | users: UserModelData().userData1,
28 | audienceNumber: 1000,
29 | speechNumber: 5),
30 | TopicModel(
31 | topicId: "2",
32 | clubName: "TECH TALKS",
33 | topicTitle: "Flutter vs React Native",
34 | users: UserModelData().userData2,
35 | audienceNumber: 510,
36 | speechNumber: 10),
37 | TopicModel(
38 | topicId: "3",
39 | topicTitle: "Coffee",
40 | users: UserModelData().userData1,
41 | audienceNumber: 10,
42 | speechNumber: 2),
43 | ];
44 | }
45 |
--------------------------------------------------------------------------------
/lib/model/user_model.dart:
--------------------------------------------------------------------------------
1 | class UserModel {
2 | final String userId;
3 | final String userName;
4 | final String userImage;
5 |
6 | UserModel({
7 | this.userId,
8 | this.userName,
9 | this.userImage,
10 | });
11 | }
12 |
13 | class UserModelData {
14 | List userData1 = [
15 | UserModel(
16 | userId: "3",
17 | userName: "Elon Mask",
18 | userImage:
19 | "https://content.fortune.com/wp-content/uploads/2021/02/GettyImages-1229901940.jpg",
20 | ),
21 | UserModel(
22 | userId: "2",
23 | userName: "Tim Cook",
24 | userImage:
25 | "https://photos5.appleinsider.com/gallery/37111-69508-Tim-Cook-Onstage-xl.jpg",
26 | ),
27 | UserModel(
28 | userId: "1",
29 | userName: "Ricky",
30 | userImage:
31 | "https://images.pexels.com/photos/415829/pexels-photo-415829.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
32 | ),
33 | ];
34 |
35 | List userData2 = [
36 | UserModel(
37 | userId: "4",
38 | userName: "Chris",
39 | userImage:
40 | "https://images.pexels.com/photos/697509/pexels-photo-697509.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
41 | ),
42 | UserModel(
43 | userId: "4",
44 | userName: "Shorr",
45 | userImage:
46 | "https://images.pexels.com/photos/1310522/pexels-photo-1310522.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
47 | ),
48 | ];
49 | }
50 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ClubHouseClone
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 |
--------------------------------------------------------------------------------
/lib/share/icon_add.dart:
--------------------------------------------------------------------------------
1 | import 'package:ClubHouseClone/share/shared_style.dart';
2 | import 'package:cached_network_image/cached_network_image.dart';
3 | import 'package:flutter/cupertino.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class IconAdd extends StatelessWidget {
7 | final String imageUrl;
8 | final double size;
9 | const IconAdd({
10 | Key key,
11 | @required this.imageUrl,
12 | this.size = 48,
13 | }) : super(key: key);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Container(
18 | child: Stack(
19 | children: [
20 | Padding(
21 | padding: EdgeInsets.all(5),
22 | child: Container(
23 | height: size * 1.05,
24 | width: size,
25 | decoration: BoxDecoration(
26 | borderRadius: BorderRadius.circular(size / 2.1),
27 | ),
28 | clipBehavior: Clip.hardEdge,
29 | child: CachedNetworkImage(
30 | imageUrl: imageUrl,
31 | fit: BoxFit.cover,
32 | ),
33 | ),
34 | ),
35 | Positioned(
36 | left: size / 2.5 > 18 ? 0 : 2,
37 | bottom: size / 2.5 > 18 ? 0 : 2,
38 | child: Container(
39 | alignment: Alignment.center,
40 | height: size / 2.5,
41 | width: size / 2.5,
42 | decoration: BoxDecoration(
43 | shape: BoxShape.circle,
44 | color: themeColor,
45 | ),
46 | child: Icon(Icons.add_circle_rounded,
47 | color: indigo, size: size / 2.5),
48 | ),
49 | ),
50 | ],
51 | ),
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 29
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
41 | applicationId "com.example.ClubHouseClone"
42 | minSdkVersion 16
43 | targetSdkVersion 29
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | }
47 |
48 | buildTypes {
49 | release {
50 | // TODO: Add your own signing config for the release build.
51 | // Signing with the debug keys for now, so `flutter run --release` works.
52 | signingConfig signingConfigs.debug
53 | }
54 | }
55 | }
56 |
57 | flutter {
58 | source '../..'
59 | }
60 |
61 | dependencies {
62 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
63 | }
64 |
--------------------------------------------------------------------------------
/lib/share/snapping_scroll_physics.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'dart:math';
3 |
4 | import 'package:flutter/material.dart';
5 |
6 | class SnappingScrollPhysics extends ScrollPhysics {
7 | final double mainAxisStartPadding;
8 | final double itemExtent;
9 |
10 | const SnappingScrollPhysics({
11 | ScrollPhysics parent,
12 | this.mainAxisStartPadding = 0.0,
13 | @required this.itemExtent,
14 | }) : super(parent: parent);
15 |
16 | @override
17 | SnappingScrollPhysics applyTo(ScrollPhysics ancestor) {
18 | return SnappingScrollPhysics(
19 | parent: buildParent(ancestor),
20 | mainAxisStartPadding: mainAxisStartPadding,
21 | itemExtent: itemExtent,
22 | );
23 | }
24 |
25 | double _getItem(ScrollPosition position) {
26 | return (position.pixels - mainAxisStartPadding) / itemExtent;
27 | }
28 |
29 | double _getPixels(ScrollPosition position, double item) {
30 | return min(item * itemExtent, position.maxScrollExtent);
31 | }
32 |
33 | double _getTargetPixels(
34 | ScrollPosition position,
35 | Tolerance tolerance,
36 | double velocity,
37 | ) {
38 | double item = _getItem(position);
39 | if (velocity < -tolerance.velocity) {
40 | item -= 0.5;
41 | } else if (velocity > tolerance.velocity) {
42 | item += 0.5;
43 | }
44 | return _getPixels(position, item.roundToDouble());
45 | }
46 |
47 | @override
48 | Simulation createBallisticSimulation(
49 | ScrollMetrics position,
50 | double velocity,
51 | ) {
52 | if ((velocity <= 0.0 && position.pixels <= position.minScrollExtent) ||
53 | (velocity >= 0.0 && position.pixels >= position.maxScrollExtent))
54 | return super.createBallisticSimulation(position, velocity);
55 | final Tolerance tolerance = this.tolerance;
56 | final double target = _getTargetPixels(position, tolerance, velocity);
57 | if (target != position.pixels)
58 | return ScrollSpringSimulation(spring, position.pixels, target, velocity,
59 | tolerance: tolerance);
60 | return null;
61 | }
62 |
63 | @override
64 | bool get allowImplicitScrolling => false;
65 | }
66 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
12 |
19 |
23 |
27 |
32 |
36 |
37 |
38 |
39 |
40 |
41 |
43 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/lib/share/shared_style.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | const Widget horizontalSpaceTiny = SizedBox(width: 5.0);
4 | const Widget horizontalSpaceSmall = SizedBox(width: 10.0);
5 | const Widget horizontalSpaceMedium = SizedBox(width: 25.0);
6 |
7 | const Widget verticalSpaceTiny = SizedBox(height: 5.0);
8 | const Widget verticalSpaceSmall = SizedBox(height: 10.0);
9 | const Widget verticalSpaceMedium = SizedBox(height: 25.0);
10 | const Widget verticalSpaceLarge = SizedBox(height: 50.0);
11 | const Widget verticalSpaceMassive = SizedBox(height: 120.0);
12 |
13 | Widget spacedDivider = Column(
14 | children: const [
15 | verticalSpaceMedium,
16 | const Divider(color: Colors.blueGrey, height: 5.0),
17 | verticalSpaceMedium,
18 | ],
19 | );
20 |
21 | Widget verticalSpace(double height) => SizedBox(height: height);
22 |
23 | double screenWidth(BuildContext context) => MediaQuery.of(context).size.width;
24 | double screenHeight(BuildContext context) => MediaQuery.of(context).size.height;
25 |
26 | double screenHeightFraction(BuildContext context,
27 | {int dividedBy = 1, double offsetBy = 0}) =>
28 | (screenHeight(context) - offsetBy) / dividedBy;
29 |
30 | double screenWidthFraction(BuildContext context,
31 | {int dividedBy = 1, double offsetBy = 0}) =>
32 | (screenWidth(context) - offsetBy) / dividedBy;
33 |
34 | double halfScreenWidth(BuildContext context) =>
35 | screenWidthFraction(context, dividedBy: 2);
36 |
37 | double thirdScreenWidth(BuildContext context) =>
38 | screenWidthFraction(context, dividedBy: 3);
39 |
40 | // Box Decorations
41 |
42 | BoxDecoration fieldDecortaion =
43 | BoxDecoration(borderRadius: BorderRadius.circular(40), color: Colors.white);
44 |
45 | BoxDecoration disabledFieldDecortaion = BoxDecoration(
46 | borderRadius: BorderRadius.circular(40), color: Colors.grey[100]);
47 |
48 | // Field Variables
49 |
50 | const double fieldHeight = 55;
51 | const double smallFieldHeight = 40;
52 | const double inputFieldBottomMargin = 30;
53 | const double inputFieldSmallBottomMargin = 0;
54 | const EdgeInsets fieldPadding = const EdgeInsets.symmetric(horizontal: 15);
55 | const EdgeInsets largeFieldPadding =
56 | const EdgeInsets.symmetric(horizontal: 15, vertical: 15);
57 |
58 | // Text Variables
59 | const TextStyle buttonTitleTextStyle =
60 | const TextStyle(fontWeight: FontWeight.w700, color: Colors.white);
61 |
62 | // Colors
63 | const Color themeColor = Color(0xFFf1eee5);
64 | const Color followColor = Color(0xFFf7f4ef);
65 | const Color indigo = Color(0xFF5c75a6);
66 | const Color green = Color(0xFF56ab68);
67 | const Color brown = Color(0xFF6f664e);
68 | const Color search = Color(0xFFe3e0d9);
69 | const Color white = Color(0xFFffffff);
70 | const Color black = Color(0xFF000000);
71 | const Color grey = Color(0xFFf2f2f2);
72 | const Color grey1 = Color(0xFFdddddd);
73 |
74 | const Color grey2 = Color(0xFFe8e7ec);
75 | const Color grey3 = Color(0xFFf9f8fb);
76 |
77 | const double fontSize1 = 15;
78 | const double fontSize2 = 16;
79 | const double fontSize3 = 20;
80 | const double fontSize4 = 23;
81 | const double fontSize5 = 26;
82 | const double fontSize6 = 39;
83 |
--------------------------------------------------------------------------------
/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.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: ClubHouseClone
2 | description: A new Flutter project.
3 |
4 | # The following line prevents the package from being accidentally published to
5 | # pub.dev using `pub publish`. This is preferred for private packages.
6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
7 |
8 | # The following defines the version and build number for your application.
9 | # A version number is three numbers separated by dots, like 1.2.43
10 | # followed by an optional build number separated by a +.
11 | # Both the version and the builder number may be overridden in flutter
12 | # build by specifying --build-name and --build-number, respectively.
13 | # In Android, build-name is used as versionName while build-number used as versionCode.
14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
16 | # Read more about iOS versioning at
17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
18 | version: 1.0.0+1
19 |
20 | environment:
21 | sdk: ">=2.7.0 <3.0.0"
22 |
23 | dependencies:
24 | flutter:
25 | sdk: flutter
26 |
27 |
28 | # The following adds the Cupertino Icons font to your application.
29 | # Use with the CupertinoIcons class for iOS style icons.
30 | cupertino_icons: ^1.0.0
31 | get_it: ^3.0.0+1
32 | cached_network_image: ^2.5.1
33 | flutter_emoji: ">= 2.0.0"
34 | visibility_detector: ^0.1.5
35 |
36 |
37 |
38 |
39 |
40 |
41 | dev_dependencies:
42 | flutter_test:
43 | sdk: flutter
44 |
45 | # For information on the generic Dart part of this file, see the
46 | # following page: https://dart.dev/tools/pub/pubspec
47 |
48 | # The following section is specific to Flutter.
49 | flutter:
50 |
51 | # The following line ensures that the Material Icons font is
52 | # included with your application, so that you can use the icons in
53 | # the material Icons class.
54 | uses-material-design: true
55 |
56 | # To add assets to your application, add an assets section, like this:
57 | # assets:
58 | # - images/a_dot_burr.jpeg
59 | # - images/a_dot_ham.jpeg
60 |
61 | # An image asset can refer to one or more resolution-specific "variants", see
62 | # https://flutter.dev/assets-and-images/#resolution-aware.
63 |
64 | # For details regarding adding assets from package dependencies, see
65 | # https://flutter.dev/assets-and-images/#from-packages
66 |
67 | # To add custom fonts to your application, add a fonts section here,
68 | # in this "flutter" section. Each entry in this list should have a
69 | # "family" key with the font family name, and a "fonts" key with a
70 | # list giving the asset and other descriptors for the font. For
71 | # example:
72 | # fonts:
73 | # - family: Schyler
74 | # fonts:
75 | # - asset: fonts/Schyler-Regular.ttf
76 | # - asset: fonts/Schyler-Italic.ttf
77 | # style: italic
78 | # - family: Trajan Pro
79 | # fonts:
80 | # - asset: fonts/TrajanPro.ttf
81 | # - asset: fonts/TrajanPro_Bold.ttf
82 | # weight: 700
83 | #
84 | fonts:
85 | - family: Nunito
86 | fonts:
87 | - asset: fonts/Nunito-Black.ttf
88 | weight: 900
89 | - asset: fonts/Nunito-ExtraBold.ttf
90 | weight: 800
91 | - asset: fonts/Nunito-Bold.ttf
92 | weight: 700
93 | - asset: fonts/Nunito-SemiBold.ttf
94 | weight: 600
95 | - asset: fonts/Nunito-Regular.ttf
96 | weight: 400
97 | - asset: fonts/Nunito-Italic.ttf
98 | # For details regarding fonts from package dependencies,
99 | # see https://flutter.dev/custom-fonts/#from-packages
100 |
--------------------------------------------------------------------------------
/lib/screen/search_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:ClubHouseClone/app/locator.dart';
2 | import 'package:ClubHouseClone/app/navigation_service.dart';
3 | import 'package:ClubHouseClone/share/my_sliver_appbar_delegate.dart';
4 | import 'package:ClubHouseClone/share/shared_style.dart';
5 | import 'package:cached_network_image/cached_network_image.dart';
6 | import 'package:flutter/cupertino.dart';
7 | import 'package:ClubHouseClone/share/nav_bar.dart' as nav_bar;
8 | import 'package:flutter/material.dart';
9 |
10 | class SearchView extends StatefulWidget {
11 | const SearchView({
12 | Key key,
13 | }) : super(key: key);
14 |
15 | @override
16 | State createState() {
17 | return _SearchViewState();
18 | }
19 | }
20 |
21 | class _SearchViewState extends State with WidgetsBindingObserver {
22 | NavigationService _navigationService = locator();
23 |
24 | @override
25 | void initState() {
26 | super.initState();
27 | }
28 |
29 | @override
30 | void dispose() {
31 | super.dispose();
32 | }
33 |
34 | @override
35 | void didChangeAppLifecycleState(AppLifecycleState state) {
36 | print('state = $state');
37 | }
38 |
39 | @override
40 | Widget build(BuildContext context) {
41 | return CupertinoPageScaffold(
42 | backgroundColor: themeColor,
43 | navigationBar: nav_bar.CupertinoNavigationBar(
44 | border: null,
45 | padding: EdgeInsetsDirectional.zero,
46 | backgroundColor: themeColor,
47 | automaticallyImplyLeading: false,
48 | leading: CupertinoButton(
49 | padding: EdgeInsets.zero,
50 | child: Icon(
51 | CupertinoIcons.back,
52 | size: 35,
53 | color: CupertinoColors.black,
54 | ),
55 | onPressed: () {
56 | _navigationService.pop();
57 | },
58 | ),
59 | middle: Text(
60 | "EXPLORE",
61 | textScaleFactor: 1.0,
62 | style: TextStyle(fontSize: 16, color: black),
63 | ),
64 | ),
65 | child: CustomScrollView(
66 | slivers: [
67 | SliverPersistentHeader(
68 | pinned: true,
69 | delegate: MySliverAppBarDelegate(
70 | child: PreferredSize(
71 | preferredSize: Size.fromHeight(50.0),
72 | child: _searchWidget(),
73 | ),
74 | ),
75 | ),
76 | SliverToBoxAdapter(
77 | child: Container(
78 | padding: EdgeInsets.fromLTRB(16, 30, 16, 10),
79 | child: Text(
80 | "PEOPLE TO FELLOW",
81 | textScaleFactor: 1,
82 | style: TextStyle(
83 | fontWeight: FontWeight.bold,
84 | ),
85 | ),
86 | ),
87 | ),
88 | SliverList(
89 | delegate: SliverChildBuilderDelegate(
90 | (BuildContext context, int index) {
91 | return Container(
92 | height: 80,
93 | color: followColor,
94 | padding: EdgeInsets.symmetric(horizontal: 16),
95 | child: Row(
96 | children: [
97 | Container(
98 | height: 45,
99 | width: 45,
100 | decoration: BoxDecoration(
101 | borderRadius: BorderRadius.circular(20),
102 | ),
103 | clipBehavior: Clip.hardEdge,
104 | child: CachedNetworkImage(
105 | imageUrl:
106 | "https://content.fortune.com/wp-content/uploads/2021/02/GettyImages-1229901940.jpg",
107 | fit: BoxFit.cover,
108 | ),
109 | ),
110 | SizedBox(
111 | width: 16,
112 | ),
113 | Expanded(
114 | child: Column(
115 | mainAxisAlignment: MainAxisAlignment.center,
116 | crossAxisAlignment: CrossAxisAlignment.start,
117 | children: [
118 | Text(
119 | "Elon Mask",
120 | textScaleFactor: 1,
121 | style: TextStyle(
122 | fontSize: 16, fontWeight: FontWeight.bold),
123 | ),
124 | Text(
125 | "Lorem ipsum dolor sit amet, est eius accusata maluisset eu, omnis aperiam accusamus sit ex.",
126 | textScaleFactor: 1,
127 | maxLines: 2,
128 | overflow: TextOverflow.ellipsis,
129 | ),
130 | ],
131 | ),
132 | ),
133 | SizedBox(
134 | width: 16,
135 | ),
136 | FlatButton(
137 | child: Text(
138 | "Follow",
139 | textScaleFactor: 1,
140 | style: TextStyle(
141 | color: indigo,
142 | ),
143 | ),
144 | shape: RoundedRectangleBorder(
145 | side: BorderSide(
146 | color: indigo,
147 | width: 2,
148 | style: BorderStyle.solid,
149 | ),
150 | borderRadius: BorderRadius.circular(20)),
151 | onPressed: () {},
152 | ),
153 | ],
154 | ),
155 | );
156 | },
157 | childCount: 3,
158 | ),
159 | ),
160 | SliverToBoxAdapter(
161 | child: Container(
162 | padding: EdgeInsets.fromLTRB(16, 30, 16, 10),
163 | child: Text(
164 | "FIND CONVERSATIONS ABOUT...",
165 | textScaleFactor: 1,
166 | style: TextStyle(
167 | fontWeight: FontWeight.bold,
168 | ),
169 | ),
170 | ),
171 | ),
172 | ],
173 | ),
174 | );
175 | }
176 |
177 | _searchWidget() {
178 | return Container(
179 | height: 50,
180 | color: themeColor,
181 | child: Container(
182 | padding: EdgeInsets.fromLTRB(20, 0, 20, 10),
183 | child: GestureDetector(
184 | onTap: () {},
185 | child: AnimatedContainer(
186 | duration: Duration(milliseconds: 200),
187 | decoration: BoxDecoration(
188 | color: search,
189 | borderRadius: BorderRadius.circular(8.0),
190 | ),
191 | child: Row(
192 | mainAxisAlignment: MainAxisAlignment.start,
193 | children: [
194 | SizedBox(
195 | width: 5,
196 | ),
197 | Icon(
198 | CupertinoIcons.search,
199 | color: black.withOpacity(0.5),
200 | size: 22,
201 | ),
202 | SizedBox(
203 | width: 5,
204 | ),
205 | Expanded(
206 | child: Container(
207 | alignment: Alignment.centerLeft,
208 | child: Text(
209 | "Find People and Clubs",
210 | maxLines: 2,
211 | style: TextStyle(
212 | color: black.withOpacity(0.5),
213 | ),
214 | ),
215 | ),
216 | ),
217 | ],
218 | ),
219 | ),
220 | ),
221 | ),
222 | );
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | archive:
5 | dependency: transitive
6 | description:
7 | name: archive
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "2.0.13"
11 | args:
12 | dependency: transitive
13 | description:
14 | name: args
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "1.6.0"
18 | async:
19 | dependency: transitive
20 | description:
21 | name: async
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "2.5.0-nullsafety.1"
25 | boolean_selector:
26 | dependency: transitive
27 | description:
28 | name: boolean_selector
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "2.1.0-nullsafety.1"
32 | cached_network_image:
33 | dependency: "direct main"
34 | description:
35 | name: cached_network_image
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "2.5.1"
39 | characters:
40 | dependency: transitive
41 | description:
42 | name: characters
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "1.1.0-nullsafety.3"
46 | charcode:
47 | dependency: transitive
48 | description:
49 | name: charcode
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "1.2.0-nullsafety.1"
53 | clock:
54 | dependency: transitive
55 | description:
56 | name: clock
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "1.1.0-nullsafety.1"
60 | collection:
61 | dependency: transitive
62 | description:
63 | name: collection
64 | url: "https://pub.dartlang.org"
65 | source: hosted
66 | version: "1.15.0-nullsafety.3"
67 | convert:
68 | dependency: transitive
69 | description:
70 | name: convert
71 | url: "https://pub.dartlang.org"
72 | source: hosted
73 | version: "2.1.1"
74 | crypto:
75 | dependency: transitive
76 | description:
77 | name: crypto
78 | url: "https://pub.dartlang.org"
79 | source: hosted
80 | version: "2.1.5"
81 | cupertino_icons:
82 | dependency: "direct main"
83 | description:
84 | name: cupertino_icons
85 | url: "https://pub.dartlang.org"
86 | source: hosted
87 | version: "1.0.0"
88 | fake_async:
89 | dependency: transitive
90 | description:
91 | name: fake_async
92 | url: "https://pub.dartlang.org"
93 | source: hosted
94 | version: "1.2.0-nullsafety.1"
95 | ffi:
96 | dependency: transitive
97 | description:
98 | name: ffi
99 | url: "https://pub.dartlang.org"
100 | source: hosted
101 | version: "0.1.3"
102 | file:
103 | dependency: transitive
104 | description:
105 | name: file
106 | url: "https://pub.dartlang.org"
107 | source: hosted
108 | version: "5.2.1"
109 | flutter:
110 | dependency: "direct main"
111 | description: flutter
112 | source: sdk
113 | version: "0.0.0"
114 | flutter_blurhash:
115 | dependency: transitive
116 | description:
117 | name: flutter_blurhash
118 | url: "https://pub.dartlang.org"
119 | source: hosted
120 | version: "0.5.0"
121 | flutter_cache_manager:
122 | dependency: transitive
123 | description:
124 | name: flutter_cache_manager
125 | url: "https://pub.dartlang.org"
126 | source: hosted
127 | version: "2.1.2"
128 | flutter_emoji:
129 | dependency: "direct main"
130 | description:
131 | name: flutter_emoji
132 | url: "https://pub.dartlang.org"
133 | source: hosted
134 | version: "2.2.1+1"
135 | flutter_test:
136 | dependency: "direct dev"
137 | description: flutter
138 | source: sdk
139 | version: "0.0.0"
140 | get_it:
141 | dependency: "direct main"
142 | description:
143 | name: get_it
144 | url: "https://pub.dartlang.org"
145 | source: hosted
146 | version: "3.1.0"
147 | http:
148 | dependency: transitive
149 | description:
150 | name: http
151 | url: "https://pub.dartlang.org"
152 | source: hosted
153 | version: "0.12.2"
154 | http_parser:
155 | dependency: transitive
156 | description:
157 | name: http_parser
158 | url: "https://pub.dartlang.org"
159 | source: hosted
160 | version: "3.1.4"
161 | image:
162 | dependency: transitive
163 | description:
164 | name: image
165 | url: "https://pub.dartlang.org"
166 | source: hosted
167 | version: "2.1.19"
168 | intl:
169 | dependency: transitive
170 | description:
171 | name: intl
172 | url: "https://pub.dartlang.org"
173 | source: hosted
174 | version: "0.16.1"
175 | matcher:
176 | dependency: transitive
177 | description:
178 | name: matcher
179 | url: "https://pub.dartlang.org"
180 | source: hosted
181 | version: "0.12.10-nullsafety.1"
182 | meta:
183 | dependency: transitive
184 | description:
185 | name: meta
186 | url: "https://pub.dartlang.org"
187 | source: hosted
188 | version: "1.3.0-nullsafety.3"
189 | octo_image:
190 | dependency: transitive
191 | description:
192 | name: octo_image
193 | url: "https://pub.dartlang.org"
194 | source: hosted
195 | version: "0.3.0"
196 | path:
197 | dependency: transitive
198 | description:
199 | name: path
200 | url: "https://pub.dartlang.org"
201 | source: hosted
202 | version: "1.8.0-nullsafety.1"
203 | path_provider:
204 | dependency: transitive
205 | description:
206 | name: path_provider
207 | url: "https://pub.dartlang.org"
208 | source: hosted
209 | version: "1.6.27"
210 | path_provider_linux:
211 | dependency: transitive
212 | description:
213 | name: path_provider_linux
214 | url: "https://pub.dartlang.org"
215 | source: hosted
216 | version: "0.0.1+2"
217 | path_provider_macos:
218 | dependency: transitive
219 | description:
220 | name: path_provider_macos
221 | url: "https://pub.dartlang.org"
222 | source: hosted
223 | version: "0.0.4+8"
224 | path_provider_platform_interface:
225 | dependency: transitive
226 | description:
227 | name: path_provider_platform_interface
228 | url: "https://pub.dartlang.org"
229 | source: hosted
230 | version: "1.0.4"
231 | path_provider_windows:
232 | dependency: transitive
233 | description:
234 | name: path_provider_windows
235 | url: "https://pub.dartlang.org"
236 | source: hosted
237 | version: "0.0.4+3"
238 | pedantic:
239 | dependency: transitive
240 | description:
241 | name: pedantic
242 | url: "https://pub.dartlang.org"
243 | source: hosted
244 | version: "1.9.2"
245 | petitparser:
246 | dependency: transitive
247 | description:
248 | name: petitparser
249 | url: "https://pub.dartlang.org"
250 | source: hosted
251 | version: "3.1.0"
252 | platform:
253 | dependency: transitive
254 | description:
255 | name: platform
256 | url: "https://pub.dartlang.org"
257 | source: hosted
258 | version: "2.2.1"
259 | plugin_platform_interface:
260 | dependency: transitive
261 | description:
262 | name: plugin_platform_interface
263 | url: "https://pub.dartlang.org"
264 | source: hosted
265 | version: "1.0.3"
266 | process:
267 | dependency: transitive
268 | description:
269 | name: process
270 | url: "https://pub.dartlang.org"
271 | source: hosted
272 | version: "3.0.13"
273 | rxdart:
274 | dependency: transitive
275 | description:
276 | name: rxdart
277 | url: "https://pub.dartlang.org"
278 | source: hosted
279 | version: "0.25.0"
280 | sky_engine:
281 | dependency: transitive
282 | description: flutter
283 | source: sdk
284 | version: "0.0.99"
285 | source_span:
286 | dependency: transitive
287 | description:
288 | name: source_span
289 | url: "https://pub.dartlang.org"
290 | source: hosted
291 | version: "1.8.0-nullsafety.2"
292 | sqflite:
293 | dependency: transitive
294 | description:
295 | name: sqflite
296 | url: "https://pub.dartlang.org"
297 | source: hosted
298 | version: "1.3.2+4"
299 | sqflite_common:
300 | dependency: transitive
301 | description:
302 | name: sqflite_common
303 | url: "https://pub.dartlang.org"
304 | source: hosted
305 | version: "1.0.3+3"
306 | stack_trace:
307 | dependency: transitive
308 | description:
309 | name: stack_trace
310 | url: "https://pub.dartlang.org"
311 | source: hosted
312 | version: "1.10.0-nullsafety.1"
313 | stream_channel:
314 | dependency: transitive
315 | description:
316 | name: stream_channel
317 | url: "https://pub.dartlang.org"
318 | source: hosted
319 | version: "2.1.0-nullsafety.1"
320 | string_scanner:
321 | dependency: transitive
322 | description:
323 | name: string_scanner
324 | url: "https://pub.dartlang.org"
325 | source: hosted
326 | version: "1.1.0-nullsafety.1"
327 | synchronized:
328 | dependency: transitive
329 | description:
330 | name: synchronized
331 | url: "https://pub.dartlang.org"
332 | source: hosted
333 | version: "2.2.0+2"
334 | term_glyph:
335 | dependency: transitive
336 | description:
337 | name: term_glyph
338 | url: "https://pub.dartlang.org"
339 | source: hosted
340 | version: "1.2.0-nullsafety.1"
341 | test_api:
342 | dependency: transitive
343 | description:
344 | name: test_api
345 | url: "https://pub.dartlang.org"
346 | source: hosted
347 | version: "0.2.19-nullsafety.2"
348 | typed_data:
349 | dependency: transitive
350 | description:
351 | name: typed_data
352 | url: "https://pub.dartlang.org"
353 | source: hosted
354 | version: "1.3.0-nullsafety.3"
355 | uuid:
356 | dependency: transitive
357 | description:
358 | name: uuid
359 | url: "https://pub.dartlang.org"
360 | source: hosted
361 | version: "2.2.2"
362 | vector_math:
363 | dependency: transitive
364 | description:
365 | name: vector_math
366 | url: "https://pub.dartlang.org"
367 | source: hosted
368 | version: "2.1.0-nullsafety.3"
369 | visibility_detector:
370 | dependency: "direct main"
371 | description:
372 | name: visibility_detector
373 | url: "https://pub.dartlang.org"
374 | source: hosted
375 | version: "0.1.5"
376 | win32:
377 | dependency: transitive
378 | description:
379 | name: win32
380 | url: "https://pub.dartlang.org"
381 | source: hosted
382 | version: "1.7.4+1"
383 | xdg_directories:
384 | dependency: transitive
385 | description:
386 | name: xdg_directories
387 | url: "https://pub.dartlang.org"
388 | source: hosted
389 | version: "0.1.2"
390 | xml:
391 | dependency: transitive
392 | description:
393 | name: xml
394 | url: "https://pub.dartlang.org"
395 | source: hosted
396 | version: "4.5.1"
397 | sdks:
398 | dart: ">=2.10.2 <2.11.0"
399 | flutter: ">=1.22.2 <2.0.0"
400 |
--------------------------------------------------------------------------------
/lib/share/text.dart:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Flutter Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | // @dart = 2.8
6 |
7 | import 'dart:ui' as ui show TextHeightBehavior;
8 |
9 | import 'package:flutter/foundation.dart';
10 | import 'package:flutter/material.dart';
11 | import 'package:flutter/painting.dart';
12 |
13 | // Examples can assume:
14 | // String _name;
15 |
16 | /// The text style to apply to descendant [Text] widgets which don't have an
17 | /// explicit style.
18 | ///
19 | /// See also:
20 | ///
21 | /// * [AnimatedDefaultTextStyle], which animates changes in the text style
22 | /// smoothly over a given duration.
23 | /// * [DefaultTextStyleTransition], which takes a provided [Animation] to
24 | /// animate changes in text style smoothly over time.
25 | class DefaultTextStyle extends InheritedTheme {
26 | /// Creates a default text style for the given subtree.
27 | ///
28 | /// Consider using [DefaultTextStyle.merge] to inherit styling information
29 | /// from the current default text style for a given [BuildContext].
30 | ///
31 | /// The [style] and [child] arguments are required and must not be null.
32 | ///
33 | /// The [softWrap] and [overflow] arguments must not be null (though they do
34 | /// have default values).
35 | ///
36 | /// The [maxLines] property may be null (and indeed defaults to null), but if
37 | /// it is not null, it must be greater than zero.
38 | const DefaultTextStyle({
39 | Key key,
40 | @required this.style,
41 | this.textAlign,
42 | this.softWrap = true,
43 | this.overflow = TextOverflow.clip,
44 | this.maxLines,
45 | this.textWidthBasis = TextWidthBasis.parent,
46 | this.textHeightBehavior,
47 | @required Widget child,
48 | }) : assert(style != null),
49 | assert(softWrap != null),
50 | assert(overflow != null),
51 | assert(maxLines == null || maxLines > 0),
52 | assert(child != null),
53 | assert(textWidthBasis != null),
54 | super(key: key, child: child);
55 |
56 | /// A const-constructable default text style that provides fallback values.
57 | ///
58 | /// Returned from [of] when the given [BuildContext] doesn't have an enclosing default text style.
59 | ///
60 | /// This constructor creates a [DefaultTextStyle] that lacks a [child], which
61 | /// means the constructed value cannot be incorporated into the tree.
62 | const DefaultTextStyle.fallback({ Key key })
63 | : style = const TextStyle(),
64 | textAlign = null,
65 | softWrap = true,
66 | maxLines = null,
67 | overflow = TextOverflow.clip,
68 | textWidthBasis = TextWidthBasis.parent,
69 | textHeightBehavior = null,
70 | super(key: key, child: null);
71 |
72 | /// Creates a default text style that overrides the text styles in scope at
73 | /// this point in the widget tree.
74 | ///
75 | /// The given [style] is merged with the [style] from the default text style
76 | /// for the [BuildContext] where the widget is inserted, and any of the other
77 | /// arguments that are not null replace the corresponding properties on that
78 | /// same default text style.
79 | ///
80 | /// This constructor cannot be used to override the [maxLines] property of the
81 | /// ancestor with the value null, since null here is used to mean "defer to
82 | /// ancestor". To replace a non-null [maxLines] from an ancestor with the null
83 | /// value (to remove the restriction on number of lines), manually obtain the
84 | /// ambient [DefaultTextStyle] using [DefaultTextStyle.of], then create a new
85 | /// [DefaultTextStyle] using the [new DefaultTextStyle] constructor directly.
86 | /// See the source below for an example of how to do this (since that's
87 | /// essentially what this constructor does).
88 | static Widget merge({
89 | Key key,
90 | TextStyle style,
91 | TextAlign textAlign,
92 | bool softWrap,
93 | TextOverflow overflow,
94 | int maxLines,
95 | TextWidthBasis textWidthBasis,
96 | @required Widget child,
97 | }) {
98 | assert(child != null);
99 | return Builder(
100 | builder: (BuildContext context) {
101 | final DefaultTextStyle parent = DefaultTextStyle.of(context);
102 | return DefaultTextStyle(
103 | key: key,
104 | style: parent.style.merge(style),
105 | textAlign: textAlign ?? parent.textAlign,
106 | softWrap: softWrap ?? parent.softWrap,
107 | overflow: overflow ?? parent.overflow,
108 | maxLines: maxLines ?? parent.maxLines,
109 | textWidthBasis: textWidthBasis ?? parent.textWidthBasis,
110 | child: child,
111 | );
112 | },
113 | );
114 | }
115 |
116 | /// The text style to apply.
117 | final TextStyle style;
118 |
119 | /// How each line of text in the Text widget should be aligned horizontally.
120 | final TextAlign textAlign;
121 |
122 | /// Whether the text should break at soft line breaks.
123 | ///
124 | /// If false, the glyphs in the text will be positioned as if there was unlimited horizontal space.
125 | ///
126 | /// This also decides the [overflow] property's behavior. If this is true or null,
127 | /// the glyph causing overflow, and those that follow, will not be rendered.
128 | final bool softWrap;
129 |
130 | /// How visual overflow should be handled.
131 | ///
132 | /// If [softWrap] is true or null, the glyph causing overflow, and those that follow,
133 | /// will not be rendered. Otherwise, it will be shown with the given overflow option.
134 | final TextOverflow overflow;
135 |
136 | /// An optional maximum number of lines for the text to span, wrapping if necessary.
137 | /// If the text exceeds the given number of lines, it will be truncated according
138 | /// to [overflow].
139 | ///
140 | /// If this is 1, text will not wrap. Otherwise, text will be wrapped at the
141 | /// edge of the box.
142 | ///
143 | /// If this is non-null, it will override even explicit null values of
144 | /// [Text.maxLines].
145 | final int maxLines;
146 |
147 | /// The strategy to use when calculating the width of the Text.
148 | ///
149 | /// See [TextWidthBasis] for possible values and their implications.
150 | final TextWidthBasis textWidthBasis;
151 |
152 | /// {@macro flutter.dart:ui.textHeightBehavior}
153 | final ui.TextHeightBehavior textHeightBehavior;
154 |
155 | /// The closest instance of this class that encloses the given context.
156 | ///
157 | /// If no such instance exists, returns an instance created by
158 | /// [DefaultTextStyle.fallback], which contains fallback values.
159 | ///
160 | /// Typical usage is as follows:
161 | ///
162 | /// ```dart
163 | /// DefaultTextStyle style = DefaultTextStyle.of(context);
164 | /// ```
165 | static DefaultTextStyle of(BuildContext context) {
166 | return context.dependOnInheritedWidgetOfExactType() ?? const DefaultTextStyle.fallback();
167 | }
168 |
169 | @override
170 | bool updateShouldNotify(DefaultTextStyle oldWidget) {
171 | return style != oldWidget.style ||
172 | textAlign != oldWidget.textAlign ||
173 | softWrap != oldWidget.softWrap ||
174 | overflow != oldWidget.overflow ||
175 | maxLines != oldWidget.maxLines ||
176 | textWidthBasis != oldWidget.textWidthBasis ||
177 | textHeightBehavior != oldWidget.textHeightBehavior;
178 | }
179 |
180 | @override
181 | Widget wrap(BuildContext context, Widget child) {
182 | final DefaultTextStyle defaultTextStyle = context.findAncestorWidgetOfExactType();
183 | return identical(this, defaultTextStyle) ? child : DefaultTextStyle(
184 | style: style,
185 | textAlign: textAlign,
186 | softWrap: softWrap,
187 | overflow: overflow,
188 | maxLines: maxLines,
189 | textWidthBasis: textWidthBasis,
190 | textHeightBehavior: textHeightBehavior,
191 | child: child,
192 | );
193 | }
194 |
195 | @override
196 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
197 | super.debugFillProperties(properties);
198 | style?.debugFillProperties(properties);
199 | properties.add(EnumProperty('textAlign', textAlign, defaultValue: null));
200 | properties.add(FlagProperty('softWrap', value: softWrap, ifTrue: 'wrapping at box width', ifFalse: 'no wrapping except at line break characters', showName: true));
201 | properties.add(EnumProperty('overflow', overflow, defaultValue: null));
202 | properties.add(IntProperty('maxLines', maxLines, defaultValue: null));
203 | properties.add(EnumProperty('textWidthBasis', textWidthBasis, defaultValue: TextWidthBasis.parent));
204 | properties.add(DiagnosticsProperty('textHeightBehavior', textHeightBehavior, defaultValue: null));
205 | }
206 | }
207 |
208 | /// The [TextHeightBehavior] that will apply to descendant [Text] and [EditableText]
209 | /// widgets which have not explicitly set [Text.textHeightBehavior].
210 | ///
211 | /// If there is a [DefaultTextStyle] with a non-null [DefaultTextStyle.textHeightBehavior]
212 | /// below this widget, the [DefaultTextStyle.textHeightBehavior] will be used
213 | /// over this widget's [TextHeightBehavior].
214 | ///
215 | /// See also:
216 | ///
217 | /// * [DefaultTextStyle], which defines a [TextStyle] to apply to descendant
218 | /// [Text] widgets.
219 | class DefaultTextHeightBehavior extends InheritedTheme {
220 | /// Creates a default text height behavior for the given subtree.
221 | ///
222 | /// The [textHeightBehavior] and [child] arguments are required and must not be null.
223 | const DefaultTextHeightBehavior({
224 | Key key,
225 | @required this.textHeightBehavior,
226 | @required Widget child,
227 | }) : assert(textHeightBehavior != null),
228 | assert(child != null),
229 | super(key: key, child: child);
230 |
231 | /// {@macro flutter.dart:ui.textHeightBehavior}
232 | final TextHeightBehavior textHeightBehavior;
233 |
234 | /// The closest instance of this class that encloses the given context.
235 | ///
236 | /// If no such instance exists, this method will return `null`.
237 | ///
238 | /// Typical usage is as follows:
239 | ///
240 | /// ```dart
241 | /// DefaultTextHeightBehavior defaultTextHeightBehavior = DefaultTextHeightBehavior.of(context);
242 | /// ```
243 | static TextHeightBehavior of(BuildContext context) {
244 | return context.dependOnInheritedWidgetOfExactType()?.textHeightBehavior;
245 | }
246 |
247 | @override
248 | bool updateShouldNotify(DefaultTextHeightBehavior oldWidget) {
249 | return textHeightBehavior != oldWidget.textHeightBehavior;
250 | }
251 |
252 | @override
253 | Widget wrap(BuildContext context, Widget child) {
254 | final DefaultTextHeightBehavior defaultTextHeightBehavior = context.findAncestorWidgetOfExactType();
255 | return identical(this, defaultTextHeightBehavior) ? child : DefaultTextHeightBehavior(
256 | textHeightBehavior: textHeightBehavior,
257 | child: child,
258 | );
259 | }
260 |
261 | @override
262 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
263 | super.debugFillProperties(properties);
264 | properties.add(DiagnosticsProperty('textHeightBehavior', textHeightBehavior, defaultValue: null));
265 | }
266 | }
267 |
268 | /// A run of text with a single style.
269 | ///
270 | /// The [Text] widget displays a string of text with single style. The string
271 | /// might break across multiple lines or might all be displayed on the same line
272 | /// depending on the layout constraints.
273 | ///
274 | /// The [style] argument is optional. When omitted, the text will use the style
275 | /// from the closest enclosing [DefaultTextStyle]. If the given style's
276 | /// [TextStyle.inherit] property is true (the default), the given style will
277 | /// be merged with the closest enclosing [DefaultTextStyle]. This merging
278 | /// behavior is useful, for example, to make the text bold while using the
279 | /// default font family and size.
280 | ///
281 | /// {@tool snippet}
282 | ///
283 | /// This example shows how to display text using the [Text] widget with the
284 | /// [overflow] set to [TextOverflow.ellipsis].
285 | ///
286 | /// 
287 | ///
288 | /// 
289 | ///
290 | /// ```dart
291 | /// Text(
292 | /// 'Hello, $_name! How are you?',
293 | /// textAlign: TextAlign.center,
294 | /// overflow: TextOverflow.ellipsis,
295 | /// style: TextStyle(fontWeight: FontWeight.bold),
296 | /// )
297 | /// ```
298 | /// {@end-tool}
299 | ///
300 | /// Using the [Text.rich] constructor, the [Text] widget can
301 | /// display a paragraph with differently styled [TextSpan]s. The sample
302 | /// that follows displays "Hello beautiful world" with different styles
303 | /// for each word.
304 | ///
305 | /// {@tool snippet}
306 | ///
307 | /// 
308 | ///
309 | /// ```dart
310 | /// const Text.rich(
311 | /// TextSpan(
312 | /// text: 'Hello', // default text style
313 | /// children: [
314 | /// TextSpan(text: ' beautiful ', style: TextStyle(fontStyle: FontStyle.italic)),
315 | /// TextSpan(text: 'world', style: TextStyle(fontWeight: FontWeight.bold)),
316 | /// ],
317 | /// ),
318 | /// )
319 | /// ```
320 | /// {@end-tool}
321 | ///
322 | /// ## Interactivity
323 | ///
324 | /// To make [Text] react to touch events, wrap it in a [GestureDetector] widget
325 | /// with a [GestureDetector.onTap] handler.
326 | ///
327 | /// In a material design application, consider using a [TextButton] instead, or
328 | /// if that isn't appropriate, at least using an [InkWell] instead of
329 | /// [GestureDetector].
330 | ///
331 | /// To make sections of the text interactive, use [RichText] and specify a
332 | /// [TapGestureRecognizer] as the [TextSpan.recognizer] of the relevant part of
333 | /// the text.
334 | ///
335 | /// See also:
336 | ///
337 | /// * [RichText], which gives you more control over the text styles.
338 | /// * [DefaultTextStyle], which sets default styles for [Text] widgets.
339 | class Text extends StatelessWidget {
340 | /// Creates a text widget.
341 | ///
342 | /// If the [style] argument is null, the text will use the style from the
343 | /// closest enclosing [DefaultTextStyle].
344 | ///
345 | /// The [data] parameter must not be null.
346 | ///
347 | /// The [overflow] property's behavior is affected by the [softWrap] argument.
348 | /// If the [softWrap] is true or null, the glyph causing overflow, and those that follow,
349 | /// will not be rendered. Otherwise, it will be shown with the given overflow option.
350 | const Text(
351 | this.data, {
352 | Key key,
353 | this.style,
354 | this.strutStyle,
355 | this.textAlign,
356 | this.textDirection,
357 | this.locale,
358 | this.softWrap,
359 | this.overflow,
360 | this.textScaleFactor,
361 | this.maxLines,
362 | this.semanticsLabel,
363 | this.textWidthBasis,
364 | this.textHeightBehavior,
365 | }) : assert(
366 | data != null,
367 | 'A non-null String must be provided to a Text widget.',
368 | ),
369 | textSpan = null,
370 | super(key: key);
371 |
372 | /// Creates a text widget with a [InlineSpan].
373 | ///
374 | /// The following subclasses of [InlineSpan] may be used to build rich text:
375 | ///
376 | /// * [TextSpan]s define text and children [InlineSpan]s.
377 | /// * [WidgetSpan]s define embedded inline widgets.
378 | ///
379 | /// The [textSpan] parameter must not be null.
380 | ///
381 | /// See [RichText] which provides a lower-level way to draw text.
382 | const Text.rich(
383 | this.textSpan, {
384 | Key key,
385 | this.style,
386 | this.strutStyle,
387 | this.textAlign,
388 | this.textDirection,
389 | this.locale,
390 | this.softWrap,
391 | this.overflow,
392 | this.textScaleFactor,
393 | this.maxLines,
394 | this.semanticsLabel,
395 | this.textWidthBasis,
396 | this.textHeightBehavior,
397 | }) : assert(
398 | textSpan != null,
399 | 'A non-null TextSpan must be provided to a Text.rich widget.',
400 | ),
401 | data = null,
402 | super(key: key);
403 |
404 | /// The text to display.
405 | ///
406 | /// This will be null if a [textSpan] is provided instead.
407 | final String data;
408 |
409 | /// The text to display as a [InlineSpan].
410 | ///
411 | /// This will be null if [data] is provided instead.
412 | final InlineSpan textSpan;
413 |
414 | /// If non-null, the style to use for this text.
415 | ///
416 | /// If the style's "inherit" property is true, the style will be merged with
417 | /// the closest enclosing [DefaultTextStyle]. Otherwise, the style will
418 | /// replace the closest enclosing [DefaultTextStyle].
419 | final TextStyle style;
420 |
421 | /// {@macro flutter.painting.textPainter.strutStyle}
422 | final StrutStyle strutStyle;
423 |
424 | /// How the text should be aligned horizontally.
425 | final TextAlign textAlign;
426 |
427 | /// The directionality of the text.
428 | ///
429 | /// This decides how [textAlign] values like [TextAlign.start] and
430 | /// [TextAlign.end] are interpreted.
431 | ///
432 | /// This is also used to disambiguate how to render bidirectional text. For
433 | /// example, if the [data] is an English phrase followed by a Hebrew phrase,
434 | /// in a [TextDirection.ltr] context the English phrase will be on the left
435 | /// and the Hebrew phrase to its right, while in a [TextDirection.rtl]
436 | /// context, the English phrase will be on the right and the Hebrew phrase on
437 | /// its left.
438 | ///
439 | /// Defaults to the ambient [Directionality], if any.
440 | final TextDirection textDirection;
441 |
442 | /// Used to select a font when the same Unicode character can
443 | /// be rendered differently, depending on the locale.
444 | ///
445 | /// It's rarely necessary to set this property. By default its value
446 | /// is inherited from the enclosing app with `Localizations.localeOf(context)`.
447 | ///
448 | /// See [RenderParagraph.locale] for more information.
449 | final Locale locale;
450 |
451 | /// Whether the text should break at soft line breaks.
452 | ///
453 | /// If false, the glyphs in the text will be positioned as if there was unlimited horizontal space.
454 | final bool softWrap;
455 |
456 | /// How visual overflow should be handled.
457 | ///
458 | /// Defaults to retrieving the value from the nearest [DefaultTextStyle] ancestor.
459 | final TextOverflow overflow;
460 |
461 | /// The number of font pixels for each logical pixel.
462 | ///
463 | /// For example, if the text scale factor is 1.5, text will be 50% larger than
464 | /// the specified font size.
465 | ///
466 | /// The value given to the constructor as textScaleFactor. If null, will
467 | /// use the [MediaQueryData.textScaleFactor] obtained from the ambient
468 | /// [MediaQuery], or 1.0 if there is no [MediaQuery] in scope.
469 | final double textScaleFactor;
470 |
471 | /// An optional maximum number of lines for the text to span, wrapping if necessary.
472 | /// If the text exceeds the given number of lines, it will be truncated according
473 | /// to [overflow].
474 | ///
475 | /// If this is 1, text will not wrap. Otherwise, text will be wrapped at the
476 | /// edge of the box.
477 | ///
478 | /// If this is null, but there is an ambient [DefaultTextStyle] that specifies
479 | /// an explicit number for its [DefaultTextStyle.maxLines], then the
480 | /// [DefaultTextStyle] value will take precedence. You can use a [RichText]
481 | /// widget directly to entirely override the [DefaultTextStyle].
482 | final int maxLines;
483 |
484 | /// An alternative semantics label for this text.
485 | ///
486 | /// If present, the semantics of this widget will contain this value instead
487 | /// of the actual text. This will overwrite any of the semantics labels applied
488 | /// directly to the [TextSpan]s.
489 | ///
490 | /// This is useful for replacing abbreviations or shorthands with the full
491 | /// text value:
492 | ///
493 | /// ```dart
494 | /// Text(r'$$', semanticsLabel: 'Double dollars')
495 | /// ```
496 | final String semanticsLabel;
497 |
498 | /// {@macro flutter.painting.textPainter.textWidthBasis}
499 | final TextWidthBasis textWidthBasis;
500 |
501 | /// {@macro flutter.dart:ui.textHeightBehavior}
502 | final ui.TextHeightBehavior textHeightBehavior;
503 |
504 | @override
505 | Widget build(BuildContext context) {
506 | final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);
507 | TextStyle effectiveTextStyle = style;
508 | if (style == null || style.inherit)
509 | effectiveTextStyle = defaultTextStyle.style.merge(style);
510 | if (MediaQuery.boldTextOverride(context))
511 | effectiveTextStyle = effectiveTextStyle.merge(const TextStyle(fontWeight: FontWeight.bold));
512 | Widget result = RichText(
513 | textAlign: textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start,
514 | textDirection: textDirection, // RichText uses Directionality.of to obtain a default if this is null.
515 | locale: locale, // RichText uses Localizations.localeOf to obtain a default if this is null
516 | softWrap: softWrap ?? defaultTextStyle.softWrap,
517 | overflow: overflow ?? defaultTextStyle.overflow,
518 | textScaleFactor: textScaleFactor ?? 1,
519 | maxLines: maxLines ?? defaultTextStyle.maxLines,
520 | strutStyle: strutStyle,
521 | textWidthBasis: textWidthBasis ?? defaultTextStyle.textWidthBasis,
522 | textHeightBehavior: textHeightBehavior ?? defaultTextStyle.textHeightBehavior ?? DefaultTextHeightBehavior.of(context),
523 | text: TextSpan(
524 | style: effectiveTextStyle,
525 | text: data,
526 | children: textSpan != null ? [textSpan] : null,
527 | ),
528 | );
529 | if (semanticsLabel != null) {
530 | result = Semantics(
531 | textDirection: textDirection,
532 | label: semanticsLabel,
533 | child: ExcludeSemantics(
534 | child: result,
535 | ),
536 | );
537 | }
538 | return result;
539 | }
540 |
541 | @override
542 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
543 | super.debugFillProperties(properties);
544 | properties.add(StringProperty('data', data, showName: false));
545 | if (textSpan != null) {
546 | properties.add(textSpan.toDiagnosticsNode(name: 'textSpan', style: DiagnosticsTreeStyle.transition));
547 | }
548 | style?.debugFillProperties(properties);
549 | properties.add(EnumProperty('textAlign', textAlign, defaultValue: null));
550 | properties.add(EnumProperty('textDirection', textDirection, defaultValue: null));
551 | properties.add(DiagnosticsProperty('locale', locale, defaultValue: null));
552 | properties.add(FlagProperty('softWrap', value: softWrap, ifTrue: 'wrapping at box width', ifFalse: 'no wrapping except at line break characters', showName: true));
553 | properties.add(EnumProperty('overflow', overflow, defaultValue: null));
554 | properties.add(DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: null));
555 | properties.add(IntProperty('maxLines', maxLines, defaultValue: null));
556 | properties.add(EnumProperty('textWidthBasis', textWidthBasis, defaultValue: null));
557 | properties.add(DiagnosticsProperty('textHeightBehavior', textHeightBehavior, defaultValue: null));
558 | if (semanticsLabel != null) {
559 | properties.add(StringProperty('semanticsLabel', semanticsLabel));
560 | }
561 | }
562 | }
563 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 51;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 221A1473CB51FCB348029855 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EFF6A05ACAFA9E11C23EE9D /* Pods_Runner.framework */; };
12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
13 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
14 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
15 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
16 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXCopyFilesBuildPhase section */
20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
21 | isa = PBXCopyFilesBuildPhase;
22 | buildActionMask = 2147483647;
23 | dstPath = "";
24 | dstSubfolderSpec = 10;
25 | files = (
26 | );
27 | name = "Embed Frameworks";
28 | runOnlyForDeploymentPostprocessing = 0;
29 | };
30 | /* End PBXCopyFilesBuildPhase section */
31 |
32 | /* Begin PBXFileReference section */
33 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
34 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
35 | 1EFF6A05ACAFA9E11C23EE9D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
36 | 2B029A4094A056E628E857C8 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
37 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
38 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
39 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
40 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
41 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
42 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
43 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
44 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
45 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
46 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
47 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
48 | D1A700314C3A9FC91CA54CE9 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
49 | EE3DD467847E5C1633BA369A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
50 | /* End PBXFileReference section */
51 |
52 | /* Begin PBXFrameworksBuildPhase section */
53 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
54 | isa = PBXFrameworksBuildPhase;
55 | buildActionMask = 2147483647;
56 | files = (
57 | 221A1473CB51FCB348029855 /* Pods_Runner.framework in Frameworks */,
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | /* End PBXFrameworksBuildPhase section */
62 |
63 | /* Begin PBXGroup section */
64 | 3276DCCFAC90F5C55343B482 /* Pods */ = {
65 | isa = PBXGroup;
66 | children = (
67 | 2B029A4094A056E628E857C8 /* Pods-Runner.debug.xcconfig */,
68 | D1A700314C3A9FC91CA54CE9 /* Pods-Runner.release.xcconfig */,
69 | EE3DD467847E5C1633BA369A /* Pods-Runner.profile.xcconfig */,
70 | );
71 | path = Pods;
72 | sourceTree = "";
73 | };
74 | 3E8E85268CD00DFA9C8F7ED0 /* Frameworks */ = {
75 | isa = PBXGroup;
76 | children = (
77 | 1EFF6A05ACAFA9E11C23EE9D /* Pods_Runner.framework */,
78 | );
79 | name = Frameworks;
80 | sourceTree = "";
81 | };
82 | 9740EEB11CF90186004384FC /* Flutter */ = {
83 | isa = PBXGroup;
84 | children = (
85 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
86 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
87 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
88 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
89 | );
90 | name = Flutter;
91 | sourceTree = "";
92 | };
93 | 97C146E51CF9000F007C117D = {
94 | isa = PBXGroup;
95 | children = (
96 | 9740EEB11CF90186004384FC /* Flutter */,
97 | 97C146F01CF9000F007C117D /* Runner */,
98 | 97C146EF1CF9000F007C117D /* Products */,
99 | 3276DCCFAC90F5C55343B482 /* Pods */,
100 | 3E8E85268CD00DFA9C8F7ED0 /* Frameworks */,
101 | );
102 | sourceTree = "";
103 | };
104 | 97C146EF1CF9000F007C117D /* Products */ = {
105 | isa = PBXGroup;
106 | children = (
107 | 97C146EE1CF9000F007C117D /* Runner.app */,
108 | );
109 | name = Products;
110 | sourceTree = "";
111 | };
112 | 97C146F01CF9000F007C117D /* Runner */ = {
113 | isa = PBXGroup;
114 | children = (
115 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
116 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
117 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
118 | 97C147021CF9000F007C117D /* Info.plist */,
119 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
120 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
121 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
122 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
123 | );
124 | path = Runner;
125 | sourceTree = "";
126 | };
127 | /* End PBXGroup section */
128 |
129 | /* Begin PBXNativeTarget section */
130 | 97C146ED1CF9000F007C117D /* Runner */ = {
131 | isa = PBXNativeTarget;
132 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
133 | buildPhases = (
134 | BE8400CF301FAB326F8C763F /* [CP] Check Pods Manifest.lock */,
135 | 9740EEB61CF901F6004384FC /* Run Script */,
136 | 97C146EA1CF9000F007C117D /* Sources */,
137 | 97C146EB1CF9000F007C117D /* Frameworks */,
138 | 97C146EC1CF9000F007C117D /* Resources */,
139 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
140 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
141 | 79AB272CFF2AB432E4EA8228 /* [CP] Embed Pods Frameworks */,
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 = 1020;
159 | ORGANIZATIONNAME = "";
160 | TargetAttributes = {
161 | 97C146ED1CF9000F007C117D = {
162 | CreatedOnToolsVersion = 7.3.1;
163 | LastSwiftMigration = 1100;
164 | };
165 | };
166 | };
167 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
168 | compatibilityVersion = "Xcode 9.3";
169 | developmentRegion = en;
170 | hasScannedForEncodings = 0;
171 | knownRegions = (
172 | en,
173 | Base,
174 | );
175 | mainGroup = 97C146E51CF9000F007C117D;
176 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
177 | projectDirPath = "";
178 | projectRoot = "";
179 | targets = (
180 | 97C146ED1CF9000F007C117D /* Runner */,
181 | );
182 | };
183 | /* End PBXProject section */
184 |
185 | /* Begin PBXResourcesBuildPhase section */
186 | 97C146EC1CF9000F007C117D /* Resources */ = {
187 | isa = PBXResourcesBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
191 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
192 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
193 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
194 | );
195 | runOnlyForDeploymentPostprocessing = 0;
196 | };
197 | /* End PBXResourcesBuildPhase section */
198 |
199 | /* Begin PBXShellScriptBuildPhase section */
200 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
201 | isa = PBXShellScriptBuildPhase;
202 | buildActionMask = 2147483647;
203 | files = (
204 | );
205 | inputPaths = (
206 | );
207 | name = "Thin Binary";
208 | outputPaths = (
209 | );
210 | runOnlyForDeploymentPostprocessing = 0;
211 | shellPath = /bin/sh;
212 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
213 | };
214 | 79AB272CFF2AB432E4EA8228 /* [CP] Embed Pods Frameworks */ = {
215 | isa = PBXShellScriptBuildPhase;
216 | buildActionMask = 2147483647;
217 | files = (
218 | );
219 | inputFileListPaths = (
220 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
221 | );
222 | name = "[CP] Embed Pods Frameworks";
223 | outputFileListPaths = (
224 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
225 | );
226 | runOnlyForDeploymentPostprocessing = 0;
227 | shellPath = /bin/sh;
228 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
229 | showEnvVarsInLog = 0;
230 | };
231 | 9740EEB61CF901F6004384FC /* Run Script */ = {
232 | isa = PBXShellScriptBuildPhase;
233 | buildActionMask = 2147483647;
234 | files = (
235 | );
236 | inputPaths = (
237 | );
238 | name = "Run Script";
239 | outputPaths = (
240 | );
241 | runOnlyForDeploymentPostprocessing = 0;
242 | shellPath = /bin/sh;
243 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
244 | };
245 | BE8400CF301FAB326F8C763F /* [CP] Check Pods Manifest.lock */ = {
246 | isa = PBXShellScriptBuildPhase;
247 | buildActionMask = 2147483647;
248 | files = (
249 | );
250 | inputFileListPaths = (
251 | );
252 | inputPaths = (
253 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
254 | "${PODS_ROOT}/Manifest.lock",
255 | );
256 | name = "[CP] Check Pods Manifest.lock";
257 | outputFileListPaths = (
258 | );
259 | outputPaths = (
260 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
261 | );
262 | runOnlyForDeploymentPostprocessing = 0;
263 | shellPath = /bin/sh;
264 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
265 | showEnvVarsInLog = 0;
266 | };
267 | /* End PBXShellScriptBuildPhase section */
268 |
269 | /* Begin PBXSourcesBuildPhase section */
270 | 97C146EA1CF9000F007C117D /* Sources */ = {
271 | isa = PBXSourcesBuildPhase;
272 | buildActionMask = 2147483647;
273 | files = (
274 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
275 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
276 | );
277 | runOnlyForDeploymentPostprocessing = 0;
278 | };
279 | /* End PBXSourcesBuildPhase section */
280 |
281 | /* Begin PBXVariantGroup section */
282 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
283 | isa = PBXVariantGroup;
284 | children = (
285 | 97C146FB1CF9000F007C117D /* Base */,
286 | );
287 | name = Main.storyboard;
288 | sourceTree = "";
289 | };
290 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
291 | isa = PBXVariantGroup;
292 | children = (
293 | 97C147001CF9000F007C117D /* Base */,
294 | );
295 | name = LaunchScreen.storyboard;
296 | sourceTree = "";
297 | };
298 | /* End PBXVariantGroup section */
299 |
300 | /* Begin XCBuildConfiguration section */
301 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
302 | isa = XCBuildConfiguration;
303 | buildSettings = {
304 | ALWAYS_SEARCH_USER_PATHS = NO;
305 | CLANG_ANALYZER_NONNULL = YES;
306 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
307 | CLANG_CXX_LIBRARY = "libc++";
308 | CLANG_ENABLE_MODULES = YES;
309 | CLANG_ENABLE_OBJC_ARC = YES;
310 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
311 | CLANG_WARN_BOOL_CONVERSION = YES;
312 | CLANG_WARN_COMMA = YES;
313 | CLANG_WARN_CONSTANT_CONVERSION = YES;
314 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
315 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
316 | CLANG_WARN_EMPTY_BODY = YES;
317 | CLANG_WARN_ENUM_CONVERSION = YES;
318 | CLANG_WARN_INFINITE_RECURSION = YES;
319 | CLANG_WARN_INT_CONVERSION = YES;
320 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
321 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
322 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
324 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
325 | CLANG_WARN_STRICT_PROTOTYPES = YES;
326 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
327 | CLANG_WARN_UNREACHABLE_CODE = YES;
328 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
329 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
330 | COPY_PHASE_STRIP = NO;
331 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
332 | ENABLE_NS_ASSERTIONS = NO;
333 | ENABLE_STRICT_OBJC_MSGSEND = YES;
334 | GCC_C_LANGUAGE_STANDARD = gnu99;
335 | GCC_NO_COMMON_BLOCKS = YES;
336 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
337 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
338 | GCC_WARN_UNDECLARED_SELECTOR = YES;
339 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
340 | GCC_WARN_UNUSED_FUNCTION = YES;
341 | GCC_WARN_UNUSED_VARIABLE = YES;
342 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
343 | MTL_ENABLE_DEBUG_INFO = NO;
344 | SDKROOT = iphoneos;
345 | SUPPORTED_PLATFORMS = iphoneos;
346 | TARGETED_DEVICE_FAMILY = "1,2";
347 | VALIDATE_PRODUCT = YES;
348 | };
349 | name = Profile;
350 | };
351 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
352 | isa = XCBuildConfiguration;
353 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
354 | buildSettings = {
355 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
356 | CLANG_ENABLE_MODULES = YES;
357 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
358 | DEVELOPMENT_TEAM = F5CHD3X2FV;
359 | ENABLE_BITCODE = NO;
360 | FRAMEWORK_SEARCH_PATHS = (
361 | "$(inherited)",
362 | "$(PROJECT_DIR)/Flutter",
363 | );
364 | INFOPLIST_FILE = Runner/Info.plist;
365 | LD_RUNPATH_SEARCH_PATHS = (
366 | "$(inherited)",
367 | "@executable_path/Frameworks",
368 | );
369 | LIBRARY_SEARCH_PATHS = (
370 | "$(inherited)",
371 | "$(PROJECT_DIR)/Flutter",
372 | );
373 | PRODUCT_BUNDLE_IDENTIFIER = com.ClubHouseClone;
374 | PRODUCT_NAME = "$(TARGET_NAME)";
375 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
376 | SWIFT_VERSION = 5.0;
377 | VERSIONING_SYSTEM = "apple-generic";
378 | };
379 | name = Profile;
380 | };
381 | 97C147031CF9000F007C117D /* Debug */ = {
382 | isa = XCBuildConfiguration;
383 | buildSettings = {
384 | ALWAYS_SEARCH_USER_PATHS = NO;
385 | CLANG_ANALYZER_NONNULL = YES;
386 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
387 | CLANG_CXX_LIBRARY = "libc++";
388 | CLANG_ENABLE_MODULES = YES;
389 | CLANG_ENABLE_OBJC_ARC = YES;
390 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
391 | CLANG_WARN_BOOL_CONVERSION = YES;
392 | CLANG_WARN_COMMA = YES;
393 | CLANG_WARN_CONSTANT_CONVERSION = YES;
394 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
395 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
396 | CLANG_WARN_EMPTY_BODY = YES;
397 | CLANG_WARN_ENUM_CONVERSION = YES;
398 | CLANG_WARN_INFINITE_RECURSION = YES;
399 | CLANG_WARN_INT_CONVERSION = YES;
400 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
401 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
402 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
403 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
404 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
405 | CLANG_WARN_STRICT_PROTOTYPES = YES;
406 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
407 | CLANG_WARN_UNREACHABLE_CODE = YES;
408 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
409 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
410 | COPY_PHASE_STRIP = NO;
411 | DEBUG_INFORMATION_FORMAT = dwarf;
412 | ENABLE_STRICT_OBJC_MSGSEND = YES;
413 | ENABLE_TESTABILITY = YES;
414 | GCC_C_LANGUAGE_STANDARD = gnu99;
415 | GCC_DYNAMIC_NO_PIC = NO;
416 | GCC_NO_COMMON_BLOCKS = YES;
417 | GCC_OPTIMIZATION_LEVEL = 0;
418 | GCC_PREPROCESSOR_DEFINITIONS = (
419 | "DEBUG=1",
420 | "$(inherited)",
421 | );
422 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
423 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
424 | GCC_WARN_UNDECLARED_SELECTOR = YES;
425 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
426 | GCC_WARN_UNUSED_FUNCTION = YES;
427 | GCC_WARN_UNUSED_VARIABLE = YES;
428 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
429 | MTL_ENABLE_DEBUG_INFO = YES;
430 | ONLY_ACTIVE_ARCH = YES;
431 | SDKROOT = iphoneos;
432 | TARGETED_DEVICE_FAMILY = "1,2";
433 | };
434 | name = Debug;
435 | };
436 | 97C147041CF9000F007C117D /* Release */ = {
437 | isa = XCBuildConfiguration;
438 | buildSettings = {
439 | ALWAYS_SEARCH_USER_PATHS = NO;
440 | CLANG_ANALYZER_NONNULL = YES;
441 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
442 | CLANG_CXX_LIBRARY = "libc++";
443 | CLANG_ENABLE_MODULES = YES;
444 | CLANG_ENABLE_OBJC_ARC = YES;
445 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
446 | CLANG_WARN_BOOL_CONVERSION = YES;
447 | CLANG_WARN_COMMA = YES;
448 | CLANG_WARN_CONSTANT_CONVERSION = YES;
449 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
450 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
451 | CLANG_WARN_EMPTY_BODY = YES;
452 | CLANG_WARN_ENUM_CONVERSION = YES;
453 | CLANG_WARN_INFINITE_RECURSION = YES;
454 | CLANG_WARN_INT_CONVERSION = YES;
455 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
456 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
457 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
458 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
459 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
460 | CLANG_WARN_STRICT_PROTOTYPES = YES;
461 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
462 | CLANG_WARN_UNREACHABLE_CODE = YES;
463 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
464 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
465 | COPY_PHASE_STRIP = NO;
466 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
467 | ENABLE_NS_ASSERTIONS = NO;
468 | ENABLE_STRICT_OBJC_MSGSEND = YES;
469 | GCC_C_LANGUAGE_STANDARD = gnu99;
470 | GCC_NO_COMMON_BLOCKS = YES;
471 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
472 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
473 | GCC_WARN_UNDECLARED_SELECTOR = YES;
474 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
475 | GCC_WARN_UNUSED_FUNCTION = YES;
476 | GCC_WARN_UNUSED_VARIABLE = YES;
477 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
478 | MTL_ENABLE_DEBUG_INFO = NO;
479 | SDKROOT = iphoneos;
480 | SUPPORTED_PLATFORMS = iphoneos;
481 | SWIFT_COMPILATION_MODE = wholemodule;
482 | SWIFT_OPTIMIZATION_LEVEL = "-O";
483 | TARGETED_DEVICE_FAMILY = "1,2";
484 | VALIDATE_PRODUCT = YES;
485 | };
486 | name = Release;
487 | };
488 | 97C147061CF9000F007C117D /* Debug */ = {
489 | isa = XCBuildConfiguration;
490 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
491 | buildSettings = {
492 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
493 | CLANG_ENABLE_MODULES = YES;
494 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
495 | DEVELOPMENT_TEAM = F5CHD3X2FV;
496 | ENABLE_BITCODE = NO;
497 | FRAMEWORK_SEARCH_PATHS = (
498 | "$(inherited)",
499 | "$(PROJECT_DIR)/Flutter",
500 | );
501 | INFOPLIST_FILE = Runner/Info.plist;
502 | LD_RUNPATH_SEARCH_PATHS = (
503 | "$(inherited)",
504 | "@executable_path/Frameworks",
505 | );
506 | LIBRARY_SEARCH_PATHS = (
507 | "$(inherited)",
508 | "$(PROJECT_DIR)/Flutter",
509 | );
510 | PRODUCT_BUNDLE_IDENTIFIER = com.ClubHouseClone;
511 | PRODUCT_NAME = "$(TARGET_NAME)";
512 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
513 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
514 | SWIFT_VERSION = 5.0;
515 | VERSIONING_SYSTEM = "apple-generic";
516 | };
517 | name = Debug;
518 | };
519 | 97C147071CF9000F007C117D /* Release */ = {
520 | isa = XCBuildConfiguration;
521 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
522 | buildSettings = {
523 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
524 | CLANG_ENABLE_MODULES = YES;
525 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
526 | DEVELOPMENT_TEAM = F5CHD3X2FV;
527 | ENABLE_BITCODE = NO;
528 | FRAMEWORK_SEARCH_PATHS = (
529 | "$(inherited)",
530 | "$(PROJECT_DIR)/Flutter",
531 | );
532 | INFOPLIST_FILE = Runner/Info.plist;
533 | LD_RUNPATH_SEARCH_PATHS = (
534 | "$(inherited)",
535 | "@executable_path/Frameworks",
536 | );
537 | LIBRARY_SEARCH_PATHS = (
538 | "$(inherited)",
539 | "$(PROJECT_DIR)/Flutter",
540 | );
541 | PRODUCT_BUNDLE_IDENTIFIER = com.ClubHouseClone;
542 | PRODUCT_NAME = "$(TARGET_NAME)";
543 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
544 | SWIFT_VERSION = 5.0;
545 | VERSIONING_SYSTEM = "apple-generic";
546 | };
547 | name = Release;
548 | };
549 | /* End XCBuildConfiguration section */
550 |
551 | /* Begin XCConfigurationList section */
552 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
553 | isa = XCConfigurationList;
554 | buildConfigurations = (
555 | 97C147031CF9000F007C117D /* Debug */,
556 | 97C147041CF9000F007C117D /* Release */,
557 | 249021D3217E4FDB00AE95B9 /* Profile */,
558 | );
559 | defaultConfigurationIsVisible = 0;
560 | defaultConfigurationName = Release;
561 | };
562 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
563 | isa = XCConfigurationList;
564 | buildConfigurations = (
565 | 97C147061CF9000F007C117D /* Debug */,
566 | 97C147071CF9000F007C117D /* Release */,
567 | 249021D4217E4FDB00AE95B9 /* Profile */,
568 | );
569 | defaultConfigurationIsVisible = 0;
570 | defaultConfigurationName = Release;
571 | };
572 | /* End XCConfigurationList section */
573 | };
574 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
575 | }
576 |
--------------------------------------------------------------------------------
/lib/screen/home_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:ClubHouseClone/app/locator.dart';
2 | import 'package:ClubHouseClone/app/navigation_service.dart';
3 | import 'package:ClubHouseClone/app/route_names.dart';
4 | import 'package:ClubHouseClone/model/topic_model.dart';
5 | import 'package:ClubHouseClone/share/grid_icon.dart';
6 | import 'package:ClubHouseClone/share/icon_add.dart';
7 | import 'package:ClubHouseClone/share/nav_bar.dart' as nav_bar;
8 | import 'package:ClubHouseClone/share/shared_style.dart';
9 | import 'package:ClubHouseClone/share/snapping_scroll_physics.dart';
10 | import 'package:cached_network_image/cached_network_image.dart';
11 | import 'package:flutter/cupertino.dart';
12 | import 'package:flutter/material.dart';
13 | import 'package:flutter/rendering.dart';
14 | import 'package:flutter_emoji/flutter_emoji.dart';
15 | import 'package:visibility_detector/visibility_detector.dart';
16 |
17 | class HomeView extends StatefulWidget {
18 | const HomeView({
19 | Key key,
20 | }) : super(key: key);
21 |
22 | @override
23 | State createState() {
24 | return _HomeViewState();
25 | }
26 | }
27 |
28 | class _HomeViewState extends State with WidgetsBindingObserver {
29 | NavigationService _navigationService = locator();
30 | ScrollController _scrollController = ScrollController(initialScrollOffset: 0);
31 | bool showGridIcon = true;
32 |
33 | List topicData;
34 | GlobalKey gridIconKey = GlobalKey();
35 |
36 | @override
37 | void initState() {
38 | super.initState();
39 | _scrollController.addListener(_listener);
40 | topicData = TopicModelData().topicData;
41 | }
42 |
43 | _listener() {
44 | if (_scrollController.offset >
45 | _scrollController.position.maxScrollExtent + 100) {
46 | _scrollController.animateTo(0,
47 | duration: Duration(milliseconds: 100), curve: Curves.ease);
48 | }
49 | }
50 |
51 | @override
52 | void dispose() {
53 | super.dispose();
54 | }
55 |
56 | @override
57 | void didChangeAppLifecycleState(AppLifecycleState state) {
58 | print('state = $state');
59 | }
60 |
61 | @override
62 | Widget build(BuildContext context) {
63 | return CupertinoPageScaffold(
64 | backgroundColor: themeColor,
65 | navigationBar: nav_bar.CupertinoNavigationBar(
66 | border: null,
67 | backgroundColor: themeColor,
68 | leading: GestureDetector(
69 | onTap: () {
70 | _navigationService.navigateTo(SearchViewRoute);
71 | },
72 | child: Icon(
73 | CupertinoIcons.search,
74 | color: CupertinoColors.black,
75 | ),
76 | ),
77 | trailing: Row(
78 | mainAxisAlignment: MainAxisAlignment.end,
79 | crossAxisAlignment: CrossAxisAlignment.center,
80 | children: [
81 | Padding(
82 | padding: EdgeInsets.symmetric(
83 | horizontal: 15,
84 | ),
85 | child: GestureDetector(
86 | onTap: () => _navigationService.navigateTo(SearchViewRoute),
87 | child: Icon(
88 | CupertinoIcons.mail,
89 | color: CupertinoColors.black,
90 | ),
91 | ),
92 | ),
93 | Padding(
94 | padding: EdgeInsets.symmetric(
95 | horizontal: 15,
96 | ),
97 | child: GestureDetector(
98 | onTap: () => _navigationService.navigateTo(SearchViewRoute),
99 | child: Icon(
100 | CupertinoIcons.calendar_today,
101 | color: CupertinoColors.black,
102 | ),
103 | ),
104 | ),
105 | Padding(
106 | padding: EdgeInsets.symmetric(
107 | horizontal: 15,
108 | ),
109 | child: GestureDetector(
110 | onTap: () => _navigationService.navigateTo(SearchViewRoute),
111 | child: Icon(
112 | CupertinoIcons.bell,
113 | color: CupertinoColors.black,
114 | ),
115 | ),
116 | ),
117 | Padding(
118 | padding: EdgeInsets.symmetric(
119 | horizontal: 15,
120 | ),
121 | child: GestureDetector(
122 | onTap: () => _navigationService.navigateTo(SearchViewRoute),
123 | child: Container(
124 | height: 32,
125 | width: 33,
126 | decoration: BoxDecoration(
127 | borderRadius: BorderRadius.circular(12),
128 | ),
129 | clipBehavior: Clip.hardEdge,
130 | child: CachedNetworkImage(
131 | imageUrl:
132 | "https://images.pexels.com/photos/2078265/pexels-photo-2078265.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
133 | fit: BoxFit.cover,
134 | ),
135 | ),
136 | ),
137 | ),
138 | ],
139 | ),
140 | ),
141 | child: ListView(
142 | shrinkWrap: false,
143 | scrollDirection: Axis.horizontal,
144 | controller: _scrollController,
145 | physics: SnappingScrollPhysics(
146 | itemExtent: MediaQuery.of(context).size.width / 1.3,
147 | ),
148 | children: [
149 | _mainView(),
150 | _slideView(),
151 | ],
152 | ),
153 | );
154 | }
155 |
156 | Widget _buildTitle() {
157 | return GestureDetector(
158 | onTap: () => _navigationService.navigateTo(SearchViewRoute),
159 | child: Container(
160 | color: themeColor,
161 | child: Column(
162 | children: [
163 | SizedBox(
164 | height: 25,
165 | ),
166 | Container(
167 | alignment: Alignment.center,
168 | child: Text(
169 | "Clubhouse is full of interesting people! \n Try following at least 25.",
170 | textAlign: TextAlign.center,
171 | textScaleFactor: 1,
172 | style: TextStyle(
173 | color: black,
174 | fontWeight: FontWeight.bold,
175 | // fontSize: 12,
176 | ),
177 | ),
178 | ),
179 | SizedBox(
180 | height: 10,
181 | ),
182 | Container(
183 | height: 115,
184 | width: double.infinity,
185 | alignment: Alignment.center,
186 | child: Container(
187 | width: 260,
188 | child: Stack(
189 | children: [
190 | Positioned.fill(
191 | child: Align(
192 | alignment: Alignment.center,
193 | child: Stack(
194 | children: [
195 | Positioned(
196 | left: 30,
197 | top: 0,
198 | child: IconAdd(
199 | size: 38,
200 | imageUrl:
201 | "https://images.pexels.com/photos/415829/pexels-photo-415829.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260",
202 | ),
203 | ),
204 | Positioned(
205 | left: 5,
206 | top: 35,
207 | child: IconAdd(
208 | size: 25,
209 | imageUrl:
210 | "https://images.pexels.com/photos/2078265/pexels-photo-2078265.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
211 | ),
212 | ),
213 | Positioned(
214 | left: 80,
215 | top: 0,
216 | child: IconAdd(
217 | size: 49,
218 | imageUrl:
219 | "https://images.pexels.com/photos/1310522/pexels-photo-1310522.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260"),
220 | ),
221 | Positioned(
222 | left: 50,
223 | top: 45,
224 | child: IconAdd(
225 | size: 38,
226 | imageUrl:
227 | "https://images.pexels.com/photos/1043471/pexels-photo-1043471.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
228 | ),
229 | ),
230 | Positioned(
231 | left: 120,
232 | top: 25,
233 | child: IconAdd(
234 | size: 60,
235 | imageUrl:
236 | "https://images.pexels.com/photos/1382731/pexels-photo-1382731.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
237 | ),
238 | ),
239 | Positioned(
240 | left: 175,
241 | top: 0,
242 | child: IconAdd(
243 | size: 35,
244 | imageUrl:
245 | "https://images.pexels.com/photos/697509/pexels-photo-697509.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
246 | ),
247 | ),
248 | Positioned(
249 | left: 200,
250 | top: 35,
251 | child: IconAdd(
252 | size: 35,
253 | imageUrl:
254 | "https://images.pexels.com/photos/943084/pexels-photo-943084.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
255 | ),
256 | ),
257 | Positioned(
258 | left: 220,
259 | top: 10,
260 | child: IconAdd(
261 | size: 22,
262 | imageUrl:
263 | "https://images.pexels.com/photos/1222271/pexels-photo-1222271.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
264 | ),
265 | ),
266 | ],
267 | ),
268 | ),
269 | )
270 | ],
271 | ),
272 | ),
273 | ),
274 | Container(
275 | margin: EdgeInsets.symmetric(horizontal: 80),
276 | child: CupertinoButton(
277 | padding: EdgeInsets.symmetric(horizontal: 20, vertical: 0),
278 | borderRadius: BorderRadius.circular(20),
279 | minSize: 30,
280 | color: brown.withOpacity(0.1),
281 | child: Row(
282 | mainAxisAlignment: MainAxisAlignment.center,
283 | children: [
284 | Icon(
285 | CupertinoIcons.person_crop_circle_badge_plus,
286 | color: brown,
287 | size: 15,
288 | ),
289 | SizedBox(
290 | width: 5,
291 | ),
292 | Text(
293 | "Find more people to follow",
294 | textScaleFactor: 1,
295 | style: TextStyle(
296 | color: brown,
297 | fontWeight: FontWeight.bold,
298 | ),
299 | ),
300 | ],
301 | ),
302 | onPressed: () => _navigationService.navigateTo(SearchViewRoute),
303 | ),
304 | ),
305 | SizedBox(
306 | height: 45,
307 | ),
308 | ],
309 | ),
310 | ),
311 | );
312 | }
313 |
314 | Widget _slideView() {
315 | return Container(
316 | color: themeColor,
317 | alignment: Alignment.center,
318 | width: MediaQuery.of(context).size.width / 1.3,
319 | child: Column(
320 | mainAxisSize: MainAxisSize.min,
321 | mainAxisAlignment: MainAxisAlignment.center,
322 | children: [
323 | Text(
324 | "No one you follow is online",
325 | textScaleFactor: 1,
326 | style: TextStyle(
327 | fontWeight: FontWeight.bold,
328 | ),
329 | ),
330 | Container(
331 | child: CupertinoButton(
332 | color: brown.withOpacity(0.1),
333 | borderRadius: BorderRadius.circular(20),
334 | padding: EdgeInsets.symmetric(horizontal: 20, vertical: 0),
335 | minSize: 30,
336 | child: Text(
337 | "Find people to follow",
338 | textScaleFactor: 1,
339 | style: TextStyle(
340 | color: brown,
341 | fontWeight: FontWeight.bold,
342 | ),
343 | ),
344 | onPressed: () => _navigationService.navigateTo(SearchViewRoute),
345 | ),
346 | ),
347 | ],
348 | ),
349 | );
350 | }
351 |
352 | Widget _mainView() {
353 | return VisibilityDetector(
354 | key: Key("main_page"),
355 | onVisibilityChanged: (VisibilityInfo info) {
356 | if (gridIconKey.currentState != null) {
357 | if (info.visibleFraction == 1) {
358 | gridIconKey.currentState.changeState(true);
359 | } else {
360 | gridIconKey.currentState.changeState(false);
361 | }
362 | }
363 | },
364 | child: Container(
365 | width: MediaQuery.of(context).size.width,
366 | child: Stack(
367 | children: [
368 | CustomScrollView(
369 | slivers: [
370 | SliverToBoxAdapter(
371 | child: _buildTitle(),
372 | ),
373 | SliverList(
374 | delegate: SliverChildBuilderDelegate(
375 | (BuildContext context, int index) {
376 | return Container(
377 | width: double.infinity,
378 | decoration: BoxDecoration(
379 | color: white,
380 | borderRadius: BorderRadius.circular(20),
381 | boxShadow: [
382 | BoxShadow(
383 | color: brown.withOpacity(0.2),
384 | spreadRadius: 0.1,
385 | blurRadius: 0.2,
386 | offset: Offset(0, 1),
387 | )
388 | ],
389 | ),
390 | margin:
391 | EdgeInsets.only(left: 16, right: 16, bottom: 16),
392 | padding: EdgeInsets.all(20),
393 | child: Column(
394 | mainAxisSize: MainAxisSize.min,
395 | mainAxisAlignment: MainAxisAlignment.start,
396 | crossAxisAlignment: CrossAxisAlignment.start,
397 | children: [
398 | topicData[index].clubName != null
399 | ? Text(
400 | topicData[index].clubName.toUpperCase() +
401 | " ${EmojiParser().get("house").code}",
402 | textScaleFactor: 1,
403 | style: TextStyle(
404 | fontWeight: FontWeight.w600,
405 | ),
406 | )
407 | : Container(),
408 | Text(
409 | topicData[index].topicTitle,
410 | textScaleFactor: 1,
411 | maxLines: 2,
412 | overflow: TextOverflow.ellipsis,
413 | style: TextStyle(
414 | fontSize: 16,
415 | fontWeight: FontWeight.bold,
416 | ),
417 | ),
418 | Container(
419 | child: Row(
420 | children: [
421 | Container(
422 | height: 70,
423 | width: 100,
424 | child: Stack(
425 | children: [
426 | Container(
427 | height: 45,
428 | width: 45,
429 | decoration: BoxDecoration(
430 | borderRadius:
431 | BorderRadius.circular(20),
432 | ),
433 | clipBehavior: Clip.hardEdge,
434 | child: CachedNetworkImage(
435 | imageUrl: topicData[index]
436 | .users[1]
437 | .userImage,
438 | fit: BoxFit.cover,
439 | ),
440 | ),
441 | Positioned(
442 | left: 30,
443 | top: 25,
444 | child: Container(
445 | height: 45,
446 | width: 45,
447 | decoration: BoxDecoration(
448 | borderRadius:
449 | BorderRadius.circular(20),
450 | ),
451 | clipBehavior: Clip.hardEdge,
452 | child: CachedNetworkImage(
453 | imageUrl: topicData[index]
454 | .users[0]
455 | .userImage,
456 | fit: BoxFit.cover,
457 | ),
458 | ),
459 | ),
460 | ],
461 | ),
462 | ),
463 | Expanded(
464 | child: Container(
465 | child: Column(
466 | crossAxisAlignment:
467 | CrossAxisAlignment.start,
468 | children: [
469 | ...List.generate(
470 | topicData[index].users.length, (i) {
471 | return Text(
472 | topicData[index].users[i].userName +
473 | " ${EmojiParser().get("speech_balloon").code}",
474 | textScaleFactor: 1,
475 | style: TextStyle(
476 | fontWeight: FontWeight.w600,
477 | fontSize: 18),
478 | );
479 | }),
480 | SizedBox(
481 | height: 5,
482 | ),
483 | Row(
484 | children: [
485 | Text(
486 | "${topicData[index].audienceNumber} ",
487 | textScaleFactor: 1,
488 | style: TextStyle(fontSize: 10),
489 | ),
490 | Icon(
491 | Icons.person,
492 | color: brown,
493 | size: 12,
494 | ),
495 | Text(
496 | " / ",
497 | textScaleFactor: 1,
498 | style: TextStyle(fontSize: 11),
499 | ),
500 | Text(
501 | "${topicData[index].speechNumber} ",
502 | textScaleFactor: 1,
503 | style: TextStyle(fontSize: 10),
504 | ),
505 | Icon(
506 | CupertinoIcons.chat_bubble_text,
507 | color: brown,
508 | size: 12,
509 | ),
510 | ],
511 | ),
512 | ],
513 | ),
514 | )),
515 | ],
516 | ),
517 | ),
518 | ],
519 | ),
520 | );
521 | },
522 | childCount: topicData.length,
523 | ),
524 | ),
525 | SliverToBoxAdapter(
526 | child: _explore(),
527 | ),
528 | ],
529 | ),
530 | Positioned(
531 | bottom: 0,
532 | left: 0,
533 | right: 0,
534 | height: 100,
535 | child: _bottomView(),
536 | ),
537 | ],
538 | ),
539 | ),
540 | );
541 | }
542 |
543 | Widget _explore() {
544 | return Column(
545 | children: [
546 | Container(
547 | width: 150,
548 | padding: EdgeInsets.symmetric(horizontal: 15),
549 | child: CupertinoButton(
550 | borderRadius: BorderRadius.circular(20),
551 | padding: EdgeInsets.symmetric(horizontal: 20),
552 | color: brown.withOpacity(0.1),
553 | child: Row(
554 | mainAxisAlignment: MainAxisAlignment.center,
555 | children: [
556 | Text(
557 | EmojiParser().get("earth_asia").code,
558 | textScaleFactor: 1,
559 | ),
560 | SizedBox(
561 | width: 5,
562 | ),
563 | Text(
564 | "Explore",
565 | textScaleFactor: 1,
566 | style: TextStyle(
567 | color: brown,
568 | fontWeight: FontWeight.bold,
569 | ),
570 | ),
571 | ],
572 | ),
573 | onPressed: () => _navigationService.navigateTo(SearchViewRoute),
574 | ),
575 | ),
576 | SizedBox(height: 150),
577 | ],
578 | );
579 | }
580 |
581 | Widget _bottomView() {
582 | return Container(
583 | alignment: Alignment.topCenter,
584 | child: Column(
585 | children: [
586 | Container(
587 | decoration: BoxDecoration(
588 | gradient: LinearGradient(
589 | colors: [themeColor.withOpacity(0.1), themeColor],
590 | begin: Alignment.topCenter,
591 | end: Alignment.bottomCenter),
592 | ),
593 | child: Row(
594 | mainAxisAlignment: MainAxisAlignment.spaceEvenly,
595 | children: [
596 | Expanded(
597 | flex: 1,
598 | child: SizedBox(),
599 | ),
600 | Expanded(
601 | flex: 2,
602 | child: Container(
603 | padding: EdgeInsets.symmetric(horizontal: 20),
604 | child: CupertinoButton(
605 | borderRadius: BorderRadius.circular(20),
606 | padding: EdgeInsets.symmetric(horizontal: 20),
607 | color: green,
608 | child: Row(
609 | mainAxisAlignment: MainAxisAlignment.center,
610 | children: [
611 | Icon(
612 | CupertinoIcons.plus,
613 | color: white,
614 | size: 18,
615 | ),
616 | SizedBox(
617 | width: 5,
618 | ),
619 | Text(
620 | "Start a room",
621 | textScaleFactor: 1,
622 | style: TextStyle(
623 | color: white,
624 | fontWeight: FontWeight.bold,
625 | ),
626 | ),
627 | ],
628 | ),
629 | onPressed: () =>
630 | _navigationService.navigateTo(SearchViewRoute),
631 | ),
632 | ),
633 | ),
634 | Expanded(
635 | flex: 1,
636 | child: GridIcon(
637 | key: gridIconKey,
638 | onTap: () {
639 | _scrollController.animateTo(
640 | _scrollController.position.maxScrollExtent,
641 | duration: Duration(milliseconds: 400),
642 | curve: Curves.ease,
643 | );
644 | },
645 | ),
646 | ),
647 | ],
648 | ),
649 | ),
650 | Expanded(
651 | child: Container(
652 | color: themeColor,
653 | ),
654 | ),
655 | ],
656 | ),
657 | );
658 | }
659 | }
660 |
--------------------------------------------------------------------------------
/lib/share/route.dart:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Flutter Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | // @dart = 2.8
6 |
7 | import 'dart:async';
8 | import 'dart:math';
9 | import 'dart:ui' show lerpDouble, ImageFilter;
10 |
11 | import 'package:flutter/cupertino.dart';
12 | import 'package:flutter/foundation.dart';
13 | import 'package:flutter/gestures.dart';
14 | import 'package:flutter/rendering.dart';
15 | import 'package:flutter/widgets.dart';
16 | import 'package:flutter/animation.dart' show Curves;
17 |
18 | const double _kBackGestureWidth = 20.0;
19 | const double _kMinFlingVelocity = 1.0; // Screen widths per second.
20 |
21 | // An eyeballed value for the maximum time it takes for a page to animate forward
22 | // if the user releases a page mid swipe.
23 | const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds.
24 |
25 | // The maximum time for a page to get reset to it's original position if the
26 | // user releases a page mid swipe.
27 | const int _kMaxPageBackAnimationTime = 300; // Milliseconds.
28 |
29 | // Barrier color for a Cupertino modal barrier.
30 | // Extracted from https://developer.apple.com/design/resources/.
31 | const Color _kModalBarrierColor = CupertinoDynamicColor.withBrightness(
32 | color: Color(0x33000000),
33 | darkColor: Color(0x7A000000),
34 | );
35 |
36 | // The duration of the transition used when a modal popup is shown.
37 | const Duration _kModalPopupTransitionDuration = Duration(milliseconds: 335);
38 |
39 | // Offset from offscreen to the right to fully on screen.
40 | final Animatable _kRightMiddleTween = Tween(
41 | begin: const Offset(1.0, 0.0),
42 | end: Offset.zero,
43 | );
44 |
45 | // Offset from fully on screen to 1/3 offscreen to the left.
46 | final Animatable _kMiddleLeftTween = Tween(
47 | begin: Offset.zero,
48 | end: const Offset(-1.0 / 3.0, 0.0),
49 | );
50 |
51 | // Offset from offscreen below to fully on screen.
52 | final Animatable _kBottomUpTween = Tween(
53 | begin: const Offset(0.0, 1.0),
54 | end: Offset.zero,
55 | );
56 |
57 | // Custom decoration from no shadow to page shadow mimicking iOS page
58 | // transitions using gradients.
59 | final DecorationTween _kGradientShadowTween = DecorationTween(
60 | begin: _CupertinoEdgeShadowDecoration.none, // No decoration initially.
61 | end: const _CupertinoEdgeShadowDecoration(
62 | edgeGradient: LinearGradient(
63 | // Spans 5% of the page.
64 | begin: AlignmentDirectional.centerStart,
65 | end: AlignmentDirectional.centerEnd,
66 | // Eyeballed gradient used to mimic a drop shadow on the start side only.
67 | colors: [
68 | Color(0x00000000),
69 | Color(0x04000000),
70 | Color(0x12000000),
71 | Color(0x38000000),
72 | ],
73 | stops: [0.0, 0.3, 0.6, 1.0],
74 | ),
75 | ),
76 | );
77 |
78 | /// A mixin that replaces the entire screen with an iOS transition for a
79 | /// [PageRoute].
80 | ///
81 | /// {@template flutter.cupertino.cupertinoRouteTransitionMixin}
82 | /// The page slides in from the right and exits in reverse. The page also shifts
83 | /// to the left in parallax when another page enters to cover it.
84 | ///
85 | /// The page slides in from the bottom and exits in reverse with no parallax
86 | /// effect for fullscreen dialogs.
87 | /// {@endtemplate}
88 | ///
89 | /// See also:
90 | ///
91 | /// * [MaterialRouteTransitionMixin], which is a mixin that provides
92 | /// platform-appropriate transitions for a [PageRoute]
93 | /// * [CupertinoPageRoute], which is a [PageRoute] that leverages this mixin.
94 | mixin CupertinoRouteTransitionMixin on PageRoute {
95 | /// Builds the primary contents of the route.
96 | @protected
97 | Widget buildContent(BuildContext context);
98 |
99 | /// {@template flutter.cupertino.cupertinoRouteTransitionMixin.title}
100 | /// A title string for this route.
101 | ///
102 | /// Used to auto-populate [CupertinoNavigationBar] and
103 | /// [CupertinoSliverNavigationBar]'s `middle`/`largeTitle` widgets when
104 | /// one is not manually supplied.
105 | /// {@endtemplate}
106 | String get title;
107 |
108 | ValueNotifier _previousTitle;
109 |
110 | /// The title string of the previous [CupertinoPageRoute].
111 | ///
112 | /// The [ValueListenable]'s value is readable after the route is installed
113 | /// onto a [Navigator]. The [ValueListenable] will also notify its listeners
114 | /// if the value changes (such as by replacing the previous route).
115 | ///
116 | /// The [ValueListenable] itself will be null before the route is installed.
117 | /// Its content value will be null if the previous route has no title or
118 | /// is not a [CupertinoPageRoute].
119 | ///
120 | /// See also:
121 | ///
122 | /// * [ValueListenableBuilder], which can be used to listen and rebuild
123 | /// widgets based on a ValueListenable.
124 | ValueListenable get previousTitle {
125 | assert(
126 | _previousTitle != null,
127 | 'Cannot read the previousTitle for a route that has not yet been installed',
128 | );
129 | return _previousTitle;
130 | }
131 |
132 | @override
133 | void didChangePrevious(Route previousRoute) {
134 | final String previousTitleString =
135 | previousRoute is CupertinoRouteTransitionMixin
136 | ? previousRoute.title
137 | : null;
138 | if (_previousTitle == null) {
139 | _previousTitle = ValueNotifier(previousTitleString);
140 | } else {
141 | _previousTitle.value = previousTitleString;
142 | }
143 | super.didChangePrevious(previousRoute);
144 | }
145 |
146 | @override
147 | // A relatively rigorous eyeball estimation.
148 | Duration get transitionDuration => const Duration(milliseconds: 400);
149 |
150 | @override
151 | Color get barrierColor => null;
152 |
153 | @override
154 | String get barrierLabel => null;
155 |
156 | @override
157 | bool canTransitionTo(TransitionRoute nextRoute) {
158 | // Don't perform outgoing animation if the next route is a fullscreen dialog.
159 | return nextRoute is CupertinoRouteTransitionMixin &&
160 | !nextRoute.fullscreenDialog;
161 | }
162 |
163 | /// True if an iOS-style back swipe pop gesture is currently underway for [route].
164 | ///
165 | /// This just check the route's [NavigatorState.userGestureInProgress].
166 | ///
167 | /// See also:
168 | ///
169 | /// * [popGestureEnabled], which returns true if a user-triggered pop gesture
170 | /// would be allowed.
171 | static bool isPopGestureInProgress(PageRoute route) {
172 | return route.navigator.userGestureInProgress;
173 | }
174 |
175 | /// True if an iOS-style back swipe pop gesture is currently underway for this route.
176 | ///
177 | /// See also:
178 | ///
179 | /// * [isPopGestureInProgress], which returns true if a Cupertino pop gesture
180 | /// is currently underway for specific route.
181 | /// * [popGestureEnabled], which returns true if a user-triggered pop gesture
182 | /// would be allowed.
183 | bool get popGestureInProgress => isPopGestureInProgress(this);
184 |
185 | /// Whether a pop gesture can be started by the user.
186 | ///
187 | /// Returns true if the user can edge-swipe to a previous route.
188 | ///
189 | /// Returns false once [isPopGestureInProgress] is true, but
190 | /// [isPopGestureInProgress] can only become true if [popGestureEnabled] was
191 | /// true first.
192 | ///
193 | /// This should only be used between frames, not during build.
194 | bool get popGestureEnabled => _isPopGestureEnabled(this);
195 |
196 | static bool _isPopGestureEnabled(PageRoute route) {
197 | // If there's nothing to go back to, then obviously we don't support
198 | // the back gesture.
199 | if (route.isFirst) return false;
200 | // If the route wouldn't actually pop if we popped it, then the gesture
201 | // would be really confusing (or would skip internal routes), so disallow it.
202 | if (route.willHandlePopInternally) return false;
203 | // If attempts to dismiss this route might be vetoed such as in a page
204 | // with forms, then do not allow the user to dismiss the route with a swipe.
205 | if (route.hasScopedWillPopCallback) return false;
206 | // Fullscreen dialogs aren't dismissible by back swipe.
207 | if (route.fullscreenDialog) return false;
208 | // If we're in an animation already, we cannot be manually swiped.
209 | if (route.animation.status != AnimationStatus.completed) return false;
210 | // If we're being popped into, we also cannot be swiped until the pop above
211 | // it completes. This translates to our secondary animation being
212 | // dismissed.
213 | if (route.secondaryAnimation.status != AnimationStatus.dismissed)
214 | return false;
215 | // If we're in a gesture already, we cannot start another.
216 | if (isPopGestureInProgress(route)) return false;
217 |
218 | // Looks like a back gesture would be welcome!
219 | return true;
220 | }
221 |
222 | @override
223 | Widget buildPage(BuildContext context, Animation animation,
224 | Animation secondaryAnimation) {
225 | final Widget child = buildContent(context);
226 | final Widget result = Semantics(
227 | scopesRoute: true,
228 | explicitChildNodes: true,
229 | child: child,
230 | );
231 | assert(() {
232 | if (child == null) {
233 | throw FlutterError.fromParts([
234 | ErrorSummary(
235 | 'The builder for route "${settings.name}" returned null.'),
236 | ErrorDescription('Route builders must never return null.'),
237 | ]);
238 | }
239 | return true;
240 | }());
241 | return result;
242 | }
243 |
244 | // Called by _CupertinoBackGestureDetector when a pop ("back") drag start
245 | // gesture is detected. The returned controller handles all of the subsequent
246 | // drag events.
247 | static _CupertinoBackGestureController _startPopGesture(
248 | PageRoute route) {
249 | assert(_isPopGestureEnabled(route));
250 |
251 | return _CupertinoBackGestureController(
252 | navigator: route.navigator,
253 | controller: route.controller, // protected access
254 | );
255 | }
256 |
257 | /// Returns a [CupertinoFullscreenDialogTransition] if [route] is a full
258 | /// screen dialog, otherwise a [CupertinoPageTransition] is returned.
259 | ///
260 | /// Used by [CupertinoPageRoute.buildTransitions].
261 | ///
262 | /// This method can be applied to any [PageRoute], not just
263 | /// [CupertinoPageRoute]. It's typically used to provide a Cupertino style
264 | /// horizontal transition for material widgets when the target platform
265 | /// is [TargetPlatform.iOS].
266 | ///
267 | /// See also:
268 | ///
269 | /// * [CupertinoPageTransitionsBuilder], which uses this method to define a
270 | /// [PageTransitionsBuilder] for the [PageTransitionsTheme].
271 | static Widget buildPageTransitions(
272 | PageRoute route,
273 | BuildContext context,
274 | Animation animation,
275 | Animation secondaryAnimation,
276 | Widget child,
277 | ) {
278 | // Check if the route has an animation that's currently participating
279 | // in a back swipe gesture.
280 | //
281 | // In the middle of a back gesture drag, let the transition be linear to
282 | // match finger motions.
283 | final bool linearTransition = isPopGestureInProgress(route);
284 | if (route.fullscreenDialog) {
285 | return CupertinoFullscreenDialogTransition(
286 | primaryRouteAnimation: animation,
287 | secondaryRouteAnimation: secondaryAnimation,
288 | child: child,
289 | linearTransition: linearTransition,
290 | );
291 | } else {
292 | return CupertinoPageTransition(
293 | primaryRouteAnimation: animation,
294 | secondaryRouteAnimation: secondaryAnimation,
295 | linearTransition: linearTransition,
296 | child: _CupertinoBackGestureDetector(
297 | enabledCallback: () => _isPopGestureEnabled(route),
298 | onStartPopGesture: () => _startPopGesture(route),
299 | child: child,
300 | ),
301 | );
302 | }
303 | }
304 |
305 | @override
306 | Widget buildTransitions(BuildContext context, Animation animation,
307 | Animation secondaryAnimation, Widget child) {
308 | return buildPageTransitions(
309 | this, context, animation, secondaryAnimation, child);
310 | }
311 | }
312 |
313 | /// A modal route that replaces the entire screen with an iOS transition.
314 | ///
315 | /// {@macro flutter.cupertino.cupertinoRouteTransitionMixin}
316 | ///
317 | /// By default, when a modal route is replaced by another, the previous route
318 | /// remains in memory. To free all the resources when this is not necessary, set
319 | /// [maintainState] to false.
320 | ///
321 | /// The type `T` specifies the return type of the route which can be supplied as
322 | /// the route is popped from the stack via [Navigator.pop] when an optional
323 | /// `result` can be provided.
324 | ///
325 | /// See also:
326 | ///
327 | /// * [CupertinoRouteTransitionMixin], for a mixin that provides iOS transition
328 | /// for this modal route.
329 | /// * [MaterialPageRoute], for an adaptive [PageRoute] that uses a
330 | /// platform-appropriate transition.
331 | /// * [CupertinoPageScaffold], for applications that have one page with a fixed
332 | /// navigation bar on top.
333 | /// * [CupertinoTabScaffold], for applications that have a tab bar at the
334 | /// bottom with multiple pages.
335 | /// * [CupertinoPage], for a [Page] version of this class.
336 | class CupertinoPageRoute extends PageRoute
337 | with CupertinoRouteTransitionMixin {
338 | /// Creates a page route for use in an iOS designed app.
339 | ///
340 | /// The [builder], [maintainState], and [fullscreenDialog] arguments must not
341 | /// be null.
342 | CupertinoPageRoute({
343 | @required this.builder,
344 | this.title,
345 | RouteSettings settings,
346 | this.maintainState = true,
347 | bool fullscreenDialog = false,
348 | }) : assert(builder != null),
349 | assert(maintainState != null),
350 | assert(fullscreenDialog != null),
351 | assert(opaque),
352 | super(settings: settings, fullscreenDialog: fullscreenDialog);
353 |
354 | /// Builds the primary contents of the route.
355 | final WidgetBuilder builder;
356 |
357 | @override
358 | final String title;
359 |
360 | @override
361 | Widget buildContent(BuildContext context) => builder(context);
362 |
363 | @override
364 | final bool maintainState;
365 |
366 | @override
367 | String get debugLabel => '${super.debugLabel}(${settings.name})';
368 | }
369 |
370 | // A page-based version of CupertinoPageRoute.
371 | //
372 | // This route uses the builder from the page to build its content. This ensures
373 | // the content is up to date after page updates.
374 | class _PageBasedCupertinoPageRoute extends PageRoute
375 | with CupertinoRouteTransitionMixin {
376 | _PageBasedCupertinoPageRoute({
377 | @required CupertinoPage page,
378 | }) : assert(page != null),
379 | assert(opaque),
380 | super(settings: page);
381 |
382 | CupertinoPage get _page => settings as CupertinoPage;
383 |
384 | @override
385 | Widget buildContent(BuildContext context) => _page.child;
386 |
387 | @override
388 | String get title => _page.title;
389 |
390 | @override
391 | bool get maintainState => _page.maintainState;
392 |
393 | @override
394 | bool get fullscreenDialog => _page.fullscreenDialog;
395 |
396 | @override
397 | String get debugLabel => '${super.debugLabel}(${_page.name})';
398 | }
399 |
400 | /// A page that creates a cupertino style [PageRoute].
401 | ///
402 | /// {@macro flutter.cupertino.cupertinoRouteTransitionMixin}
403 | ///
404 | /// By default, when a created modal route is replaced by another, the previous
405 | /// route remains in memory. To free all the resources when this is not
406 | /// necessary, set [maintainState] to false.
407 | ///
408 | /// The type `T` specifies the return type of the route which can be supplied as
409 | /// the route is popped from the stack via [Navigator.transitionDelegate] by
410 | /// providing the optional `result` argument to the
411 | /// [RouteTransitionRecord.markForPop] in the [TransitionDelegate.resolve].
412 | ///
413 | /// See also:
414 | ///
415 | /// * [CupertinoPageRoute], for a [PageRoute] version of this class.
416 | class CupertinoPage extends Page {
417 | /// Creates a cupertino page.
418 | const CupertinoPage({
419 | @required this.child,
420 | this.maintainState = true,
421 | this.title,
422 | this.fullscreenDialog = false,
423 | LocalKey key,
424 | String name,
425 | Object arguments,
426 | }) : assert(child != null),
427 | assert(maintainState != null),
428 | assert(fullscreenDialog != null),
429 | super(key: key, name: name, arguments: arguments);
430 |
431 | /// The content to be shown in the [Route] created by this page.
432 | final Widget child;
433 |
434 | /// {@macro flutter.cupertino.cupertinoRouteTransitionMixin.title}
435 | final String title;
436 |
437 | /// {@macro flutter.widgets.modalRoute.maintainState}
438 | final bool maintainState;
439 |
440 | /// {@macro flutter.widgets.pageRoute.fullscreenDialog}
441 | final bool fullscreenDialog;
442 |
443 | @override
444 | Route createRoute(BuildContext context) {
445 | return _PageBasedCupertinoPageRoute(page: this);
446 | }
447 | }
448 |
449 | /// Provides an iOS-style page transition animation.
450 | ///
451 | /// The page slides in from the right and exits in reverse. It also shifts to the left in
452 | /// a parallax motion when another page enters to cover it.
453 | class CupertinoPageTransition extends StatelessWidget {
454 | /// Creates an iOS-style page transition.
455 | ///
456 | /// * `primaryRouteAnimation` is a linear route animation from 0.0 to 1.0
457 | /// when this screen is being pushed.
458 | /// * `secondaryRouteAnimation` is a linear route animation from 0.0 to 1.0
459 | /// when another screen is being pushed on top of this one.
460 | /// * `linearTransition` is whether to perform the transitions linearly.
461 | /// Used to precisely track back gesture drags.
462 | CupertinoPageTransition({
463 | Key key,
464 | @required Animation primaryRouteAnimation,
465 | @required Animation secondaryRouteAnimation,
466 | @required this.child,
467 | @required bool linearTransition,
468 | }) : assert(linearTransition != null),
469 | _primaryPositionAnimation = (linearTransition
470 | ? primaryRouteAnimation
471 | : CurvedAnimation(
472 | // The curves below have been rigorously derived from plots of native
473 | // iOS animation frames. Specifically, a video was taken of a page
474 | // transition animation and the distance in each frame that the page
475 | // moved was measured. A best fit bezier curve was the fitted to the
476 | // point set, which is linearToEaseIn. Conversely, easeInToLinear is the
477 | // reflection over the origin of linearToEaseIn.
478 | parent: primaryRouteAnimation,
479 | curve: Curves.linearToEaseOut,
480 | reverseCurve: Curves.easeInToLinear,
481 | ))
482 | .drive(_kRightMiddleTween),
483 | _secondaryPositionAnimation = (linearTransition
484 | ? secondaryRouteAnimation
485 | : CurvedAnimation(
486 | parent: secondaryRouteAnimation,
487 | curve: Curves.linearToEaseOut,
488 | reverseCurve: Curves.easeInToLinear,
489 | ))
490 | .drive(_kMiddleLeftTween),
491 | _primaryShadowAnimation = (linearTransition
492 | ? primaryRouteAnimation
493 | : CurvedAnimation(
494 | parent: primaryRouteAnimation,
495 | curve: Curves.linearToEaseOut,
496 | ))
497 | .drive(_kGradientShadowTween),
498 | super(key: key);
499 |
500 | // When this page is coming in to cover another page.
501 | final Animation _primaryPositionAnimation;
502 | // When this page is becoming covered by another page.
503 | final Animation _secondaryPositionAnimation;
504 | final Animation _primaryShadowAnimation;
505 |
506 | /// The widget below this widget in the tree.
507 | final Widget child;
508 |
509 | @override
510 | Widget build(BuildContext context) {
511 | assert(debugCheckHasDirectionality(context));
512 | final TextDirection textDirection = Directionality.of(context);
513 | return SlideTransition(
514 | position: _secondaryPositionAnimation,
515 | textDirection: textDirection,
516 | transformHitTests: false,
517 | child: SlideTransition(
518 | position: _primaryPositionAnimation,
519 | textDirection: textDirection,
520 | child: DecoratedBoxTransition(
521 | decoration: _primaryShadowAnimation,
522 | child: child,
523 | ),
524 | ),
525 | );
526 | }
527 | }
528 |
529 | /// An iOS-style transition used for summoning fullscreen dialogs.
530 | ///
531 | /// For example, used when creating a new calendar event by bringing in the next
532 | /// screen from the bottom.
533 | class CupertinoFullscreenDialogTransition extends StatelessWidget {
534 | /// Creates an iOS-style transition used for summoning fullscreen dialogs.
535 | ///
536 | /// * `primaryRouteAnimation` is a linear route animation from 0.0 to 1.0
537 | /// when this screen is being pushed.
538 | /// * `secondaryRouteAnimation` is a linear route animation from 0.0 to 1.0
539 | /// when another screen is being pushed on top of this one.
540 | /// * `linearTransition` is whether to perform the secondary transition linearly.
541 | /// Used to precisely track back gesture drags.
542 | CupertinoFullscreenDialogTransition({
543 | Key key,
544 | @required Animation primaryRouteAnimation,
545 | @required Animation secondaryRouteAnimation,
546 | @required this.child,
547 | @required bool linearTransition,
548 | }) : _positionAnimation = CurvedAnimation(
549 | parent: primaryRouteAnimation,
550 | curve: Curves.linearToEaseOut,
551 | // The curve must be flipped so that the reverse animation doesn't play
552 | // an ease-in curve, which iOS does not use.
553 | reverseCurve: Curves.linearToEaseOut.flipped,
554 | ).drive(_kBottomUpTween),
555 | _secondaryPositionAnimation = (linearTransition
556 | ? secondaryRouteAnimation
557 | : CurvedAnimation(
558 | parent: secondaryRouteAnimation,
559 | curve: Curves.linearToEaseOut,
560 | reverseCurve: Curves.easeInToLinear,
561 | ))
562 | .drive(_kMiddleLeftTween),
563 | super(key: key);
564 |
565 | final Animation _positionAnimation;
566 | // When this page is becoming covered by another page.
567 | final Animation _secondaryPositionAnimation;
568 |
569 | /// The widget below this widget in the tree.
570 | final Widget child;
571 |
572 | @override
573 | Widget build(BuildContext context) {
574 | assert(debugCheckHasDirectionality(context));
575 | final TextDirection textDirection = Directionality.of(context);
576 | return SlideTransition(
577 | position: _secondaryPositionAnimation,
578 | textDirection: textDirection,
579 | transformHitTests: false,
580 | child: SlideTransition(
581 | position: _positionAnimation,
582 | child: child,
583 | ),
584 | );
585 | }
586 | }
587 |
588 | /// This is the widget side of [_CupertinoBackGestureController].
589 | ///
590 | /// This widget provides a gesture recognizer which, when it determines the
591 | /// route can be closed with a back gesture, creates the controller and
592 | /// feeds it the input from the gesture recognizer.
593 | ///
594 | /// The gesture data is converted from absolute coordinates to logical
595 | /// coordinates by this widget.
596 | ///
597 | /// The type `T` specifies the return type of the route with which this gesture
598 | /// detector is associated.
599 | class _CupertinoBackGestureDetector extends StatefulWidget {
600 | const _CupertinoBackGestureDetector({
601 | Key key,
602 | @required this.enabledCallback,
603 | @required this.onStartPopGesture,
604 | @required this.child,
605 | }) : assert(enabledCallback != null),
606 | assert(onStartPopGesture != null),
607 | assert(child != null),
608 | super(key: key);
609 |
610 | final Widget child;
611 |
612 | final ValueGetter enabledCallback;
613 |
614 | final ValueGetter<_CupertinoBackGestureController> onStartPopGesture;
615 |
616 | @override
617 | _CupertinoBackGestureDetectorState createState() =>
618 | _CupertinoBackGestureDetectorState();
619 | }
620 |
621 | class _CupertinoBackGestureDetectorState
622 | extends State<_CupertinoBackGestureDetector> {
623 | _CupertinoBackGestureController _backGestureController;
624 |
625 | HorizontalDragGestureRecognizer _recognizer;
626 |
627 | @override
628 | void initState() {
629 | super.initState();
630 | _recognizer = HorizontalDragGestureRecognizer(debugOwner: this)
631 | ..onStart = _handleDragStart
632 | ..onUpdate = _handleDragUpdate
633 | ..onEnd = _handleDragEnd
634 | ..onCancel = _handleDragCancel;
635 | }
636 |
637 | @override
638 | void dispose() {
639 | _recognizer.dispose();
640 | super.dispose();
641 | }
642 |
643 | void _handleDragStart(DragStartDetails details) {
644 | assert(mounted);
645 | assert(_backGestureController == null);
646 | _backGestureController = widget.onStartPopGesture();
647 | }
648 |
649 | void _handleDragUpdate(DragUpdateDetails details) {
650 | assert(mounted);
651 | assert(_backGestureController != null);
652 | _backGestureController.dragUpdate(
653 | _convertToLogical(details.primaryDelta / context.size.width));
654 | }
655 |
656 | void _handleDragEnd(DragEndDetails details) {
657 | assert(mounted);
658 | assert(_backGestureController != null);
659 | _backGestureController.dragEnd(_convertToLogical(
660 | details.velocity.pixelsPerSecond.dx / context.size.width));
661 | _backGestureController = null;
662 | }
663 |
664 | void _handleDragCancel() {
665 | assert(mounted);
666 | // This can be called even if start is not called, paired with the "down" event
667 | // that we don't consider here.
668 | _backGestureController?.dragEnd(0.0);
669 | _backGestureController = null;
670 | }
671 |
672 | void _handlePointerDown(PointerDownEvent event) {
673 | if (widget.enabledCallback()) _recognizer.addPointer(event);
674 | }
675 |
676 | double _convertToLogical(double value) {
677 | switch (Directionality.of(context)) {
678 | case TextDirection.rtl:
679 | return -value;
680 | case TextDirection.ltr:
681 | return value;
682 | }
683 | return null;
684 | }
685 |
686 | @override
687 | Widget build(BuildContext context) {
688 | assert(debugCheckHasDirectionality(context));
689 | // For devices with notches, the drag area needs to be larger on the side
690 | // that has the notch.
691 | double dragAreaWidth = Directionality.of(context) == TextDirection.ltr
692 | ? MediaQuery.of(context).padding.left
693 | : MediaQuery.of(context).padding.right;
694 | dragAreaWidth = max(dragAreaWidth, _kBackGestureWidth);
695 | return Stack(
696 | fit: StackFit.passthrough,
697 | children: [
698 | widget.child,
699 | PositionedDirectional(
700 | start: 0.0,
701 | width: dragAreaWidth,
702 | top: 0.0,
703 | bottom: 0.0,
704 | child: Listener(
705 | onPointerDown: _handlePointerDown,
706 | behavior: HitTestBehavior.translucent,
707 | ),
708 | ),
709 | ],
710 | );
711 | }
712 | }
713 |
714 | /// A controller for an iOS-style back gesture.
715 | ///
716 | /// This is created by a [CupertinoPageRoute] in response from a gesture caught
717 | /// by a [_CupertinoBackGestureDetector] widget, which then also feeds it input
718 | /// from the gesture. It controls the animation controller owned by the route,
719 | /// based on the input provided by the gesture detector.
720 | ///
721 | /// This class works entirely in logical coordinates (0.0 is new page dismissed,
722 | /// 1.0 is new page on top).
723 | ///
724 | /// The type `T` specifies the return type of the route with which this gesture
725 | /// detector controller is associated.
726 | class _CupertinoBackGestureController {
727 | /// Creates a controller for an iOS-style back gesture.
728 | ///
729 | /// The [navigator] and [controller] arguments must not be null.
730 | _CupertinoBackGestureController({
731 | @required this.navigator,
732 | @required this.controller,
733 | }) : assert(navigator != null),
734 | assert(controller != null) {
735 | navigator.didStartUserGesture();
736 | }
737 |
738 | final AnimationController controller;
739 | final NavigatorState navigator;
740 |
741 | /// The drag gesture has changed by [fractionalDelta]. The total range of the
742 | /// drag should be 0.0 to 1.0.
743 | void dragUpdate(double delta) {
744 | controller.value -= delta;
745 | }
746 |
747 | /// The drag gesture has ended with a horizontal motion of
748 | /// [fractionalVelocity] as a fraction of screen width per second.
749 | void dragEnd(double velocity) {
750 | // Fling in the appropriate direction.
751 | // AnimationController.fling is guaranteed to
752 | // take at least one frame.
753 | //
754 | // This curve has been determined through rigorously eyeballing native iOS
755 | // animations.
756 | const Curve animationCurve = Curves.fastLinearToSlowEaseIn;
757 | bool animateForward;
758 |
759 | // If the user releases the page before mid screen with sufficient velocity,
760 | // or after mid screen, we should animate the page out. Otherwise, the page
761 | // should be animated back in.
762 | if (velocity.abs() >= _kMinFlingVelocity)
763 | animateForward = velocity <= 0;
764 | else
765 | animateForward = controller.value > 0.5;
766 |
767 | if (animateForward) {
768 | // The closer the panel is to dismissing, the shorter the animation is.
769 | // We want to cap the animation time, but we want to use a linear curve
770 | // to determine it.
771 | final int droppedPageForwardAnimationTime = min(
772 | lerpDouble(
773 | _kMaxDroppedSwipePageForwardAnimationTime, 0, controller.value)
774 | .floor(),
775 | _kMaxPageBackAnimationTime,
776 | );
777 | controller.animateTo(1.0,
778 | duration: Duration(milliseconds: droppedPageForwardAnimationTime),
779 | curve: animationCurve);
780 | } else {
781 | // This route is destined to pop at this point. Reuse navigator's pop.
782 | navigator.pop();
783 |
784 | // The popping may have finished inline if already at the target destination.
785 | if (controller.isAnimating) {
786 | // Otherwise, use a custom popping animation duration and curve.
787 | final int droppedPageBackAnimationTime = lerpDouble(
788 | 0, _kMaxDroppedSwipePageForwardAnimationTime, controller.value)
789 | .floor();
790 | controller.animateBack(0.0,
791 | duration: Duration(milliseconds: droppedPageBackAnimationTime),
792 | curve: animationCurve);
793 | }
794 | }
795 |
796 | if (controller.isAnimating) {
797 | // Keep the userGestureInProgress in true state so we don't change the
798 | // curve of the page transition mid-flight since CupertinoPageTransition
799 | // depends on userGestureInProgress.
800 | AnimationStatusListener animationStatusCallback;
801 | animationStatusCallback = (AnimationStatus status) {
802 | navigator.didStopUserGesture();
803 | controller.removeStatusListener(animationStatusCallback);
804 | };
805 | controller.addStatusListener(animationStatusCallback);
806 | } else {
807 | navigator.didStopUserGesture();
808 | }
809 | }
810 | }
811 |
812 | // A custom [Decoration] used to paint an extra shadow on the start edge of the
813 | // box it's decorating. It's like a [BoxDecoration] with only a gradient except
814 | // it paints on the start side of the box instead of behind the box.
815 | //
816 | // The [edgeGradient] will be given a [TextDirection] when its shader is
817 | // created, and so can be direction-sensitive; in this file we set it to a
818 | // gradient that uses an AlignmentDirectional to position the gradient on the
819 | // end edge of the gradient's box (which will be the edge adjacent to the start
820 | // edge of the actual box we're supposed to paint in).
821 | class _CupertinoEdgeShadowDecoration extends Decoration {
822 | const _CupertinoEdgeShadowDecoration({this.edgeGradient});
823 |
824 | // An edge shadow decoration where the shadow is null. This is used
825 | // for interpolating from no shadow.
826 | static const _CupertinoEdgeShadowDecoration none =
827 | _CupertinoEdgeShadowDecoration();
828 |
829 | // A gradient to draw to the left of the box being decorated.
830 | // Alignments are relative to the original box translated one box
831 | // width to the left.
832 | final LinearGradient edgeGradient;
833 |
834 | // Linearly interpolate between two edge shadow decorations decorations.
835 | //
836 | // The `t` argument represents position on the timeline, with 0.0 meaning
837 | // that the interpolation has not started, returning `a` (or something
838 | // equivalent to `a`), 1.0 meaning that the interpolation has finished,
839 | // returning `b` (or something equivalent to `b`), and values in between
840 | // meaning that the interpolation is at the relevant point on the timeline
841 | // between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
842 | // 1.0, so negative values and values greater than 1.0 are valid (and can
843 | // easily be generated by curves such as [Curves.elasticInOut]).
844 | //
845 | // Values for `t` are usually obtained from an [Animation], such as
846 | // an [AnimationController].
847 | //
848 | // See also:
849 | //
850 | // * [Decoration.lerp].
851 | static _CupertinoEdgeShadowDecoration lerp(
852 | _CupertinoEdgeShadowDecoration a,
853 | _CupertinoEdgeShadowDecoration b,
854 | double t,
855 | ) {
856 | assert(t != null);
857 | if (a == null && b == null) return null;
858 | return _CupertinoEdgeShadowDecoration(
859 | edgeGradient: LinearGradient.lerp(a?.edgeGradient, b?.edgeGradient, t),
860 | );
861 | }
862 |
863 | @override
864 | _CupertinoEdgeShadowDecoration lerpFrom(Decoration a, double t) {
865 | if (a is _CupertinoEdgeShadowDecoration)
866 | return _CupertinoEdgeShadowDecoration.lerp(a, this, t);
867 | return _CupertinoEdgeShadowDecoration.lerp(null, this, t);
868 | }
869 |
870 | @override
871 | _CupertinoEdgeShadowDecoration lerpTo(Decoration b, double t) {
872 | if (b is _CupertinoEdgeShadowDecoration)
873 | return _CupertinoEdgeShadowDecoration.lerp(this, b, t);
874 | return _CupertinoEdgeShadowDecoration.lerp(this, null, t);
875 | }
876 |
877 | @override
878 | _CupertinoEdgeShadowPainter createBoxPainter([VoidCallback onChanged]) {
879 | return _CupertinoEdgeShadowPainter(this, onChanged);
880 | }
881 |
882 | @override
883 | bool operator ==(Object other) {
884 | if (other.runtimeType != runtimeType) return false;
885 | return other is _CupertinoEdgeShadowDecoration &&
886 | other.edgeGradient == edgeGradient;
887 | }
888 |
889 | @override
890 | int get hashCode => edgeGradient.hashCode;
891 |
892 | @override
893 | void debugFillProperties(DiagnosticPropertiesBuilder properties) {
894 | super.debugFillProperties(properties);
895 | properties
896 | .add(DiagnosticsProperty('edgeGradient', edgeGradient));
897 | }
898 | }
899 |
900 | /// A [BoxPainter] used to draw the page transition shadow using gradients.
901 | class _CupertinoEdgeShadowPainter extends BoxPainter {
902 | _CupertinoEdgeShadowPainter(
903 | this._decoration,
904 | VoidCallback onChange,
905 | ) : assert(_decoration != null),
906 | super(onChange);
907 |
908 | final _CupertinoEdgeShadowDecoration _decoration;
909 |
910 | @override
911 | void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
912 | final LinearGradient gradient = _decoration.edgeGradient;
913 | if (gradient == null) return;
914 | // The drawable space for the gradient is a rect with the same size as
915 | // its parent box one box width on the start side of the box.
916 | final TextDirection textDirection = configuration.textDirection;
917 | assert(textDirection != null);
918 | double deltaX;
919 | switch (textDirection) {
920 | case TextDirection.rtl:
921 | deltaX = configuration.size.width;
922 | break;
923 | case TextDirection.ltr:
924 | deltaX = -configuration.size.width;
925 | break;
926 | }
927 | final Rect rect = (offset & configuration.size).translate(deltaX, 0.0);
928 | final Paint paint = Paint()
929 | ..shader = gradient.createShader(rect, textDirection: textDirection);
930 |
931 | canvas.drawRect(rect, paint);
932 | }
933 | }
934 |
935 | class _CupertinoModalPopupRoute extends PopupRoute {
936 | _CupertinoModalPopupRoute({
937 | this.barrierColor,
938 | this.barrierLabel,
939 | this.builder,
940 | bool semanticsDismissible,
941 | ImageFilter filter,
942 | RouteSettings settings,
943 | }) : super(
944 | filter: filter,
945 | settings: settings,
946 | ) {
947 | _semanticsDismissible = semanticsDismissible;
948 | }
949 |
950 | final WidgetBuilder builder;
951 | bool _semanticsDismissible;
952 |
953 | @override
954 | final String barrierLabel;
955 |
956 | @override
957 | final Color barrierColor;
958 |
959 | @override
960 | bool get barrierDismissible => true;
961 |
962 | @override
963 | bool get semanticsDismissible => _semanticsDismissible ?? false;
964 |
965 | @override
966 | Duration get transitionDuration => _kModalPopupTransitionDuration;
967 |
968 | Animation _animation;
969 |
970 | Tween _offsetTween;
971 |
972 | @override
973 | Animation createAnimation() {
974 | assert(_animation == null);
975 | _animation = CurvedAnimation(
976 | parent: super.createAnimation(),
977 |
978 | // These curves were initially measured from native iOS horizontal page
979 | // route animations and seemed to be a good match here as well.
980 | curve: Curves.linearToEaseOut,
981 | reverseCurve: Curves.linearToEaseOut.flipped,
982 | );
983 | _offsetTween = Tween(
984 | begin: const Offset(0.0, 1.0),
985 | end: const Offset(0.0, 0.0),
986 | );
987 | return _animation;
988 | }
989 |
990 | @override
991 | Widget buildPage(BuildContext context, Animation animation,
992 | Animation secondaryAnimation) {
993 | return CupertinoUserInterfaceLevel(
994 | data: CupertinoUserInterfaceLevelData.elevated,
995 | child: Builder(builder: builder),
996 | );
997 | }
998 |
999 | @override
1000 | Widget buildTransitions(BuildContext context, Animation animation,
1001 | Animation secondaryAnimation, Widget child) {
1002 | return Align(
1003 | alignment: Alignment.bottomCenter,
1004 | child: FractionalTranslation(
1005 | translation: _offsetTween.evaluate(_animation),
1006 | child: child,
1007 | ),
1008 | );
1009 | }
1010 | }
1011 |
1012 | /// Shows a modal iOS-style popup that slides up from the bottom of the screen.
1013 | ///
1014 | /// Such a popup is an alternative to a menu or a dialog and prevents the user
1015 | /// from interacting with the rest of the app.
1016 | ///
1017 | /// The `context` argument is used to look up the [Navigator] for the popup.
1018 | /// It is only used when the method is called. Its corresponding widget can be
1019 | /// safely removed from the tree before the popup is closed.
1020 | ///
1021 | /// The `useRootNavigator` argument is used to determine whether to push the
1022 | /// popup to the [Navigator] furthest from or nearest to the given `context`. It
1023 | /// is `false` by default.
1024 | ///
1025 | /// The `semanticsDismissible` argument is used to determine whether the
1026 | /// semantics of the modal barrier are included in the semantics tree.
1027 | ///
1028 | /// The `builder` argument typically builds a [CupertinoActionSheet] widget.
1029 | /// Content below the widget is dimmed with a [ModalBarrier]. The widget built
1030 | /// by the `builder` does not share a context with the location that
1031 | /// `showCupertinoModalPopup` is originally called from. Use a
1032 | /// [StatefulBuilder] or a custom [StatefulWidget] if the widget needs to
1033 | /// update dynamically.
1034 | ///
1035 | /// Returns a `Future` that resolves to the value that was passed to
1036 | /// [Navigator.pop] when the popup was closed.
1037 | ///
1038 | /// See also:
1039 | ///
1040 | /// * [CupertinoActionSheet], which is the widget usually returned by the
1041 | /// `builder` argument to [showCupertinoModalPopup].
1042 | /// *
1043 | Future showCupertinoModalPopup({
1044 | @required BuildContext context,
1045 | @required WidgetBuilder builder,
1046 | ImageFilter filter,
1047 | bool useRootNavigator = true,
1048 | bool semanticsDismissible,
1049 | }) {
1050 | assert(useRootNavigator != null);
1051 | return Navigator.of(context, rootNavigator: useRootNavigator).push(
1052 | _CupertinoModalPopupRoute(
1053 | barrierColor: CupertinoDynamicColor.resolve(_kModalBarrierColor, context),
1054 | barrierLabel: 'Dismiss',
1055 | builder: builder,
1056 | filter: filter,
1057 | semanticsDismissible: semanticsDismissible,
1058 | ),
1059 | );
1060 | }
1061 |
1062 | // The curve and initial scale values were mostly eyeballed from iOS, however
1063 | // they reuse the same animation curve that was modeled after native page
1064 | // transitions.
1065 | final Animatable _dialogScaleTween = Tween(begin: 1.3, end: 1.0)
1066 | .chain(CurveTween(curve: Curves.linearToEaseOut));
1067 |
1068 | Widget _buildCupertinoDialogTransitions(
1069 | BuildContext context,
1070 | Animation animation,
1071 | Animation secondaryAnimation,
1072 | Widget child) {
1073 | final CurvedAnimation fadeAnimation = CurvedAnimation(
1074 | parent: animation,
1075 | curve: Curves.easeInOut,
1076 | );
1077 | if (animation.status == AnimationStatus.reverse) {
1078 | return FadeTransition(
1079 | opacity: fadeAnimation,
1080 | child: child,
1081 | );
1082 | }
1083 | return FadeTransition(
1084 | opacity: fadeAnimation,
1085 | child: ScaleTransition(
1086 | child: child,
1087 | scale: animation.drive(_dialogScaleTween),
1088 | ),
1089 | );
1090 | }
1091 |
1092 | /// Displays an iOS-style dialog above the current contents of the app, with
1093 | /// iOS-style entrance and exit animations, modal barrier color, and modal
1094 | /// barrier behavior (by default, the dialog is not dismissible with a tap on
1095 | /// the barrier).
1096 | ///
1097 | /// This function takes a `builder` which typically builds a [CupertinoDialog]
1098 | /// or [CupertinoAlertDialog] widget. Content below the dialog is dimmed with a
1099 | /// [ModalBarrier]. The widget returned by the `builder` does not share a
1100 | /// context with the location that `showCupertinoDialog` is originally called
1101 | /// from. Use a [StatefulBuilder] or a custom [StatefulWidget] if the dialog
1102 | /// needs to update dynamically.
1103 | ///
1104 | /// The `context` argument is used to look up the [Navigator] for the dialog.
1105 | /// It is only used when the method is called. Its corresponding widget can
1106 | /// be safely removed from the tree before the dialog is closed.
1107 | ///
1108 | /// The `useRootNavigator` argument is used to determine whether to push the
1109 | /// dialog to the [Navigator] furthest from or nearest to the given `context`.
1110 | /// By default, `useRootNavigator` is `true` and the dialog route created by
1111 | /// this method is pushed to the root navigator.
1112 | ///
1113 | /// If the application has multiple [Navigator] objects, it may be necessary to
1114 | /// call `Navigator.of(context, rootNavigator: true).pop(result)` to close the
1115 | /// dialog rather than just `Navigator.pop(context, result)`.
1116 | ///
1117 | /// Returns a [Future] that resolves to the value (if any) that was passed to
1118 | /// [Navigator.pop] when the dialog was closed.
1119 | ///
1120 | /// See also:
1121 | ///
1122 | /// * [CupertinoDialog], an iOS-style dialog.
1123 | /// * [CupertinoAlertDialog], an iOS-style alert dialog.
1124 | /// * [showDialog], which displays a Material-style dialog.
1125 | /// * [showGeneralDialog], which allows for customization of the dialog popup.
1126 | /// *
1127 | Future showCupertinoDialog({
1128 | @required BuildContext context,
1129 | @required WidgetBuilder builder,
1130 | bool useRootNavigator = true,
1131 | bool barrierDismissible = false,
1132 | RouteSettings routeSettings,
1133 | }) {
1134 | assert(builder != null);
1135 | assert(useRootNavigator != null);
1136 | return showGeneralDialog(
1137 | context: context,
1138 | barrierDismissible: barrierDismissible,
1139 | barrierLabel: CupertinoLocalizations.of(context).modalBarrierDismissLabel,
1140 | barrierColor: CupertinoDynamicColor.resolve(_kModalBarrierColor, context),
1141 | // This transition duration was eyeballed comparing with iOS
1142 | transitionDuration: const Duration(milliseconds: 250),
1143 | pageBuilder: (BuildContext context, Animation animation,
1144 | Animation secondaryAnimation) {
1145 | return builder(context);
1146 | },
1147 | transitionBuilder: _buildCupertinoDialogTransitions,
1148 | useRootNavigator: useRootNavigator,
1149 | routeSettings: routeSettings,
1150 | );
1151 | }
1152 |
--------------------------------------------------------------------------------