diff --git a/navigation_and_routing/.gitignore b/navigation_and_routing/.gitignore new file mode 100644 index 000000000..9d532b18a --- /dev/null +++ b/navigation_and_routing/.gitignore @@ -0,0 +1,41 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json diff --git a/navigation_and_routing/.metadata b/navigation_and_routing/.metadata new file mode 100644 index 000000000..f0274b3eb --- /dev/null +++ b/navigation_and_routing/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 1aafb3a8b9b0c36241c5f5b34ee914770f015818 + channel: stable + +project_type: app diff --git a/navigation_and_routing/README.md b/navigation_and_routing/README.md new file mode 100644 index 000000000..8f345eeda --- /dev/null +++ b/navigation_and_routing/README.md @@ -0,0 +1,46 @@ +# Navigation and Routing sample code + +Sample code for [Learning Flutter's New Navigation and Routing System][article], +an article explaining Navigator 2.0. + +## Samples + +**Navigator 1.0 samples** + +* `nav_1/anonymous_routes.dart` - Shows how to use a Navigator to push and pop + anonymous routes (e.g. MaterialPageRoute) +* `nav_1/named_routes.dart` - Shows how to use define named routes via the `routes` + parameter on MaterialApp, and navigate using Navigator.pushNamed +* `nav_1/on_generate_route.dart` - Shows how to handle arbitrary named routes + using the `onGenerateRoute` callback defined in the `MaterialApp` constructor. + +** Navigator 2.0 samples** + +* `nav_2/pages.dart` - Shows how to define a list of [Page] objects on Navigator + declaratively. +* `nav_2/router.dart` - Full sample that shows a custom RouteInformationParser + and RouterDelegate parsing named routes and declaratively building the stack + of pages for the Navigator. + + +** Advanced ** + +* `nav_2_advanced/nested_router.dart` - Shows two [RouterDelegate], one nested + within the other. A [BottomNavigationBar] can be used to select the route of + the outer RouterDelegate, and additional routes can be pushed onto the inner + RouterDelegate / Navigator. +* `nav_2_advanced/transition_delegate.dart` - Shows how a custom + TransitionDelegate can be used to customized when transition animations are + shown. + + +## Running + +Each file in this project is an entrypoint. To run, specify the filename of +the sample: + +```bash +flutter run lib/nav_2/router.dart +``` + +[article]: https://medium.com/flutter/learning-flutters-new-navigation-and-routing-system-7c9068155ade diff --git a/navigation_and_routing/android/.gitignore b/navigation_and_routing/android/.gitignore new file mode 100644 index 000000000..0a741cb43 --- /dev/null +++ b/navigation_and_routing/android/.gitignore @@ -0,0 +1,11 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/navigation_and_routing/android/app/build.gradle b/navigation_and_routing/android/app/build.gradle new file mode 100644 index 000000000..43ab00829 --- /dev/null +++ b/navigation_and_routing/android/app/build.gradle @@ -0,0 +1,63 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 29 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.navigation_and_routing" + minSdkVersion 16 + targetSdkVersion 29 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/navigation_and_routing/android/app/src/debug/AndroidManifest.xml b/navigation_and_routing/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000..c50a172da --- /dev/null +++ b/navigation_and_routing/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/navigation_and_routing/android/app/src/main/AndroidManifest.xml b/navigation_and_routing/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..aa1a09d24 --- /dev/null +++ b/navigation_and_routing/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/navigation_and_routing/android/app/src/main/kotlin/com/example/navigation_and_routing/MainActivity.kt b/navigation_and_routing/android/app/src/main/kotlin/com/example/navigation_and_routing/MainActivity.kt new file mode 100644 index 000000000..d5a2b6c80 --- /dev/null +++ b/navigation_and_routing/android/app/src/main/kotlin/com/example/navigation_and_routing/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.navigation_and_routing + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/navigation_and_routing/android/app/src/main/res/drawable/launch_background.xml b/navigation_and_routing/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 000000000..304732f88 --- /dev/null +++ b/navigation_and_routing/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/navigation_and_routing/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/navigation_and_routing/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..db77bb4b7 Binary files /dev/null and b/navigation_and_routing/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/navigation_and_routing/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/navigation_and_routing/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..17987b79b Binary files /dev/null and b/navigation_and_routing/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/navigation_and_routing/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/navigation_and_routing/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..09d439148 Binary files /dev/null and b/navigation_and_routing/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/navigation_and_routing/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/navigation_and_routing/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..d5f1c8d34 Binary files /dev/null and b/navigation_and_routing/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/navigation_and_routing/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/navigation_and_routing/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..4d6372eeb Binary files /dev/null and b/navigation_and_routing/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/navigation_and_routing/android/app/src/main/res/values/styles.xml b/navigation_and_routing/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..1f83a33fd --- /dev/null +++ b/navigation_and_routing/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/navigation_and_routing/android/app/src/profile/AndroidManifest.xml b/navigation_and_routing/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 000000000..c50a172da --- /dev/null +++ b/navigation_and_routing/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/navigation_and_routing/android/build.gradle b/navigation_and_routing/android/build.gradle new file mode 100644 index 000000000..3100ad2d5 --- /dev/null +++ b/navigation_and_routing/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/navigation_and_routing/android/gradle.properties b/navigation_and_routing/android/gradle.properties new file mode 100644 index 000000000..94adc3a3f --- /dev/null +++ b/navigation_and_routing/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/navigation_and_routing/android/gradle/wrapper/gradle-wrapper.properties b/navigation_and_routing/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..296b146b7 --- /dev/null +++ b/navigation_and_routing/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/navigation_and_routing/android/settings.gradle b/navigation_and_routing/android/settings.gradle new file mode 100644 index 000000000..44e62bcf0 --- /dev/null +++ b/navigation_and_routing/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/navigation_and_routing/ios/.gitignore b/navigation_and_routing/ios/.gitignore new file mode 100644 index 000000000..e96ef602b --- /dev/null +++ b/navigation_and_routing/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/navigation_and_routing/ios/Flutter/AppFrameworkInfo.plist b/navigation_and_routing/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 000000000..6b4c0f78a --- /dev/null +++ b/navigation_and_routing/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/navigation_and_routing/ios/Flutter/Debug.xcconfig b/navigation_and_routing/ios/Flutter/Debug.xcconfig new file mode 100644 index 000000000..592ceee85 --- /dev/null +++ b/navigation_and_routing/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/navigation_and_routing/ios/Flutter/Release.xcconfig b/navigation_and_routing/ios/Flutter/Release.xcconfig new file mode 100644 index 000000000..592ceee85 --- /dev/null +++ b/navigation_and_routing/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/navigation_and_routing/ios/Runner.xcodeproj/project.pbxproj b/navigation_and_routing/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000..f4b40b249 --- /dev/null +++ b/navigation_and_routing/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,495 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.navigationAndRouting; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.navigationAndRouting; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.navigationAndRouting; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/navigation_and_routing/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/navigation_and_routing/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..1d526a16e --- /dev/null +++ b/navigation_and_routing/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/navigation_and_routing/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/navigation_and_routing/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/navigation_and_routing/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/navigation_and_routing/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/navigation_and_routing/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..f9b0d7c5e --- /dev/null +++ b/navigation_and_routing/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/navigation_and_routing/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/navigation_and_routing/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000..a28140cfd --- /dev/null +++ b/navigation_and_routing/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/navigation_and_routing/ios/Runner.xcworkspace/contents.xcworkspacedata b/navigation_and_routing/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..1d526a16e --- /dev/null +++ b/navigation_and_routing/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/navigation_and_routing/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/navigation_and_routing/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/navigation_and_routing/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/navigation_and_routing/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/navigation_and_routing/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..f9b0d7c5e --- /dev/null +++ b/navigation_and_routing/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/navigation_and_routing/ios/Runner/AppDelegate.swift b/navigation_and_routing/ios/Runner/AppDelegate.swift new file mode 100644 index 000000000..70693e4a8 --- /dev/null +++ b/navigation_and_routing/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..d36b1fab2 --- /dev/null +++ b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 000000000..dc9ada472 Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 000000000..28c6bf030 Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 000000000..2ccbfd967 Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 000000000..f091b6b0b Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 000000000..4cde12118 Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 000000000..d0ef06e7e Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 000000000..dcdc2306c Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 000000000..2ccbfd967 Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 000000000..c8f9ed8f5 Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 000000000..a6d6b8609 Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 000000000..a6d6b8609 Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 000000000..75b2d164a Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 000000000..c4df70d39 Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 000000000..6a84f41e1 Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 000000000..d0e1f5853 Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 000000000..0bedcf2fd --- /dev/null +++ b/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 000000000..9da19eaca Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 000000000..9da19eaca Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 000000000..9da19eaca Binary files /dev/null and b/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 000000000..89c2725b7 --- /dev/null +++ b/navigation_and_routing/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +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. \ No newline at end of file diff --git a/navigation_and_routing/ios/Runner/Base.lproj/LaunchScreen.storyboard b/navigation_and_routing/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..f2e259c7c --- /dev/null +++ b/navigation_and_routing/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/navigation_and_routing/ios/Runner/Base.lproj/Main.storyboard b/navigation_and_routing/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 000000000..f3c28516f --- /dev/null +++ b/navigation_and_routing/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/navigation_and_routing/ios/Runner/Info.plist b/navigation_and_routing/ios/Runner/Info.plist new file mode 100644 index 000000000..7f840e028 --- /dev/null +++ b/navigation_and_routing/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + navigation_and_routing + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/navigation_and_routing/ios/Runner/Runner-Bridging-Header.h b/navigation_and_routing/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 000000000..308a2a560 --- /dev/null +++ b/navigation_and_routing/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/navigation_and_routing/lib/nav_1/anonymous_routes.dart b/navigation_and_routing/lib/nav_1/anonymous_routes.dart new file mode 100644 index 000000000..6a3b5b831 --- /dev/null +++ b/navigation_and_routing/lib/nav_1/anonymous_routes.dart @@ -0,0 +1,61 @@ +// Copyright 2020, the Flutter project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Shows how to use [Navigator] APIs to push and pop an anonymous +/// route. In this case, it is an instance of [MaterialPageRoute]. +library anonymous_routes; + +import 'package:flutter/material.dart'; + +void main() { + runApp(Nav2App()); +} + +class Nav2App extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + home: HomeScreen(), + ); + } +} + +class HomeScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Center( + child: FlatButton( + child: Text('View Details'), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return DetailScreen(); + }), + ); + }, + ), + ), + ); + } +} + +class DetailScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Center( + child: FlatButton( + child: Text('Pop!'), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + ); + } +} diff --git a/navigation_and_routing/lib/nav_1/named_routes.dart b/navigation_and_routing/lib/nav_1/named_routes.dart new file mode 100644 index 000000000..adccc64c4 --- /dev/null +++ b/navigation_and_routing/lib/nav_1/named_routes.dart @@ -0,0 +1,62 @@ +// Copyright 2020, the Flutter project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Shows how to use define named routes via the `routes` parameter on +/// MaterialApp, and navigate using Navigator.pushNamed. +library named_routes; + +import 'package:flutter/material.dart'; + +void main() { + runApp(Nav2App()); +} + +class Nav2App extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + routes: { + '/': (context) => HomeScreen(), + '/details': (context) => DetailScreen(), + }, + ); + } +} + +class HomeScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Center( + child: FlatButton( + child: Text('View Details'), + onPressed: () { + Navigator.pushNamed( + context, + '/details', + ); + }, + ), + ), + ); + } +} + +class DetailScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Center( + child: FlatButton( + child: Text('Pop!'), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + ); + } +} diff --git a/navigation_and_routing/lib/nav_1/on_generate_route.dart b/navigation_and_routing/lib/nav_1/on_generate_route.dart new file mode 100644 index 000000000..52fa761f6 --- /dev/null +++ b/navigation_and_routing/lib/nav_1/on_generate_route.dart @@ -0,0 +1,98 @@ +// Copyright 2020, the Flutter project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Shows how to handle arbitrary named routes using the `onGenerateRoute` +/// callback defined in the `MaterialApp` constructor. +library on_generate_route; + +import 'package:flutter/material.dart'; + +void main() { + runApp(Nav2App()); +} + +class Nav2App extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + onGenerateRoute: (settings) { + // Handle '/' + if (settings.name == '/') { + return MaterialPageRoute(builder: (context) => HomeScreen()); + } + + // Handle '/details/:id' + var uri = Uri.parse(settings.name); + if (uri.pathSegments.length == 2 && + uri.pathSegments.first == 'details') { + var id = uri.pathSegments[1]; + return MaterialPageRoute(builder: (context) => DetailScreen(id: id)); + } + + return MaterialPageRoute(builder: (context) => UnknownScreen()); + }, + ); + } +} + +class HomeScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Center( + child: FlatButton( + child: Text('View Details'), + onPressed: () { + Navigator.pushNamed( + context, + '/details/1', + ); + }, + ), + ), + ); + } +} + +class DetailScreen extends StatelessWidget { + String id; + + DetailScreen({ + this.id, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Viewing details for item $id'), + FlatButton( + child: Text('Pop!'), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + ), + ); + } +} + +class UnknownScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Center( + child: Text('404!'), + ), + ); + } +} diff --git a/navigation_and_routing/lib/nav_2/pages.dart b/navigation_and_routing/lib/nav_2/pages.dart new file mode 100644 index 000000000..80f88ff12 --- /dev/null +++ b/navigation_and_routing/lib/nav_2/pages.dart @@ -0,0 +1,142 @@ +// Copyright 2020, the Flutter project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Shows how to define a list of [Page] objects on Navigator declaratively. +library nav2_pages; + +import 'package:flutter/material.dart'; + +void main() { + runApp(BooksApp()); +} + +class Book { + final String title; + final String author; + + Book(this.title, this.author); +} + +class BooksApp extends StatefulWidget { + @override + State createState() => _BooksAppState(); +} + +class _BooksAppState extends State { + Book _selectedBook; + + List books = [ + Book('Stranger in a Strange Land', 'Robert A. Heinlein'), + Book('Foundation', 'Isaac Asimov'), + Book('Fahrenheit 451', 'Ray Bradbury'), + ]; + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Books App', + home: Navigator( + pages: [ + MaterialPage( + key: ValueKey('BooksListPage'), + child: BooksListScreen( + books: books, + onTapped: _handleBookTapped, + ), + ), + if (_selectedBook != null) BookDetailsPage(book: _selectedBook) + ], + onPopPage: (route, result) { + if (!route.didPop(result)) { + return false; + } + + // Update the list of pages by setting _selectedBook to null + setState(() { + _selectedBook = null; + }); + + return true; + }, + ), + ); + } + + void _handleBookTapped(Book book) { + setState(() { + _selectedBook = book; + }); + } +} + +class BookDetailsPage extends Page { + final Book book; + + BookDetailsPage({ + this.book, + }) : super(key: ValueKey(book)); + + Route createRoute(BuildContext context) { + return MaterialPageRoute( + settings: this, + builder: (BuildContext context) { + return BookDetailsScreen(book: book); + }, + ); + } +} + +class BooksListScreen extends StatelessWidget { + final List books; + final ValueChanged onTapped; + + BooksListScreen({ + @required this.books, + @required this.onTapped, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: ListView( + children: [ + for (var book in books) + ListTile( + title: Text(book.title), + subtitle: Text(book.author), + onTap: () => onTapped(book), + ) + ], + ), + ); + } +} + +class BookDetailsScreen extends StatelessWidget { + final Book book; + + BookDetailsScreen({ + @required this.book, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (book != null) ...[ + Text(book.title, style: Theme.of(context).textTheme.headline6), + Text(book.author, style: Theme.of(context).textTheme.subtitle1), + ], + ], + ), + ), + ); + } +} diff --git a/navigation_and_routing/lib/nav_2/router.dart b/navigation_and_routing/lib/nav_2/router.dart new file mode 100644 index 000000000..554ddea6e --- /dev/null +++ b/navigation_and_routing/lib/nav_2/router.dart @@ -0,0 +1,263 @@ +// Copyright 2020, the Flutter project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Full sample that shows a custom RouteInformationParser and RouterDelegate +/// parsing named routes and declaratively building the stack of pages for the +/// [Navigator]. +import 'package:flutter/material.dart'; + +void main() { + runApp(BooksApp()); +} + +class Book { + final String title; + final String author; + + Book(this.title, this.author); +} + +class BooksApp extends StatefulWidget { + @override + State createState() => _BooksAppState(); +} + +class _BooksAppState extends State { + BookRouterDelegate _routerDelegate = BookRouterDelegate(); + BookRouteInformationParser _routeInformationParser = + BookRouteInformationParser(); + + @override + Widget build(BuildContext context) { + return MaterialApp.router( + title: 'Books App', + routerDelegate: _routerDelegate, + routeInformationParser: _routeInformationParser, + ); + } +} + +class BookRouteInformationParser extends RouteInformationParser { + @override + Future parseRouteInformation( + RouteInformation routeInformation) async { + final uri = Uri.parse(routeInformation.location); + // Handle '/' + if (uri.pathSegments.length == 0) { + return BookRoutePath.home(); + } + + // Handle '/book/:id' + if (uri.pathSegments.length == 2) { + if (uri.pathSegments[0] != 'book') return BookRoutePath.unknown(); + var remaining = uri.pathSegments[1]; + var id = int.tryParse(remaining); + if (id == null) return BookRoutePath.unknown(); + return BookRoutePath.details(id); + } + + // Handle unknown routes + return BookRoutePath.unknown(); + } + + @override + RouteInformation restoreRouteInformation(BookRoutePath path) { + if (path.isUnknown) { + return RouteInformation(location: '/404'); + } + if (path.isHomePage) { + return RouteInformation(location: '/'); + } + if (path.isDetailsPage) { + return RouteInformation(location: '/book/${path.id}'); + } + return null; + } +} + +class BookRouterDelegate extends RouterDelegate + with ChangeNotifier, PopNavigatorRouterDelegateMixin { + final GlobalKey navigatorKey; + + Book _selectedBook; + bool show404 = false; + + List books = [ + Book('Stranger in a Strange Land', 'Robert A. Heinlein'), + Book('Foundation', 'Isaac Asimov'), + Book('Fahrenheit 451', 'Ray Bradbury'), + ]; + + BookRouterDelegate() : navigatorKey = GlobalKey(); + + BookRoutePath get currentConfiguration { + if (show404) { + return BookRoutePath.unknown(); + } + return _selectedBook == null + ? BookRoutePath.home() + : BookRoutePath.details(books.indexOf(_selectedBook)); + } + + @override + Widget build(BuildContext context) { + return Navigator( + key: navigatorKey, + pages: [ + MaterialPage( + key: ValueKey('BooksListPage'), + child: BooksListScreen( + books: books, + onTapped: _handleBookTapped, + ), + ), + if (show404) + MaterialPage(key: ValueKey('UnknownPage'), child: UnknownScreen()) + else if (_selectedBook != null) + BookDetailsPage(book: _selectedBook) + ], + onPopPage: (route, result) { + if (!route.didPop(result)) { + return false; + } + + // Update the list of pages by setting _selectedBook to null + _selectedBook = null; + show404 = false; + notifyListeners(); + + return true; + }, + ); + } + + @override + Future setNewRoutePath(BookRoutePath path) async { + if (path.isUnknown) { + _selectedBook = null; + show404 = true; + return; + } + + if (path.isDetailsPage) { + if (path.id < 0 || path.id > books.length - 1) { + show404 = true; + return; + } + + _selectedBook = books[path.id]; + } else { + _selectedBook = null; + } + + show404 = false; + } + + void _handleBookTapped(Book book) { + _selectedBook = book; + notifyListeners(); + } +} + +class BookDetailsPage extends Page { + final Book book; + + BookDetailsPage({ + this.book, + }) : super(key: ValueKey(book)); + + Route createRoute(BuildContext context) { + return MaterialPageRoute( + settings: this, + builder: (BuildContext context) { + return BookDetailsScreen(book: book); + }, + ); + } +} + +class BookRoutePath { + final int id; + final bool isUnknown; + + BookRoutePath.home() + : id = null, + isUnknown = false; + + BookRoutePath.details(this.id) : isUnknown = false; + + BookRoutePath.unknown() + : id = null, + isUnknown = true; + + bool get isHomePage => id == null; + + bool get isDetailsPage => id != null; +} + +class BooksListScreen extends StatelessWidget { + final List books; + final ValueChanged onTapped; + + BooksListScreen({ + @required this.books, + @required this.onTapped, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: ListView( + children: [ + for (var book in books) + ListTile( + title: Text(book.title), + subtitle: Text(book.author), + onTap: () => onTapped(book), + ) + ], + ), + ); + } +} + +class BookDetailsScreen extends StatelessWidget { + final Book book; + + BookDetailsScreen({ + @required this.book, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (book != null) ...[ + Text(book.title, style: Theme.of(context).textTheme.headline6), + Text(book.author, style: Theme.of(context).textTheme.subtitle1), + ], + ], + ), + ), + ); + } +} + +class UnknownScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Center( + child: Text('404!'), + ), + ); + } +} diff --git a/navigation_and_routing/lib/nav_2_advanced/nested_router.dart b/navigation_and_routing/lib/nav_2_advanced/nested_router.dart new file mode 100644 index 000000000..f4419fa10 --- /dev/null +++ b/navigation_and_routing/lib/nav_2_advanced/nested_router.dart @@ -0,0 +1,406 @@ +// Copyright 2020, the Flutter project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Shows two [RouterDelegate], one nested within the other. A +/// [BottomNavigationBar] can be used to select the route of the outer +/// RouterDelegate, and additional routes can be pushed onto the inner +/// RouterDelegate / Navigator. +import 'package:flutter/material.dart'; + +void main() { + runApp(NestedRouterDemo()); +} + +class Book { + final String title; + final String author; + + Book(this.title, this.author); +} + +class NestedRouterDemo extends StatefulWidget { + @override + _NestedRouterDemoState createState() => _NestedRouterDemoState(); +} + +class _NestedRouterDemoState extends State { + BookRouterDelegate _routerDelegate = BookRouterDelegate(); + BookRouteInformationParser _routeInformationParser = + BookRouteInformationParser(); + + @override + Widget build(BuildContext context) { + return MaterialApp.router( + title: 'Books App', + routerDelegate: _routerDelegate, + routeInformationParser: _routeInformationParser, + ); + } +} + +class BooksAppState extends ChangeNotifier { + int _selectedIndex; + + Book _selectedBook; + + final List books = [ + Book('Stranger in a Strange Land', 'Robert A. Heinlein'), + Book('Foundation', 'Isaac Asimov'), + Book('Fahrenheit 451', 'Ray Bradbury'), + ]; + + BooksAppState() : _selectedIndex = 0; + + int get selectedIndex => _selectedIndex; + + set selectedIndex(int idx) { + _selectedIndex = idx; + if (_selectedIndex == 1) { + // Remove this line if you want to keep the selected book when navigating + // between "settings" and "home" which book was selected when Settings is + // tapped. + selectedBook = null; + } + notifyListeners(); + } + + Book get selectedBook => _selectedBook; + + set selectedBook(Book book) { + _selectedBook = book; + notifyListeners(); + } + + int getSelectedBookById() { + if (!books.contains(_selectedBook)) return 0; + return books.indexOf(_selectedBook); + } + + void setSelectedBookById(int id) { + if (id < 0 || id > books.length - 1) { + return; + } + + _selectedBook = books[id]; + notifyListeners(); + } +} + +class BookRouteInformationParser extends RouteInformationParser { + @override + Future parseRouteInformation( + RouteInformation routeInformation) async { + final uri = Uri.parse(routeInformation.location); + + if (uri.pathSegments.isNotEmpty && uri.pathSegments.first == 'settings') { + return BooksSettingsPath(); + } else { + if (uri.pathSegments.length >= 2) { + if (uri.pathSegments[0] == 'book') { + return BooksDetailsPath(int.tryParse(uri.pathSegments[1])); + } + } + return BooksListPath(); + } + } + + @override + RouteInformation restoreRouteInformation(BookRoutePath configuration) { + if (configuration is BooksListPath) { + return RouteInformation(location: '/home'); + } + if (configuration is BooksSettingsPath) { + return RouteInformation(location: '/settings'); + } + if (configuration is BooksDetailsPath) { + return RouteInformation(location: '/book/${configuration.id}'); + } + return null; + } +} + +class BookRouterDelegate extends RouterDelegate + with ChangeNotifier, PopNavigatorRouterDelegateMixin { + final GlobalKey navigatorKey; + + BooksAppState appState = BooksAppState(); + + BookRouterDelegate() : navigatorKey = GlobalKey() { + appState.addListener(notifyListeners); + } + + BookRoutePath get currentConfiguration { + if (appState.selectedIndex == 1) { + return BooksSettingsPath(); + } else { + if (appState.selectedBook == null) { + return BooksListPath(); + } else { + return BooksDetailsPath(appState.getSelectedBookById()); + } + } + } + + @override + Widget build(BuildContext context) { + return Navigator( + key: navigatorKey, + pages: [ + MaterialPage( + child: AppShell(appState: appState), + ), + ], + onPopPage: (route, result) { + if (!route.didPop(result)) { + return false; + } + + if (appState.selectedBook != null) { + appState.selectedBook = null; + } + notifyListeners(); + return true; + }, + ); + } + + @override + Future setNewRoutePath(BookRoutePath path) async { + if (path is BooksListPath) { + appState.selectedIndex = 0; + appState.selectedBook = null; + } else if (path is BooksSettingsPath) { + appState.selectedIndex = 1; + } else if (path is BooksDetailsPath) { + appState.setSelectedBookById(path.id); + } + } +} + +// Routes +abstract class BookRoutePath {} + +class BooksListPath extends BookRoutePath {} + +class BooksSettingsPath extends BookRoutePath {} + +class BooksDetailsPath extends BookRoutePath { + final int id; + + BooksDetailsPath(this.id); +} + +// Widget that contains the AdaptiveNavigationScaffold +class AppShell extends StatefulWidget { + final BooksAppState appState; + + AppShell({ + @required this.appState, + }); + + @override + _AppShellState createState() => _AppShellState(); +} + +class _AppShellState extends State { + InnerRouterDelegate _routerDelegate; + ChildBackButtonDispatcher _backButtonDispatcher; + + void initState() { + super.initState(); + _routerDelegate = InnerRouterDelegate(widget.appState); + } + + @override + void didUpdateWidget(covariant AppShell oldWidget) { + super.didUpdateWidget(oldWidget); + _routerDelegate.appState = widget.appState; + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // Defer back button dispatching to the child router + _backButtonDispatcher = Router.of(context) + .backButtonDispatcher + .createChildBackButtonDispatcher(); + } + + @override + Widget build(BuildContext context) { + var appState = widget.appState; + + // Claim priority, If there are parallel sub router, you will need + // to pick which one should take priority; + _backButtonDispatcher.takePriority(); + + return Scaffold( + appBar: AppBar(), + body: Router( + routerDelegate: _routerDelegate, + backButtonDispatcher: _backButtonDispatcher, + ), + bottomNavigationBar: BottomNavigationBar( + items: [ + BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'), + BottomNavigationBarItem( + icon: Icon(Icons.settings), label: 'Settings'), + ], + currentIndex: appState.selectedIndex, + onTap: (newIndex) { + appState.selectedIndex = newIndex; + }, + ), + ); + } +} + +class InnerRouterDelegate extends RouterDelegate + with ChangeNotifier, PopNavigatorRouterDelegateMixin { + final GlobalKey navigatorKey = GlobalKey(); + BooksAppState get appState => _appState; + BooksAppState _appState; + set appState(BooksAppState value) { + if (value == _appState) { + return; + } + _appState = value; + notifyListeners(); + } + + InnerRouterDelegate(this._appState); + + @override + Widget build(BuildContext context) { + return Navigator( + key: navigatorKey, + pages: [ + if (appState.selectedIndex == 0) ...[ + FadeAnimationPage( + child: BooksListScreen( + books: appState.books, + onTapped: _handleBookTapped, + ), + key: ValueKey('BooksListPage'), + ), + if (appState.selectedBook != null) + MaterialPage( + key: ValueKey(appState.selectedBook), + child: BookDetailsScreen(book: appState.selectedBook), + ), + ] else + FadeAnimationPage( + child: SettingsScreen(), + key: ValueKey('SettingsPage'), + ), + ], + onPopPage: (route, result) { + appState.selectedBook = null; + notifyListeners(); + return route.didPop(result); + }, + ); + } + + @override + Future setNewRoutePath(BookRoutePath path) async { + // This is not required for inner router delegate because it does not + // parse route + assert(false); + } + + void _handleBookTapped(Book book) { + appState.selectedBook = book; + notifyListeners(); + } +} + +class FadeAnimationPage extends Page { + final Widget child; + + FadeAnimationPage({Key key, this.child}) : super(key: key); + + Route createRoute(BuildContext context) { + return PageRouteBuilder( + settings: this, + pageBuilder: (context, animation, animation2) { + var curveTween = CurveTween(curve: Curves.easeIn); + return FadeTransition( + opacity: animation.drive(curveTween), + child: child, + ); + }, + ); + } +} + +// Screens +class BooksListScreen extends StatelessWidget { + final List books; + final ValueChanged onTapped; + + BooksListScreen({ + @required this.books, + @required this.onTapped, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: ListView( + children: [ + for (var book in books) + ListTile( + title: Text(book.title), + subtitle: Text(book.author), + onTap: () => onTapped(book), + ) + ], + ), + ); + } +} + +class BookDetailsScreen extends StatelessWidget { + final Book book; + + BookDetailsScreen({ + @required this.book, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + FlatButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text('Back'), + ), + if (book != null) ...[ + Text(book.title, style: Theme.of(context).textTheme.headline6), + Text(book.author, style: Theme.of(context).textTheme.subtitle1), + ], + ], + ), + ), + ); + } +} + +class SettingsScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Text('Settings screen'), + ), + ); + } +} diff --git a/navigation_and_routing/lib/nav_2_advanced/transition_delegate.dart b/navigation_and_routing/lib/nav_2_advanced/transition_delegate.dart new file mode 100644 index 000000000..9329a6b5b --- /dev/null +++ b/navigation_and_routing/lib/nav_2_advanced/transition_delegate.dart @@ -0,0 +1,244 @@ +// Copyright 2020, the Flutter project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Shows how a custom TransitionDelegate can be used to customized when +/// transition animations are shown. (For example, [when two routes are popped +/// off the stack](https://github.com/flutter/flutter/issues/12146), however the +/// default TransitionDelegate will handle this if you are using Navigator 2.0) +import 'package:flutter/material.dart'; + +void main() { + runApp(BooksApp()); +} + +class Book { + final String title; + final String author; + + Book(this.title, this.author); +} + +class BooksApp extends StatefulWidget { + @override + State createState() => _BooksAppState(); +} + +class _BooksAppState extends State { + BookRouterDelegate _routerDelegate = BookRouterDelegate(); + BookRouteInformationParser _routeInformationParser = + BookRouteInformationParser(); + + @override + Widget build(BuildContext context) { + return MaterialApp.router( + title: 'Books App', + routerDelegate: _routerDelegate, + routeInformationParser: _routeInformationParser, + ); + } +} + +class BookRouteInformationParser extends RouteInformationParser { + @override + Future parseRouteInformation( + RouteInformation routeInformation) async { + final uri = Uri.parse(routeInformation.location); + + if (uri.pathSegments.length >= 2) { + var remaining = uri.pathSegments[1]; + return BookRoutePath.details(int.tryParse(remaining)); + } else { + return BookRoutePath.home(); + } + } + + @override + RouteInformation restoreRouteInformation(BookRoutePath path) { + if (path.isHomePage) { + return RouteInformation(location: '/'); + } + if (path.isDetailsPage) { + return RouteInformation(location: '/book/${path.id}'); + } + return null; + } +} + +class BookRouterDelegate extends RouterDelegate + with ChangeNotifier, PopNavigatorRouterDelegateMixin { + final GlobalKey navigatorKey; + + Book _selectedBook; + + List books = [ + Book('Stranger in a Strange Land', 'Robert A. Heinlein'), + Book('Foundation', 'Isaac Asimov'), + Book('Fahrenheit 451', 'Ray Bradbury'), + ]; + + BookRouterDelegate() : navigatorKey = GlobalKey(); + + BookRoutePath get currentConfiguration => _selectedBook == null + ? BookRoutePath.home() + : BookRoutePath.details(books.indexOf(_selectedBook)); + + @override + Widget build(BuildContext context) { + return Navigator( + key: navigatorKey, + transitionDelegate: NoAnimationTransitionDelegate(), + pages: [ + MaterialPage( + key: ValueKey('BooksListPage'), + child: BooksListScreen( + books: books, + onTapped: _handleBookTapped, + ), + ), + if (_selectedBook != null) BookDetailsPage(book: _selectedBook) + ], + onPopPage: (route, result) { + if (!route.didPop(result)) { + return false; + } + + // Update the list of pages by setting _selectedBook to null + _selectedBook = null; + notifyListeners(); + + return true; + }, + ); + } + + @override + Future setNewRoutePath(BookRoutePath path) async { + if (path.isDetailsPage) { + _selectedBook = books[path.id]; + } + } + + void _handleBookTapped(Book book) { + _selectedBook = book; + notifyListeners(); + } +} + +class BookDetailsPage extends Page { + final Book book; + + BookDetailsPage({ + this.book, + }) : super(key: ValueKey(book)); + + Route createRoute(BuildContext context) { + return MaterialPageRoute( + settings: this, + builder: (BuildContext context) { + return BookDetailsScreen(book: book); + }, + ); + } +} + +class BookRoutePath { + final int id; + + BookRoutePath.home() : id = null; + + BookRoutePath.details(this.id); + + bool get isHomePage => id == null; + + bool get isDetailsPage => id != null; +} + +class BooksListScreen extends StatelessWidget { + final List books; + final ValueChanged onTapped; + + BooksListScreen({ + @required this.books, + @required this.onTapped, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: ListView( + children: [ + for (var book in books) + ListTile( + title: Text(book.title), + subtitle: Text(book.author), + onTap: () => onTapped(book), + ) + ], + ), + ); + } +} + +class BookDetailsScreen extends StatelessWidget { + final Book book; + + BookDetailsScreen({ + @required this.book, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (book != null) ...[ + Text(book.title, style: Theme.of(context).textTheme.headline6), + Text(book.author, style: Theme.of(context).textTheme.subtitle1), + ], + ], + ), + ), + ); + } +} + +class NoAnimationTransitionDelegate extends TransitionDelegate { + @override + Iterable resolve({ + List newPageRouteHistory, + Map + locationToExitingPageRoute, + Map> + pageRouteToPagelessRoutes, + }) { + final results = []; + + for (final pageRoute in newPageRouteHistory) { + if (pageRoute.isWaitingForEnteringDecision) { + pageRoute.markForAdd(); + } + results.add(pageRoute); + } + + for (final exitingPageRoute in locationToExitingPageRoute.values) { + if (exitingPageRoute.isWaitingForExitingDecision) { + exitingPageRoute.markForRemove(); + final pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute]; + if (pagelessRoutes != null) { + for (final pagelessRoute in pagelessRoutes) { + pagelessRoute.markForRemove(); + } + } + } + + results.add(exitingPageRoute); + } + return results; + } +} diff --git a/navigation_and_routing/pubspec.lock b/navigation_and_routing/pubspec.lock new file mode 100644 index 000000000..f628010e7 --- /dev/null +++ b/navigation_and_routing/pubspec.lock @@ -0,0 +1,153 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.5.0-nullsafety.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0-nullsafety.1" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0-nullsafety.3" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0-nullsafety.1" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0-nullsafety.1" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.15.0-nullsafety.3" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0-nullsafety.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.10-nullsafety.1" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0-nullsafety.3" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0-nullsafety.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0-nullsafety.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0-nullsafety.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0-nullsafety.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0-nullsafety.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0-nullsafety.1" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.19-nullsafety.2" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0-nullsafety.3" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0-nullsafety.3" +sdks: + dart: ">=2.10.0-110 <2.11.0" diff --git a/navigation_and_routing/pubspec.yaml b/navigation_and_routing/pubspec.yaml new file mode 100644 index 000000000..125676589 --- /dev/null +++ b/navigation_and_routing/pubspec.yaml @@ -0,0 +1,20 @@ +name: navigation_and_routing +description: Navigation and routing samples +publish_to: 'none' + +version: 1.0.0+1 + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + cupertino_icons: ^1.0.0 + +dev_dependencies: + flutter_test: + sdk: flutter + +flutter: + uses-material-design: true