diff --git a/packages/firebase_introduction_repository/.flutter-plugins b/packages/firebase_introduction_repository/.flutter-plugins new file mode 100644 index 0000000..4892433 --- /dev/null +++ b/packages/firebase_introduction_repository/.flutter-plugins @@ -0,0 +1,8 @@ +# This is a generated file; do not edit or check into version control. +cloud_firestore=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/cloud_firestore-5.6.3/ +cloud_firestore_web=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/cloud_firestore_web-4.4.3/ +device_info_plus=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/device_info_plus-11.3.0/ +firebase_auth=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_auth-5.4.2/ +firebase_auth_web=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_auth_web-5.13.8/ +firebase_core=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_core-3.11.0/ +firebase_core_web=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_core_web-2.20.0/ diff --git a/packages/firebase_introduction_repository/.flutter-plugins-dependencies b/packages/firebase_introduction_repository/.flutter-plugins-dependencies new file mode 100644 index 0000000..9ff0764 --- /dev/null +++ b/packages/firebase_introduction_repository/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/cloud_firestore-5.6.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/device_info_plus-11.3.0/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_auth-5.4.2/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_core-3.11.0/","native_build":true,"dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/cloud_firestore-5.6.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/device_info_plus-11.3.0/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_auth-5.4.2/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_core-3.11.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"cloud_firestore","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/cloud_firestore-5.6.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/device_info_plus-11.3.0/","native_build":true,"dependencies":[]},{"name":"firebase_auth","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_auth-5.4.2/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_core-3.11.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/device_info_plus-11.3.0/","native_build":false,"dependencies":[]}],"windows":[{"name":"cloud_firestore","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/cloud_firestore-5.6.3/","native_build":true,"dependencies":["firebase_core"]},{"name":"device_info_plus","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/device_info_plus-11.3.0/","native_build":false,"dependencies":[]},{"name":"firebase_auth","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_auth-5.4.2/","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_core-3.11.0/","native_build":true,"dependencies":[]}],"web":[{"name":"cloud_firestore_web","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/cloud_firestore_web-4.4.3/","dependencies":["firebase_core_web"]},{"name":"device_info_plus","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/device_info_plus-11.3.0/","dependencies":[]},{"name":"firebase_auth_web","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_auth_web-5.13.8/","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/firebase_core_web-2.20.0/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["cloud_firestore_web","firebase_core"]},{"name":"cloud_firestore_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"device_info_plus","dependencies":[]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]}],"date_created":"2025-02-18 11:25:55.718721","version":"3.24.3","swift_package_manager_enabled":false} \ No newline at end of file diff --git a/packages/flutter_introduction_service/.gitignore b/packages/firebase_introduction_repository/.gitignore similarity index 94% rename from packages/flutter_introduction_service/.gitignore rename to packages/firebase_introduction_repository/.gitignore index 35b14c4..ac5aa98 100644 --- a/packages/flutter_introduction_service/.gitignore +++ b/packages/firebase_introduction_repository/.gitignore @@ -19,14 +19,11 @@ migrate_working_dir/ # 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/ +#.vscode/ # Flutter/Dart/Pub related # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. /pubspec.lock **/doc/api/ .dart_tool/ -.packages build/ - -.metadata diff --git a/packages/flutter_introduction_firebase/analysis_options.yaml b/packages/firebase_introduction_repository/analysis_options.yaml similarity index 98% rename from packages/flutter_introduction_firebase/analysis_options.yaml rename to packages/firebase_introduction_repository/analysis_options.yaml index 8ea00ce..31b4b51 100644 --- a/packages/flutter_introduction_firebase/analysis_options.yaml +++ b/packages/firebase_introduction_repository/analysis_options.yaml @@ -4,6 +4,6 @@ include: package:flutter_iconica_analysis/analysis_options.yaml analyzer: exclude: - + linter: rules: diff --git a/packages/firebase_introduction_repository/lib/firebase_introduction_repository.dart b/packages/firebase_introduction_repository/lib/firebase_introduction_repository.dart new file mode 100644 index 0000000..0000392 --- /dev/null +++ b/packages/firebase_introduction_repository/lib/firebase_introduction_repository.dart @@ -0,0 +1,4 @@ +/// +library firebase_introduction_repository; + +export "src/firebase_introduction_repository.dart"; diff --git a/packages/firebase_introduction_repository/lib/src/firebase_introduction_repository.dart b/packages/firebase_introduction_repository/lib/src/firebase_introduction_repository.dart new file mode 100644 index 0000000..f2ebbf4 --- /dev/null +++ b/packages/firebase_introduction_repository/lib/src/firebase_introduction_repository.dart @@ -0,0 +1,86 @@ +import "dart:io"; + +import "package:cloud_firestore/cloud_firestore.dart"; +import "package:device_info_plus/device_info_plus.dart"; +import "package:firebase_auth/firebase_auth.dart"; +import "package:introduction_repository_interface/introduction_repository_interface.dart"; + +class FirebaseIntroductionRepository + implements IntroductionRepositoryInterface { + final _introductionCollection = FirebaseFirestore.instance + .collection("flutter_introduction") + .doc("flutter_introduction"); + + @override + Future> fetchIntroductionPages() async { + try { + var introductionPagesData = await _introductionCollection + .collection("pages") + .withConverter( + fromFirestore: (snapshot, _) => IntroductionPageData.fromJson( + snapshot.data()!, + ), + toFirestore: (model, _) => model.toJson(), + ) + .get(); + var introductionPages = + introductionPagesData.docs.map((e) => e.data()).toList(); + + introductionPages.sort((a, b) => a.id.compareTo(b.id)); + return introductionPages; + } on Exception catch (_) { + throw Exception(); + } + } + + @override + Future setCompleted({bool value = true}) async { + try { + await FirebaseAuth.instance.signInAnonymously(); + var deviceId = await _getDeviceId(); + if (deviceId == null) { + throw Exception("Failed to get device id"); + } + await _introductionCollection.collection("devices").doc(deviceId).set({ + "introduction_completed": value, + }); + } catch (e) { + throw Exception("Failed to set introduction completed: $e"); + } + } + + @override + Future shouldShow() async { + try { + await FirebaseAuth.instance.signInAnonymously(); + var deviceId = await _getDeviceId(); + if (deviceId == null) { + throw Exception("Failed to get device id"); + } + var introductionCompleted = await _introductionCollection + .collection("devices") + .doc(deviceId) + .get(); + if (!introductionCompleted.exists) { + return true; + } + // ignore: avoid_dynamic_calls + return !introductionCompleted.data()!["introduction_completed"]; + } on Exception catch (_) { + throw Exception(); + } + } + + Future _getDeviceId() async { + var deviceInfo = DeviceInfoPlugin(); + + if (Platform.isAndroid) { + var androidInfo = await deviceInfo.androidInfo; + return androidInfo.id; + } else if (Platform.isIOS) { + var iosInfo = await deviceInfo.iosInfo; + return iosInfo.identifierForVendor; + } + return null; + } +} diff --git a/packages/firebase_introduction_repository/pubspec.yaml b/packages/firebase_introduction_repository/pubspec.yaml new file mode 100644 index 0000000..7b8d801 --- /dev/null +++ b/packages/firebase_introduction_repository/pubspec.yaml @@ -0,0 +1,23 @@ +name: firebase_introduction_repository +description: "A new Flutter package project." +version: 0.0.1 +publish_to: none + +environment: + sdk: ^3.5.3 + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + firebase_auth: ^5.4.2 + cloud_firestore: ^5.6.3 + introduction_repository_interface: + path: ../introduction_repository_interface + device_info_plus: ^11.3.0 + +dev_dependencies: + flutter_iconica_analysis: + git: + url: https://github.com/Iconica-Development/flutter_iconica_analysis + ref: 7.0.0 diff --git a/packages/flutter_introduction/.gitignore b/packages/flutter_introduction/.gitignore index bffd2c4..ac5aa98 100644 --- a/packages/flutter_introduction/.gitignore +++ b/packages/flutter_introduction/.gitignore @@ -1,7 +1,3 @@ -# SPDX-FileCopyrightText: 2022 Iconica -# -# SPDX-License-Identifier: GPL-3.0-or-later - # Miscellaneous *.class *.log @@ -23,19 +19,11 @@ migrate_working_dir/ # 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/ +#.vscode/ # Flutter/Dart/Pub related # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -# /pubspec.lock +/pubspec.lock **/doc/api/ .dart_tool/ -.packages build/ -.flutter-plugins-dependencies -.flutter-plugins -.metadata - -pubspec.lock - -pubspec_overrides.yaml diff --git a/packages/flutter_introduction/CHANGELOG.md b/packages/flutter_introduction/CHANGELOG.md deleted file mode 120000 index 699cc9e..0000000 --- a/packages/flutter_introduction/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -../../CHANGELOG.md \ No newline at end of file diff --git a/packages/flutter_introduction/LICENSE b/packages/flutter_introduction/LICENSE deleted file mode 120000 index 30cff74..0000000 --- a/packages/flutter_introduction/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE \ No newline at end of file diff --git a/packages/flutter_introduction/README.md b/packages/flutter_introduction/README.md deleted file mode 120000 index fe84005..0000000 --- a/packages/flutter_introduction/README.md +++ /dev/null @@ -1 +0,0 @@ -../../README.md \ No newline at end of file diff --git a/packages/flutter_introduction/analysis_options.yaml b/packages/flutter_introduction/analysis_options.yaml index 8ea00ce..31b4b51 100644 --- a/packages/flutter_introduction/analysis_options.yaml +++ b/packages/flutter_introduction/analysis_options.yaml @@ -4,6 +4,6 @@ include: package:flutter_iconica_analysis/analysis_options.yaml analyzer: exclude: - + linter: rules: diff --git a/packages/flutter_introduction_widget/assets/first.png b/packages/flutter_introduction/assets/first.png similarity index 100% rename from packages/flutter_introduction_widget/assets/first.png rename to packages/flutter_introduction/assets/first.png diff --git a/packages/flutter_introduction_widget/assets/second.png b/packages/flutter_introduction/assets/second.png similarity index 100% rename from packages/flutter_introduction_widget/assets/second.png rename to packages/flutter_introduction/assets/second.png diff --git a/packages/flutter_introduction_widget/assets/third.png b/packages/flutter_introduction/assets/third.png similarity index 100% rename from packages/flutter_introduction_widget/assets/third.png rename to packages/flutter_introduction/assets/third.png diff --git a/packages/flutter_introduction/example/.gitignore b/packages/flutter_introduction/example/.gitignore index 24476c5..29a3a50 100644 --- a/packages/flutter_introduction/example/.gitignore +++ b/packages/flutter_introduction/example/.gitignore @@ -27,7 +27,6 @@ migrate_working_dir/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies -.packages .pub-cache/ .pub/ /build/ diff --git a/packages/flutter_introduction/example/README.md b/packages/flutter_introduction/example/README.md index 8b13789..2b3fce4 100644 --- a/packages/flutter_introduction/example/README.md +++ b/packages/flutter_introduction/example/README.md @@ -1 +1,16 @@ +# example +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/flutter_introduction/example/analysis_options.yaml b/packages/flutter_introduction/example/analysis_options.yaml index 8ea00ce..0d29021 100644 --- a/packages/flutter_introduction/example/analysis_options.yaml +++ b/packages/flutter_introduction/example/analysis_options.yaml @@ -1,9 +1,28 @@ -include: package:flutter_iconica_analysis/analysis_options.yaml +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. -# Possible to overwrite the rules from the package +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml -analyzer: - exclude: - linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/packages/flutter_introduction/example/fonts/Avenir-Regular.ttf b/packages/flutter_introduction/example/fonts/Avenir-Regular.ttf new file mode 100644 index 0000000..7463844 Binary files /dev/null and b/packages/flutter_introduction/example/fonts/Avenir-Regular.ttf differ diff --git a/packages/flutter_introduction/example/fonts/Merriweather-Regular.ttf b/packages/flutter_introduction/example/fonts/Merriweather-Regular.ttf new file mode 100644 index 0000000..3fecc77 Binary files /dev/null and b/packages/flutter_introduction/example/fonts/Merriweather-Regular.ttf differ diff --git a/packages/flutter_introduction/example/ios/.gitignore b/packages/flutter_introduction/example/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/packages/flutter_introduction/example/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.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/ephemeral/ +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/packages/flutter_introduction/example/ios/Flutter/AppFrameworkInfo.plist b/packages/flutter_introduction/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..7c56964 --- /dev/null +++ b/packages/flutter_introduction/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/packages/flutter_introduction/example/ios/Flutter/Debug.xcconfig b/packages/flutter_introduction/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/packages/flutter_introduction/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/flutter_introduction/example/ios/Flutter/Release.xcconfig b/packages/flutter_introduction/example/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/packages/flutter_introduction/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/flutter_introduction/example/ios/Podfile b/packages/flutter_introduction/example/ios/Podfile new file mode 100644 index 0000000..d97f17e --- /dev/null +++ b/packages/flutter_introduction/example/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/flutter_introduction/example/ios/Podfile.lock b/packages/flutter_introduction/example/ios/Podfile.lock new file mode 100644 index 0000000..9ff64a9 --- /dev/null +++ b/packages/flutter_introduction/example/ios/Podfile.lock @@ -0,0 +1,23 @@ +PODS: + - Flutter (1.0.0) + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - Flutter (from `Flutter`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + +SPEC CHECKSUMS: + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + +PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 + +COCOAPODS: 1.16.2 diff --git a/packages/flutter_introduction/example/ios/Runner.xcodeproj/project.pbxproj b/packages/flutter_introduction/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d92869a --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,731 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 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 */; }; + AAC0EBC3B2AED5B0E05C5B4E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A6279E8D6C10D87A207346A /* Pods_Runner.framework */; }; + EEC7FB96545FA97CD379A6AD /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 395AAD3A2E008ED809D166E5 /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy 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 */ + 0A6279E8D6C10D87A207346A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 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 = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 395AAD3A2E008ED809D166E5 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 397FD6F47DA357A8D69AF1C6 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 3B2D76FBD9CF3BD3A5E0FA45 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 61AE2D460E19D6A0245EFA0F /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; 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 = ""; }; + 9A2BB7986837B8FCF654D3BF /* 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 = ""; }; + CFE1C62C5CF2914467393A95 /* 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 = ""; }; + E0AB649FB19F5AAA6CE2A1C4 /* 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 = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7105146EAB56D623D73CCB82 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EEC7FB96545FA97CD379A6AD /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AAC0EBC3B2AED5B0E05C5B4E /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0CCA99B31EB592B821B9B9B7 /* Pods */ = { + isa = PBXGroup; + children = ( + E0AB649FB19F5AAA6CE2A1C4 /* Pods-Runner.debug.xcconfig */, + CFE1C62C5CF2914467393A95 /* Pods-Runner.release.xcconfig */, + 9A2BB7986837B8FCF654D3BF /* Pods-Runner.profile.xcconfig */, + 3B2D76FBD9CF3BD3A5E0FA45 /* Pods-RunnerTests.debug.xcconfig */, + 397FD6F47DA357A8D69AF1C6 /* Pods-RunnerTests.release.xcconfig */, + 61AE2D460E19D6A0245EFA0F /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 545585EA07D653BF26DC9A95 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 0A6279E8D6C10D87A207346A /* Pods_Runner.framework */, + 395AAD3A2E008ED809D166E5 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 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 */, + 331C8082294A63A400263BE5 /* RunnerTests */, + 0CCA99B31EB592B821B9B9B7 /* Pods */, + 545585EA07D653BF26DC9A95 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + 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 */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + B46DFC93FEEE82B438CEFD5D /* [CP] Check Pods Manifest.lock */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + 7105146EAB56D623D73CCB82 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + EF7A156F27275134CE16972E /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + AAD28D6AADDD0350DB09B76E /* [CP] Embed Pods Frameworks */, + ); + 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 = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 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 */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 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; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + 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; + alwaysOutOfDate = 1; + 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"; + }; + AAD28D6AADDD0350DB09B76E /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + B46DFC93FEEE82B438CEFD5D /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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"; + showEnvVarsInLog = 0; + }; + EF7A156F27275134CE16972E /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency 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; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + 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; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + 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 = 12.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)"; + DEVELOPMENT_TEAM = 36XLC98BCM; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3B2D76FBD9CF3BD3A5E0FA45 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 397FD6F47DA357A8D69AF1C6 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 61AE2D460E19D6A0245EFA0F /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + 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; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + 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 = 12.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; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + 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; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + 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 = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + 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)"; + DEVELOPMENT_TEAM = 36XLC98BCM; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + 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)"; + DEVELOPMENT_TEAM = 36XLC98BCM; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + 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 */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 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/packages/flutter_introduction/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/flutter_introduction/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/flutter_introduction/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/flutter_introduction/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/flutter_introduction/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/flutter_introduction/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/flutter_introduction/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/flutter_introduction/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..8e3ca5d --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/flutter_introduction/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/flutter_introduction/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/flutter_introduction/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/flutter_introduction/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/flutter_introduction/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/flutter_introduction/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/flutter_introduction/example/ios/Runner/AppDelegate.swift b/packages/flutter_introduction/example/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..6266644 --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Flutter +import UIKit + +@main +@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/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/packages/flutter_introduction/example/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/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..7353c41 Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..6ed2d93 Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cd7b00 Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..fe73094 Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..321773c Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..502f463 Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..e9f5fea Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..84ac32a Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..8953cba Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..0467bf1 Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/packages/flutter_introduction/example/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/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/flutter_introduction/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/packages/flutter_introduction/example/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/packages/flutter_introduction/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/flutter_introduction/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/flutter_introduction/example/ios/Runner/Base.lproj/Main.storyboard b/packages/flutter_introduction/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/flutter_introduction/example/ios/Runner/Info.plist b/packages/flutter_introduction/example/ios/Runner/Info.plist new file mode 100644 index 0000000..5458fc4 --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Example + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + example + 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 + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/packages/flutter_introduction/example/ios/Runner/Runner-Bridging-Header.h b/packages/flutter_introduction/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/packages/flutter_introduction/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/flutter_introduction/example/ios/RunnerTests/RunnerTests.swift b/packages/flutter_introduction/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/packages/flutter_introduction/example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/packages/flutter_introduction/example/lib/main.dart b/packages/flutter_introduction/example/lib/main.dart index 2711f5b..b51e124 100644 --- a/packages/flutter_introduction/example/lib/main.dart +++ b/packages/flutter_introduction/example/lib/main.dart @@ -1,12 +1,8 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - +import 'package:example/theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_introduction/flutter_introduction.dart'; -import 'package:flutter_introduction_shared_preferences/flutter_introduction_shared_preferences.dart'; -void main() { +void main(List args) { runApp(const MyApp()); } @@ -14,79 +10,23 @@ class MyApp extends StatelessWidget { const MyApp({super.key}); @override - Widget build(BuildContext context) => MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: const MyHomePage(), - ); + Widget build(BuildContext context) { + return MaterialApp( + theme: theme, + home: const Introduction(), + ); + } } -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key}); +class Introduction extends StatelessWidget { + const Introduction({super.key}); @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - IntroductionService service = - IntroductionService(SharedPreferencesIntroductionDataProvider()); - - @override - Widget build(BuildContext context) => Scaffold( - body: Introduction( - options: IntroductionOptions( - pages: (context) => [ - const IntroductionPage( - title: Text('First page'), - text: Text('Wow a page'), - graphic: FlutterLogo(), - ), - const IntroductionPage( - title: Text('Second page'), - text: Text('Another page'), - graphic: FlutterLogo(), - ), - const IntroductionPage( - title: Text('Third page'), - text: Text('The final page of this app'), - graphic: FlutterLogo(), - ), - ], - introductionTranslations: const IntroductionTranslations( - skipButton: 'Skip it!', - nextButton: 'Next', - previousButton: 'Previous', - finishButton: 'To the app!', - ), - tapEnabled: true, - displayMode: IntroductionDisplayMode.multiPageHorizontal, - buttonMode: IntroductionScreenButtonMode.text, - indicatorMode: IndicatorMode.dash, - skippable: true, - buttonBuilder: (context, onPressed, child, type) => - ElevatedButton(onPressed: onPressed, child: child), - ), - service: service, - navigateTo: () async { - await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const Home(), - ), - ); - }, - child: const Home(), - ), - ); -} - -class Home extends StatelessWidget { - const Home({ - super.key, - }); - - @override - Widget build(BuildContext context) => Container(); + Widget build(BuildContext context) { + return IntroductionScreen( + onDone: () { + debugPrint("done"); + }, + ); + } } diff --git a/packages/flutter_introduction/example/lib/theme.dart b/packages/flutter_introduction/example/lib/theme.dart new file mode 100644 index 0000000..c253481 --- /dev/null +++ b/packages/flutter_introduction/example/lib/theme.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; + +const Color primaryColor = Color(0xFF71C6D1); + +ThemeData theme = ThemeData( + useMaterial3: false, + scaffoldBackgroundColor: const Color(0xFFFAF9F6), + fontFamily: "Merriweather", + textTheme: const TextTheme( + headlineLarge: TextStyle( + fontWeight: FontWeight.w900, + fontSize: 24, + color: Color(0xFF71C6D1), + ), + bodyMedium: TextStyle( + fontFamily: "Avenir", + fontWeight: FontWeight.w400, + fontSize: 16, + color: Colors.black, + ), + ), +); diff --git a/packages/flutter_introduction/example/pubspec.yaml b/packages/flutter_introduction/example/pubspec.yaml index 40b46dc..ab19276 100644 --- a/packages/flutter_introduction/example/pubspec.yaml +++ b/packages/flutter_introduction/example/pubspec.yaml @@ -1,31 +1,33 @@ name: example -description: A new Flutter project. +description: "A new Flutter project." -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +publish_to: "none" version: 1.0.0+1 environment: - sdk: '>=2.18.0 <3.0.0' - + sdk: ^3.5.3 dependencies: flutter: sdk: flutter - - cupertino_icons: ^1.0.2 - flutter_introduction: + flutter_introduction: path: ../ - flutter_introduction_shared_preferences: - path: ../../flutter_introduction_shared_preferences - + shared_preferences_introduction_repository: + path: ../../shared_preferences_introduction_repository dev_dependencies: - flutter_test: - sdk: flutter - flutter_iconica_analysis: - git: - url: https://github.com/Iconica-Development/flutter_iconica_analysis - ref: 6.0.0 + flutter_lints: ^4.0.0 flutter: uses-material-design: true + + assets: + - ../assets/ + + fonts: + - family: Merriweather + fonts: + - asset: fonts/Merriweather-Regular.ttf + - family: Avenir + fonts: + - asset: fonts/Avenir-Regular.ttf diff --git a/packages/flutter_introduction/lib/flutter_introduction.dart b/packages/flutter_introduction/lib/flutter_introduction.dart index d90c229..4f5e7f4 100644 --- a/packages/flutter_introduction/lib/flutter_introduction.dart +++ b/packages/flutter_introduction/lib/flutter_introduction.dart @@ -1,82 +1,25 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause +/// +// ignore_for_file: directives_ordering -import 'package:flutter/material.dart'; -import 'package:flutter_introduction_service/flutter_introduction_service.dart'; -import 'package:flutter_introduction_widget/flutter_introduction_widget.dart'; +library flutter_introduction; -export 'package:flutter_introduction_service/flutter_introduction_service.dart'; -export 'package:flutter_introduction_widget/flutter_introduction_widget.dart'; +/// screens +export "src/screens/introduction_screen.dart"; -class Introduction extends StatefulWidget { - const Introduction({ - required this.navigateTo, - required this.options, - this.child, - this.physics, - this.service, - super.key, - }); +/// widgets +export "src/widgets/introduction_page.dart"; +export "src/widgets/button.dart"; +export "src/widgets/dot_indicator.dart"; +export "src/widgets/dash_indicator.dart"; - /// Callback function to navigate to the next screen. - final VoidCallback navigateTo; +/// enums +export "src/enums/introduction_layout_style.dart"; +export "src/enums/indicator_mode.dart"; +export "src/enums/introduction_screen_mode.dart"; - /// The introduction service to use. - final IntroductionService? service; +/// config +export "src/config/introduction_options.dart"; +export "src/config/introduction_translations.dart"; +export "src/config/introduction_theme.dart"; - /// Options for configuring the introduction screen. - final IntroductionOptions options; - - /// The scrolling physics for the introduction screen. - final ScrollPhysics? physics; - - /// Child widget to display. - final Widget? child; - - @override - State createState() => _IntroductionState(); -} - -class _IntroductionState extends State { - late IntroductionService _service; - - @override - void initState() { - super.initState(); - if (widget.service == null) { - _service = IntroductionService(); - } else { - _service = widget.service!; - } - } - - @override - Widget build(BuildContext context) => FutureBuilder( - // ignore: discarded_futures - future: _service.shouldShow(), - builder: (context, snapshot) { - if (snapshot.data == null || - snapshot.data! || - widget.options.mode == IntroductionScreenMode.showAlways) { - return IntroductionScreen( - options: widget.options, - onComplete: () async { - await _service.onComplete(); - widget.navigateTo(); - }, - physics: widget.physics, - onSkip: () async { - await _service.onComplete(); - widget.navigateTo(); - }, - ); - } else { - WidgetsBinding.instance.addPostFrameCallback((_) { - widget.navigateTo(); - }); - return widget.child ?? const CircularProgressIndicator(); - } - }, - ); -} +export "package:introduction_repository_interface/introduction_repository_interface.dart"; diff --git a/packages/flutter_introduction/lib/src/config/introduction_options.dart b/packages/flutter_introduction/lib/src/config/introduction_options.dart new file mode 100644 index 0000000..fdf7b2d --- /dev/null +++ b/packages/flutter_introduction/lib/src/config/introduction_options.dart @@ -0,0 +1,50 @@ +import "package:flutter/material.dart"; +import "package:flutter_introduction/flutter_introduction.dart"; + +class IntroductionOptions { + const IntroductionOptions({ + this.indicatorMode = IndicatorMode.dot, + this.layoutStyle = IntroductionLayoutStyle.imageBottom, + this.introductionScreenMode = IntroductionScreenMode.showOnce, + this.indicatorBuilder, + this.introductionPages = const [ + IntroductionPageData( + id: 1, + title: "welcome to iconinstagram", + description: "Welcome to the world of iconinstagram, where creativity" + " knows no bounds and connections are made through" + " captivating visuals.", + graphic: "packages/flutter_introduction/assets/first.png", + ), + IntroductionPageData( + id: 2, + title: "discover iconinstagram", + description: "Dive into the vibrant world of iconinstagram and" + " discover endless possibilities. From stunning" + " photography to engaging videos, iconinstagram" + " offers a diverse range of content to explore.", + graphic: "packages/flutter_introduction/assets/second.png", + ), + IntroductionPageData( + id: 3, + title: "elevate your experience", + description: "Whether promoting your business, or connecting" + " with friends and family, iconinstagram provides" + " the tools and platform to make your voice heard.", + graphic: "packages/flutter_introduction/assets/third.png", + ), + ], + }); + + final IndicatorMode indicatorMode; + + final IntroductionLayoutStyle layoutStyle; + final IntroductionScreenMode introductionScreenMode; + final Function( + BuildContext context, + PageController controller, + int currentPage, + int totalPages, + )? indicatorBuilder; + final List introductionPages; +} diff --git a/packages/flutter_introduction/lib/src/config/introduction_theme.dart b/packages/flutter_introduction/lib/src/config/introduction_theme.dart new file mode 100644 index 0000000..e5ca743 --- /dev/null +++ b/packages/flutter_introduction/lib/src/config/introduction_theme.dart @@ -0,0 +1,26 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import "package:flutter/material.dart"; + +class IntroductionTheme { + final TextStyle? titleTextStyle; + final TextStyle? descriptionTextStyle; + final TextStyle? buttonTextStyle; + final Color? backgroundColor; + final Color indicatorColor; + final Color? buttonBackgroundColor; + final Color buttonBorderColor; + final double indicatorSize; + final double indicatorSpacing; + + const IntroductionTheme({ + this.titleTextStyle, + this.descriptionTextStyle, + this.buttonTextStyle, + this.backgroundColor, + this.indicatorColor = Colors.black, + this.buttonBackgroundColor = Colors.transparent, + this.buttonBorderColor = const Color(0xfb979797), + this.indicatorSize = 12, + this.indicatorSpacing = 12, + }); +} diff --git a/packages/flutter_introduction/lib/src/config/introduction_translations.dart b/packages/flutter_introduction/lib/src/config/introduction_translations.dart new file mode 100644 index 0000000..aaac598 --- /dev/null +++ b/packages/flutter_introduction/lib/src/config/introduction_translations.dart @@ -0,0 +1,11 @@ +class IntroductionTranslations { + const IntroductionTranslations({ + this.nextButton = "Next", + this.previousButton = "Previous", + this.doneButton = "Get started", + }); + + final String nextButton; + final String previousButton; + final String doneButton; +} diff --git a/packages/flutter_introduction/lib/src/enums/indicator_mode.dart b/packages/flutter_introduction/lib/src/enums/indicator_mode.dart new file mode 100644 index 0000000..fc659a4 --- /dev/null +++ b/packages/flutter_introduction/lib/src/enums/indicator_mode.dart @@ -0,0 +1,5 @@ +enum IndicatorMode { + dot, + dash, + custom, +} diff --git a/packages/flutter_introduction/lib/src/enums/introduction_layout_style.dart b/packages/flutter_introduction/lib/src/enums/introduction_layout_style.dart new file mode 100644 index 0000000..b7257d1 --- /dev/null +++ b/packages/flutter_introduction/lib/src/enums/introduction_layout_style.dart @@ -0,0 +1,5 @@ +enum IntroductionLayoutStyle { + imageTop, + imageCenter, + imageBottom, +} diff --git a/packages/flutter_introduction/lib/src/enums/introduction_screen_mode.dart b/packages/flutter_introduction/lib/src/enums/introduction_screen_mode.dart new file mode 100644 index 0000000..f5a2900 --- /dev/null +++ b/packages/flutter_introduction/lib/src/enums/introduction_screen_mode.dart @@ -0,0 +1,5 @@ +enum IntroductionScreenMode { + showAlways, + showNever, + showOnce, +} diff --git a/packages/flutter_introduction/lib/src/screens/introduction_screen.dart b/packages/flutter_introduction/lib/src/screens/introduction_screen.dart new file mode 100644 index 0000000..b3ff1c3 --- /dev/null +++ b/packages/flutter_introduction/lib/src/screens/introduction_screen.dart @@ -0,0 +1,281 @@ +import "dart:async"; + +import "package:flutter/material.dart"; +import "package:flutter_introduction/src/config/introduction_options.dart"; +import "package:flutter_introduction/src/config/introduction_theme.dart"; +import "package:flutter_introduction/src/config/introduction_translations.dart"; +import "package:flutter_introduction/src/enums/indicator_mode.dart"; +import "package:flutter_introduction/src/enums/introduction_screen_mode.dart"; +import "package:flutter_introduction/src/widgets/button.dart"; +import "package:flutter_introduction/src/widgets/dash_indicator.dart"; +import "package:flutter_introduction/src/widgets/dot_indicator.dart"; +import "package:flutter_introduction/src/widgets/introduction_page.dart"; +import "package:introduction_repository_interface/introduction_repository_interface.dart"; + +class IntroductionScreen extends StatefulWidget { + const IntroductionScreen({ + required this.onDone, + this.introductionService, + this.options = const IntroductionOptions(), + this.translations = const IntroductionTranslations(), + this.introductionTheme = const IntroductionTheme(), + super.key, + }); + + final IntroductionService? introductionService; + final IntroductionOptions options; + final IntroductionTranslations translations; + final IntroductionTheme introductionTheme; + final Function() onDone; + + @override + State createState() => _IntroductionScreenState(); +} + +class _IntroductionScreenState extends State { + IntroductionService? introductionService; + bool? shouldShow; + @override + void initState() { + introductionService = widget.introductionService ?? IntroductionService(); + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + await checkShouldShow(); + }); + } + + Future checkShouldShow() async { + shouldShow = await introductionService?.shouldShow(); + if (widget.options.introductionScreenMode == + IntroductionScreenMode.showAlways) { + shouldShow = true; + } + if (widget.options.introductionScreenMode == + IntroductionScreenMode.showNever) { + shouldShow = false; + } + if (!shouldShow!) { + await widget.onDone(); + } + } + + Future> fetchIntroductionPages() async { + try { + var pages = await introductionService!.fetchIntroductionPages(); + if (pages.isEmpty) { + return widget.options.introductionPages; + } + return pages; + } on Exception catch (_) { + return widget.options.introductionPages; + } + } + + @override + Widget build(BuildContext context) { + var pages = []; + + return Scaffold( + body: FutureBuilder( + // ignore: discarded_futures + future: fetchIntroductionPages(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center( + child: CircularProgressIndicator(), + ); + } + if (shouldShow != null && !shouldShow!) { + return const SizedBox.shrink(); + } + for (var page in snapshot.data!) { + pages.add( + IntroductionPage( + title: page.title, + description: page.description, + graphic: page.graphic, + imageMode: page.imageMode, + introductionTheme: widget.introductionTheme, + ), + ); + } + + return _IntroductionScreen( + pages: pages, + options: widget.options, + translations: widget.translations, + introductionTheme: widget.introductionTheme, + onDone: () async { + await introductionService?.setCompleted(); + await widget.onDone(); + }, + ); + }, + ), + ); + } +} + +class _IntroductionScreen extends StatefulWidget { + const _IntroductionScreen({ + required this.pages, + required this.onDone, + required this.options, + required this.translations, + required this.introductionTheme, + }); + + final IntroductionOptions options; + final IntroductionTranslations translations; + final List pages; + final Function() onDone; + final IntroductionTheme introductionTheme; + + @override + State<_IntroductionScreen> createState() => __IntroductionScreenState(); +} + +class __IntroductionScreenState extends State<_IntroductionScreen> { + PageController controller = PageController(); + bool isAnimating = false; + int currentPage = 0; + + @override + void initState() { + super.initState(); + controller.addListener(() { + var newPage = controller.page?.round() ?? 0; + if (newPage != currentPage) { + setState(() { + currentPage = newPage; + }); + } + }); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + var options = widget.options; + var introductionTheme = widget.introductionTheme; + var showNextButton = currentPage < widget.pages.length - 1; + var showPreviousButton = currentPage > 0; + var isLastPage = currentPage == widget.pages.length - 1; + + return Scaffold( + backgroundColor: widget.introductionTheme.backgroundColor ?? + Theme.of(context).scaffoldBackgroundColor, + body: SafeArea( + bottom: true, + child: Column( + children: [ + Expanded( + child: PageView( + controller: controller, + scrollDirection: Axis.horizontal, + physics: const PageScrollPhysics(), + children: [ + ...widget.pages, + ], + ), + ), + Column( + children: [ + ...switch (options.indicatorMode) { + IndicatorMode.dot => [ + DotsIndicator( + controller: controller, + pageCount: widget.pages.length, + indicatorSize: introductionTheme.indicatorSize, + indicatorSpacing: introductionTheme.indicatorSpacing, + indicatorColor: introductionTheme.indicatorColor, + ), + ], + IndicatorMode.dash => [ + DashIndicator( + controller: controller, + pageCount: widget.pages.length, + indicatorSize: introductionTheme.indicatorSize, + indicatorSpacing: introductionTheme.indicatorSpacing, + indicatorColor: introductionTheme.indicatorColor, + ), + ], + IndicatorMode.custom => [ + widget.options.indicatorBuilder?.call( + context, + controller, + currentPage, + widget.pages.length, + ), + ], + }, + const SizedBox( + height: 40, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Button( + showButton: showPreviousButton, + text: widget.translations.previousButton, + introductionTheme: widget.introductionTheme, + onPressed: () async { + if (isAnimating) return; + isAnimating = true; + setState(() {}); + await controller.previousPage( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + isAnimating = false; + setState(() {}); + }, + ), + const SizedBox( + width: 16, + ), + if (!isLastPage) + Button( + showButton: showNextButton, + text: widget.translations.nextButton, + introductionTheme: widget.introductionTheme, + onPressed: () async { + if (isAnimating) return; + isAnimating = true; + setState(() {}); + + await controller.nextPage( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + isAnimating = false; + setState(() {}); + }, + ), + if (isLastPage) + Button( + introductionTheme: widget.introductionTheme, + showButton: true, + text: widget.translations.doneButton, + onPressed: () async { + widget.onDone(); + }, + ), + ], + ), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/packages/flutter_introduction/lib/src/widgets/button.dart b/packages/flutter_introduction/lib/src/widgets/button.dart new file mode 100644 index 0000000..2d40578 --- /dev/null +++ b/packages/flutter_introduction/lib/src/widgets/button.dart @@ -0,0 +1,54 @@ +import "package:flutter/material.dart"; +import "package:flutter_introduction/src/config/introduction_theme.dart"; + +class Button extends StatelessWidget { + const Button({ + required this.text, + required this.onPressed, + required this.showButton, + required this.introductionTheme, + super.key, + }); + final String text; + final Function() onPressed; + final bool showButton; + final IntroductionTheme introductionTheme; + + @override + Widget build(BuildContext context) { + var theme = Theme.of(context); + + return Expanded( + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 180, + maxHeight: 32, + ), + child: showButton + ? FilledButton( + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all( + introductionTheme.buttonBackgroundColor, + ), + shape: WidgetStateProperty.all( + RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(16)), + side: BorderSide( + color: introductionTheme.buttonBorderColor, + width: 1, + ), + ), + ), + ), + onPressed: onPressed, + child: Text( + text, + style: introductionTheme.buttonTextStyle ?? + theme.textTheme.bodyMedium, + ), + ) + : const SizedBox(), + ), + ); + } +} diff --git a/packages/flutter_introduction/lib/src/widgets/dash_indicator.dart b/packages/flutter_introduction/lib/src/widgets/dash_indicator.dart new file mode 100644 index 0000000..e1c9b9f --- /dev/null +++ b/packages/flutter_introduction/lib/src/widgets/dash_indicator.dart @@ -0,0 +1,46 @@ +import "package:flutter/material.dart"; + +class DashIndicator extends StatelessWidget { + const DashIndicator({ + required this.controller, + required this.indicatorColor, + required this.indicatorSize, + required this.indicatorSpacing, + required this.pageCount, + super.key, + }); + final PageController controller; + final Color indicatorColor; + final double indicatorSize; + final double indicatorSpacing; + final int pageCount; + + @override + Widget build(BuildContext context) => AnimatedBuilder( + animation: controller, + builder: (context, child) => Row( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate( + pageCount, + (index) => Container( + width: indicatorSize * 2, + height: indicatorSize / 2, + margin: EdgeInsets.symmetric(horizontal: indicatorSpacing / 2), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: index == (controller.page?.round() ?? 0) + ? indicatorColor + : indicatorColor.withOpacity(0.5), + ), + child: InkWell( + onTap: () async => controller.animateToPage( + index, + duration: const Duration(milliseconds: 400), + curve: Curves.easeInOut, + ), + ), + ), + ), + ), + ); +} diff --git a/packages/flutter_introduction/lib/src/widgets/dot_indicator.dart b/packages/flutter_introduction/lib/src/widgets/dot_indicator.dart new file mode 100644 index 0000000..0e40b6a --- /dev/null +++ b/packages/flutter_introduction/lib/src/widgets/dot_indicator.dart @@ -0,0 +1,46 @@ +import "package:flutter/material.dart"; + +class DotsIndicator extends StatelessWidget { + const DotsIndicator({ + required this.controller, + required this.indicatorColor, + required this.indicatorSize, + required this.indicatorSpacing, + required this.pageCount, + super.key, + }); + final PageController controller; + final Color indicatorColor; + final double indicatorSize; + final double indicatorSpacing; + final int pageCount; + + @override + Widget build(BuildContext context) => AnimatedBuilder( + animation: controller, + builder: (context, child) => Row( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate( + pageCount, + (index) => Container( + width: indicatorSize, + height: indicatorSize, + margin: EdgeInsets.symmetric(horizontal: indicatorSpacing / 2), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: index == (controller.page?.round() ?? 0) + ? indicatorColor + : indicatorColor.withOpacity(0.3), + ), + child: InkWell( + onTap: () async => controller.animateToPage( + index, + duration: const Duration(milliseconds: 400), + curve: Curves.easeInOut, + ), + ), + ), + ), + ), + ); +} diff --git a/packages/flutter_introduction/lib/src/widgets/introduction_page.dart b/packages/flutter_introduction/lib/src/widgets/introduction_page.dart new file mode 100644 index 0000000..a9c972b --- /dev/null +++ b/packages/flutter_introduction/lib/src/widgets/introduction_page.dart @@ -0,0 +1,113 @@ +import "package:flutter/material.dart"; +import "package:flutter_introduction/flutter_introduction.dart"; +import "package:flutter_introduction/src/config/introduction_theme.dart"; +import "package:flutter_introduction/src/enums/introduction_layout_style.dart"; + +class IntroductionPage extends StatelessWidget { + const IntroductionPage({ + required this.title, + required this.description, + required this.graphic, + required this.introductionTheme, + required this.imageMode, + this.layoutStyle = IntroductionLayoutStyle.imageBottom, + super.key, + }); + + final String title; + final String description; + final String graphic; + final IntroductionLayoutStyle layoutStyle; + final IntroductionTheme introductionTheme; + final ImageMode imageMode; + + @override + Widget build(BuildContext context) { + var theme = Theme.of(context); + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + ...switch (layoutStyle) { + IntroductionLayoutStyle.imageTop => [ + const SizedBox( + height: 124, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: imageMode == ImageMode.asset + ? Image.asset(graphic) + : Image.network(graphic), + ), + const SizedBox(height: 40), + Text( + title, + style: introductionTheme.titleTextStyle ?? + theme.textTheme.headlineLarge, + textAlign: TextAlign.center, + ), + const SizedBox(height: 12), + Text( + description, + style: introductionTheme.descriptionTextStyle ?? + theme.textTheme.bodyMedium, + textAlign: TextAlign.center, + ), + ], + IntroductionLayoutStyle.imageCenter => [ + const SizedBox( + height: 124, + ), + Text( + title, + style: introductionTheme.titleTextStyle ?? + theme.textTheme.headlineLarge, + textAlign: TextAlign.center, + ), + const SizedBox(height: 40), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: imageMode == ImageMode.asset + ? Image.asset(graphic) + : Image.network(graphic), + ), + const SizedBox(height: 12), + Text( + description, + style: introductionTheme.descriptionTextStyle ?? + theme.textTheme.bodyMedium, + textAlign: TextAlign.center, + ), + ], + IntroductionLayoutStyle.imageBottom => [ + const SizedBox( + height: 124, + ), + Text( + title, + style: introductionTheme.titleTextStyle ?? + theme.textTheme.headlineLarge, + textAlign: TextAlign.center, + ), + const SizedBox(height: 12), + Text( + description, + style: introductionTheme.descriptionTextStyle ?? + theme.textTheme.bodyMedium, + textAlign: TextAlign.center, + ), + const SizedBox(height: 40), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: imageMode == ImageMode.asset + ? Image.asset(graphic) + : Image.network(graphic), + ), + ], + }, + ], + ), + ); + } +} diff --git a/packages/flutter_introduction/pubspec.yaml b/packages/flutter_introduction/pubspec.yaml index 1fa2baf..4022dae 100644 --- a/packages/flutter_introduction/pubspec.yaml +++ b/packages/flutter_introduction/pubspec.yaml @@ -1,28 +1,29 @@ name: flutter_introduction -description: Combined Package of Flutter Introduction Widget and Flutter Introduction Service -version: 5.0.0 -publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub +description: "A flutter introduction project" +version: 6.0.0 +homepage: none +publish_to: none environment: - sdk: ">=3.0.0 <4.0.0" + sdk: ^3.5.3 flutter: ">=1.17.0" dependencies: flutter: sdk: flutter - flutter_introduction_widget: - hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub - version: "^5.0.0" - flutter_introduction_service: - hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub - version: "^5.0.0" + introduction_repository_interface: + path: ../introduction_repository_interface dev_dependencies: - flutter_test: - sdk: flutter flutter_iconica_analysis: git: url: https://github.com/Iconica-Development/flutter_iconica_analysis - ref: 6.0.0 + ref: 7.0.0 flutter: + uses-material-design: true + + assets: + - assets/ + + diff --git a/packages/flutter_introduction_firebase/.gitignore b/packages/flutter_introduction_firebase/.gitignore deleted file mode 100644 index bffd2c4..0000000 --- a/packages/flutter_introduction_firebase/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# SPDX-FileCopyrightText: 2022 Iconica -# -# SPDX-License-Identifier: GPL-3.0-or-later - -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# 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 -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -# /pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ -.flutter-plugins-dependencies -.flutter-plugins -.metadata - -pubspec.lock - -pubspec_overrides.yaml diff --git a/packages/flutter_introduction_firebase/CHANGELOG.md b/packages/flutter_introduction_firebase/CHANGELOG.md deleted file mode 120000 index 699cc9e..0000000 --- a/packages/flutter_introduction_firebase/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -../../CHANGELOG.md \ No newline at end of file diff --git a/packages/flutter_introduction_firebase/LICENSE b/packages/flutter_introduction_firebase/LICENSE deleted file mode 120000 index 30cff74..0000000 --- a/packages/flutter_introduction_firebase/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE \ No newline at end of file diff --git a/packages/flutter_introduction_firebase/README.md b/packages/flutter_introduction_firebase/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/packages/flutter_introduction_firebase/lib/flutter_introduction_firebase.dart b/packages/flutter_introduction_firebase/lib/flutter_introduction_firebase.dart deleted file mode 100644 index 5c17400..0000000 --- a/packages/flutter_introduction_firebase/lib/flutter_introduction_firebase.dart +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -/// -library flutter_introduction_firebase; - -export 'src/firebase_service.dart'; -export 'src/introduction_widget.dart'; diff --git a/packages/flutter_introduction_firebase/lib/src/firebase_service.dart b/packages/flutter_introduction_firebase/lib/src/firebase_service.dart deleted file mode 100644 index 0e6f51e..0000000 --- a/packages/flutter_introduction_firebase/lib/src/firebase_service.dart +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_introduction_firebase/src/introduction_page.dart'; - -const _introductionDocumentRef = 'introduction/introduction'; - -class FirebaseIntroductionService { - FirebaseIntroductionService({ - DocumentReference>? documentRef, - }) : _documentRef = documentRef ?? - FirebaseFirestore.instance.doc(_introductionDocumentRef); - - final DocumentReference> _documentRef; - List _pages = []; - - Future> getIntroductionPages() async { - if (_pages.isNotEmpty) return _pages; - var pagesDocuments = - await _documentRef.collection('pages').orderBy('order').get(); - return _pages = pagesDocuments.docs.map((document) { - var data = document.data(); - // convert Map to Map - var title = data['title'] != null - ? (data['title'] as Map).cast() - : {}; - var content = data['content'] != null - ? (data['content'] as Map).cast() - : {}; - return IntroductionPageData( - title: title, - content: content, - contentImage: data['image'] as String?, - backgroundImage: data['background_image'] as String?, - // the color is stored as a hex string - backgroundColor: data['background_color'] != null - ? Color(int.parse(data['background_color'] as String, radix: 16)) - : null, - ); - }).toList(); - } - - Future introductionIsDisabled() async { - var document = await _documentRef.get(); - return document.data()!['disabled'] as bool? ?? false; - } - - Future shouldAlwaysShowIntroduction() async { - var document = await _documentRef.get(); - return document.data()!['always_show'] as bool? ?? false; - } - - Future loadIntroductionPages( - BuildContext context, - ) async { - for (var page in _pages) { - if (context.mounted && page.backgroundImage != null) { - await precacheImage( - CachedNetworkImageProvider(page.backgroundImage!), - context, - ); - } - if (context.mounted && page.contentImage != null) { - await precacheImage( - CachedNetworkImageProvider(page.contentImage!), - context, - ); - } - } - } -} diff --git a/packages/flutter_introduction_firebase/lib/src/introduction_page.dart b/packages/flutter_introduction_firebase/lib/src/introduction_page.dart deleted file mode 100644 index 618e1ef..0000000 --- a/packages/flutter_introduction_firebase/lib/src/introduction_page.dart +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; - -@immutable -class IntroductionPageData { - const IntroductionPageData({ - required this.title, - required this.content, - this.contentImage, - this.backgroundImage, - this.backgroundColor, - }); - - /// The title of the introduction page in different languages - final Map title; - - /// The content of the introduction page in different languages - final Map content; - - /// The imageUrl of the graphic on the introduction page - final String? contentImage; - - /// The imageUrl of the background image of the introduction page - final String? backgroundImage; - - /// Optional background color of the introduction page - /// (defaults to transparent) - final Color? backgroundColor; -} diff --git a/packages/flutter_introduction_firebase/lib/src/introduction_widget.dart b/packages/flutter_introduction_firebase/lib/src/introduction_widget.dart deleted file mode 100644 index de75a47..0000000 --- a/packages/flutter_introduction_firebase/lib/src/introduction_widget.dart +++ /dev/null @@ -1,184 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -// ignore_for_file: discarded_futures - -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_introduction_firebase/flutter_introduction_firebase.dart'; -import 'package:flutter_introduction_service/flutter_introduction_service.dart'; - -export 'package:flutter_introduction_firebase/src/introduction_page.dart'; -export 'package:flutter_introduction_widget/flutter_introduction_widget.dart'; - -class IntroductionFirebase extends StatefulWidget { - const IntroductionFirebase({ - required this.options, - required this.onComplete, - this.decoration, - this.layoutStyle, - this.titleBuilder, - this.contentBuilder, - this.imageBuilder, - this.onSkip, - this.firebaseService, - this.introductionService, - this.physics, - this.child, - this.languageCodeOverride, - super.key, - }); - - /// The options used to build the introduction screen - final IntroductionOptions options; - - /// The service used to determine if the introduction screen should be shown - final IntroductionService? introductionService; - - /// The service used to get the introduction pages - final FirebaseIntroductionService? firebaseService; - - /// A function called when the introductionSceen changes - final VoidCallback onComplete; - - /// A function called when the introductionScreen is skipped - final VoidCallback? onSkip; - - /// How the single child scroll view should respond to scrolling - final ScrollPhysics? physics; - - /// The widget to show when the introduction screen is loading - final Widget? child; - - /// The decoration of an introduction page if it doesn't have - /// a backgroundImage or backgroundColor - final BoxDecoration? decoration; - - /// The layout style of all the introduction pages - final IntroductionLayoutStyle? layoutStyle; - - /// The builder used to build the title of the introduction page - final Widget Function(String)? titleBuilder; - - /// The builder used to build the content of the introduction page - final Widget Function(String)? contentBuilder; - - /// The builder used to build the image of the introduction page - final Widget Function(String)? imageBuilder; - - /// Use this to override the language code that is in the context - /// used for showing the introduction in a different language - final String? languageCodeOverride; - - @override - State createState() => _IntroductionState(); -} - -class _IntroductionState extends State { - late IntroductionService _service; - late FirebaseIntroductionService _firebaseService; - - @override - void initState() { - super.initState(); - if (widget.introductionService == null) { - _service = IntroductionService(); - } else { - _service = widget.introductionService!; - } - if (widget.firebaseService == null) { - _firebaseService = FirebaseIntroductionService(); - } else { - _firebaseService = widget.firebaseService!; - } - } - - @override - Widget build(BuildContext context) { - Future shouldShow() async => - !await _firebaseService.introductionIsDisabled() && - (await _service.shouldShow() || - await _firebaseService.shouldAlwaysShowIntroduction()); - var languageCode = widget.languageCodeOverride ?? - Localizations.localeOf(context).languageCode; - - return FutureBuilder( - future: shouldShow(), - builder: (context, snapshot) { - if (snapshot.hasData && snapshot.data != null && snapshot.data!) { - return FutureBuilder( - future: _firebaseService.getIntroductionPages(), - builder: (context, snapshot) { - if (snapshot.hasData && - snapshot.data != null && - snapshot.data is List) { - return IntroductionScreen( - options: widget.options.copyWith( - pages: (context) => snapshot.data!.map( - (e) { - var title = e.title.isEmpty - ? '' - : e.title.containsKey(languageCode) - ? e.title[languageCode]! - : e.title.values.first; - var content = e.content.isEmpty - ? '' - : e.content.containsKey(languageCode) - ? e.content[languageCode]! - : e.content.values.first; - return IntroductionPage( - title: - widget.titleBuilder?.call(title) ?? Text(title), - graphic: e.contentImage != null && - e.contentImage!.isNotEmpty - ? widget.imageBuilder?.call(e.contentImage!) ?? - CachedNetworkImage(imageUrl: e.contentImage!) - : null, - text: widget.contentBuilder?.call(content) ?? - Text(content), - decoration: widget.decoration?.copyWith( - color: e.backgroundColor, - image: e.backgroundImage != null && - e.backgroundImage!.isNotEmpty - ? DecorationImage( - image: CachedNetworkImageProvider( - e.backgroundImage!, - ), - fit: BoxFit.cover, - ) - : null, - ), - layoutStyle: widget.layoutStyle, - ); - }, - ).toList(), - ), - onComplete: () async { - await _service.onComplete(); - widget.onComplete(); - }, - physics: widget.physics, - onSkip: () async { - await _service.onSkip(); - widget.onComplete(); - }, - ); - } else { - return widget.child ?? const CircularProgressIndicator(); - } - }, - ); - } else { - if (snapshot.hasData && snapshot.data != null && !snapshot.data!) { - WidgetsBinding.instance.addPostFrameCallback((_) async { - await _service.onComplete(); - widget.onComplete(); - }); - } - return widget.child ?? const CircularProgressIndicator(); - } - }, - ); - } -} diff --git a/packages/flutter_introduction_firebase/pubspec.yaml b/packages/flutter_introduction_firebase/pubspec.yaml deleted file mode 100644 index c274cee..0000000 --- a/packages/flutter_introduction_firebase/pubspec.yaml +++ /dev/null @@ -1,30 +0,0 @@ -name: flutter_introduction_firebase -description: Flutter Introduction Page that uses firebase for the pages and some settings -version: 5.0.0 -publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub - -environment: - sdk: ">=3.1.5 <4.0.0" - -dependencies: - flutter: - sdk: flutter - cloud_firestore: "^4.12.2" - cached_network_image: "^3.3.0" - - flutter_introduction_widget: - hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub - version: "^5.0.0" - flutter_introduction_service: - hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub - version: "^5.0.0" - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_iconica_analysis: - git: - url: https://github.com/Iconica-Development/flutter_iconica_analysis - ref: 6.0.0 - -flutter: diff --git a/packages/flutter_introduction_firebase/test/flutter_introduction_firebase_test.dart b/packages/flutter_introduction_firebase/test/flutter_introduction_firebase_test.dart deleted file mode 100644 index b6f647b..0000000 --- a/packages/flutter_introduction_firebase/test/flutter_introduction_firebase_test.dart +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test('test', () { - expect(true, true); - }); -} diff --git a/packages/flutter_introduction_interface/CHANGELOG.md b/packages/flutter_introduction_interface/CHANGELOG.md deleted file mode 120000 index 699cc9e..0000000 --- a/packages/flutter_introduction_interface/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -../../CHANGELOG.md \ No newline at end of file diff --git a/packages/flutter_introduction_interface/LICENSE b/packages/flutter_introduction_interface/LICENSE deleted file mode 120000 index 30cff74..0000000 --- a/packages/flutter_introduction_interface/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE \ No newline at end of file diff --git a/packages/flutter_introduction_interface/README.md b/packages/flutter_introduction_interface/README.md deleted file mode 120000 index fe84005..0000000 --- a/packages/flutter_introduction_interface/README.md +++ /dev/null @@ -1 +0,0 @@ -../../README.md \ No newline at end of file diff --git a/packages/flutter_introduction_interface/analysis_options.yaml b/packages/flutter_introduction_interface/analysis_options.yaml deleted file mode 100644 index 8ea00ce..0000000 --- a/packages/flutter_introduction_interface/analysis_options.yaml +++ /dev/null @@ -1,9 +0,0 @@ -include: package:flutter_iconica_analysis/analysis_options.yaml - -# Possible to overwrite the rules from the package - -analyzer: - exclude: - -linter: - rules: diff --git a/packages/flutter_introduction_interface/lib/flutter_introduction_interface.dart b/packages/flutter_introduction_interface/lib/flutter_introduction_interface.dart deleted file mode 100644 index aeb5392..0000000 --- a/packages/flutter_introduction_interface/lib/flutter_introduction_interface.dart +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -export './src/introduction_interface.dart'; -export './src/local_introduction.dart'; diff --git a/packages/flutter_introduction_interface/lib/src/introduction_interface.dart b/packages/flutter_introduction_interface/lib/src/introduction_interface.dart deleted file mode 100644 index 5a72f26..0000000 --- a/packages/flutter_introduction_interface/lib/src/introduction_interface.dart +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter_data_interface/flutter_data_interface.dart'; -import 'package:flutter_introduction_interface/src/local_introduction.dart'; - -abstract class IntroductionInterface extends DataInterface { - /// Constructs an instance of [IntroductionInterface]. - /// - /// The [token] is used for verification purposes. - IntroductionInterface() : super(token: _token); - - static final Object _token = Object(); - - static IntroductionInterface _instance = LocalIntroductionDataProvider(); - - /// Retrieves the current instance of [IntroductionInterface]. - static IntroductionInterface get instance => _instance; - - /// Sets the current instance of [IntroductionInterface]. - /// - /// Throws an error if the provided instance does not match the token. - static set instance(IntroductionInterface instance) { - DataInterface.verify(instance, _token); - _instance = instance; - } - - /// Sets whether the introduction is completed or not. - /// - /// The [value] parameter specifies whether the introduction is completed. - /// By default, it is set to `true`. - Future setCompleted({bool value = true}); - - /// Checks if the introduction should be shown. - /// - /// Returns `true` if the introduction should be shown; - /// otherwise, returns `false`. - Future shouldShow(); -} diff --git a/packages/flutter_introduction_interface/lib/src/local_introduction.dart b/packages/flutter_introduction_interface/lib/src/local_introduction.dart deleted file mode 100644 index 71b93d8..0000000 --- a/packages/flutter_introduction_interface/lib/src/local_introduction.dart +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter_introduction_interface/src/introduction_interface.dart'; - -/// Provides local data storage for managing introduction data. -/// -/// This class extends [IntroductionInterface] and implements methods to manage -/// introduction data locally. -class LocalIntroductionDataProvider extends IntroductionInterface { - /// Constructs an instance of [LocalIntroductionDataProvider]. - /// - /// Initializes the [hasViewed] flag to `false`. - LocalIntroductionDataProvider(); - - /// Flag indicating whether the introduction has been viewed or not. - bool hasViewed = false; - - @override - Future setCompleted({bool value = true}) async { - hasViewed = value; - } - - @override - Future shouldShow() async => hasViewed; -} diff --git a/packages/flutter_introduction_interface/pubspec.yaml b/packages/flutter_introduction_interface/pubspec.yaml deleted file mode 100644 index 802ce68..0000000 --- a/packages/flutter_introduction_interface/pubspec.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: flutter_introduction_interface -description: A new Flutter package project. -version: 5.0.0 -publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub - -environment: - sdk: '>=3.0.0 <4.0.0' - flutter: ">=1.17.0" - -dependencies: - flutter: - sdk: flutter - flutter_data_interface: - hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub - version: "^1.0.0" - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_iconica_analysis: - git: - url: https://github.com/Iconica-Development/flutter_iconica_analysis - ref: 6.0.0 - -flutter: diff --git a/packages/flutter_introduction_service/CHANGELOG.md b/packages/flutter_introduction_service/CHANGELOG.md deleted file mode 120000 index 699cc9e..0000000 --- a/packages/flutter_introduction_service/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -../../CHANGELOG.md \ No newline at end of file diff --git a/packages/flutter_introduction_service/LICENSE b/packages/flutter_introduction_service/LICENSE deleted file mode 120000 index 30cff74..0000000 --- a/packages/flutter_introduction_service/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE \ No newline at end of file diff --git a/packages/flutter_introduction_service/README.md b/packages/flutter_introduction_service/README.md deleted file mode 120000 index fe84005..0000000 --- a/packages/flutter_introduction_service/README.md +++ /dev/null @@ -1 +0,0 @@ -../../README.md \ No newline at end of file diff --git a/packages/flutter_introduction_service/lib/flutter_introduction_service.dart b/packages/flutter_introduction_service/lib/flutter_introduction_service.dart deleted file mode 100644 index 323eb42..0000000 --- a/packages/flutter_introduction_service/lib/flutter_introduction_service.dart +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -export 'package:flutter_introduction_interface/flutter_introduction_interface.dart'; - -export './src/introduction_service.dart'; diff --git a/packages/flutter_introduction_service/lib/src/introduction_service.dart b/packages/flutter_introduction_service/lib/src/introduction_service.dart deleted file mode 100644 index 73d1e20..0000000 --- a/packages/flutter_introduction_service/lib/src/introduction_service.dart +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter_introduction_interface/flutter_introduction_interface.dart'; - -/// A service for managing introduction-related operations. -/// -/// This class provides methods for handling introduction-related actions -/// such as skipping, completing, -/// and determining whether to show the introduction. -class IntroductionService { - /// Constructs an instance of [IntroductionService]. - /// - /// Optionally takes a [dataProvider] parameter, - /// which is an implementation of [IntroductionInterface]. - /// If no data provider is provided, - /// it defaults to [LocalIntroductionDataProvider]. - IntroductionService([IntroductionInterface? dataProvider]) - : _dataProvider = dataProvider ?? LocalIntroductionDataProvider(); - - late final IntroductionInterface _dataProvider; - - /// Marks the introduction as skipped. - /// - /// Calls [_dataProvider.setCompleted] with the value `true`. - Future onSkip() => _dataProvider.setCompleted(value: true); - - /// Marks the introduction as completed. - /// - /// Calls [_dataProvider.setCompleted] with the value `true`. - Future onComplete() => _dataProvider.setCompleted(value: true); - - /// Checks whether the introduction should be shown. - /// - /// Returns a `Future` indicating whether the - /// introduction should be shown. - Future shouldShow() => _dataProvider.shouldShow(); -} diff --git a/packages/flutter_introduction_service/pubspec.yaml b/packages/flutter_introduction_service/pubspec.yaml deleted file mode 100644 index f67c7f1..0000000 --- a/packages/flutter_introduction_service/pubspec.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: flutter_introduction_service -description: A new Flutter package project. -version: 5.0.0 -publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub - -environment: - sdk: '>=3.0.0 <4.0.0' - flutter: ">=1.17.0" - -dependencies: - flutter: - sdk: flutter - flutter_introduction_interface: - hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub - version: "^5.0.0" - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_iconica_analysis: - git: - url: https://github.com/Iconica-Development/flutter_iconica_analysis - ref: 6.0.0 - -flutter: diff --git a/packages/flutter_introduction_shared_preferences/CHANGELOG.md b/packages/flutter_introduction_shared_preferences/CHANGELOG.md deleted file mode 120000 index 699cc9e..0000000 --- a/packages/flutter_introduction_shared_preferences/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -../../CHANGELOG.md \ No newline at end of file diff --git a/packages/flutter_introduction_shared_preferences/LICENSE b/packages/flutter_introduction_shared_preferences/LICENSE deleted file mode 120000 index 30cff74..0000000 --- a/packages/flutter_introduction_shared_preferences/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE \ No newline at end of file diff --git a/packages/flutter_introduction_shared_preferences/README.md b/packages/flutter_introduction_shared_preferences/README.md deleted file mode 120000 index fe84005..0000000 --- a/packages/flutter_introduction_shared_preferences/README.md +++ /dev/null @@ -1 +0,0 @@ -../../README.md \ No newline at end of file diff --git a/packages/flutter_introduction_shared_preferences/lib/flutter_introduction_shared_preferences.dart b/packages/flutter_introduction_shared_preferences/lib/flutter_introduction_shared_preferences.dart deleted file mode 100644 index b11bf46..0000000 --- a/packages/flutter_introduction_shared_preferences/lib/flutter_introduction_shared_preferences.dart +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter_introduction_interface/flutter_introduction_interface.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -/// Provides data storage using SharedPreferences for -/// managing introduction data. -/// -/// This class extends [IntroductionInterface] and implements methods to manage -/// introduction data using SharedPreferences. -class SharedPreferencesIntroductionDataProvider extends IntroductionInterface { - /// Constructs an instance of [SharedPreferencesIntroductionDataProvider]. - SharedPreferencesIntroductionDataProvider(); - - SharedPreferences? _prefs; - String key = '_completedIntroduction'; - - /// Writes a key-value pair to SharedPreferences. - /// - /// The [key] is the key under which to store the [value]. - /// The [value] is the boolean value to be stored. - Future _writeKeyValue(String key, bool value) async { - await _prefs!.setBool(key, value); - } - - /// Initializes the SharedPreferences instance. - Future _init() async { - _prefs ??= await SharedPreferences.getInstance(); - } - - @override - Future setCompleted({bool value = true}) async { - await _init(); - await _writeKeyValue(key, value); - } - - @override - Future shouldShow() async { - await _init(); - return !(_prefs!.getBool(key) ?? false); - } -} diff --git a/packages/flutter_introduction_shared_preferences/pubspec.yaml b/packages/flutter_introduction_shared_preferences/pubspec.yaml deleted file mode 100644 index 5317329..0000000 --- a/packages/flutter_introduction_shared_preferences/pubspec.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: flutter_introduction_shared_preferences -description: A new Flutter package project. -version: 5.0.0 -publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub - -environment: - sdk: '>=3.0.0 <4.0.0' - flutter: ">=1.17.0" - -dependencies: - flutter: - sdk: flutter - flutter_introduction_interface: - hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub - version: "^5.0.0" - shared_preferences: "^2.2.0" - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_iconica_analysis: - git: - url: https://github.com/Iconica-Development/flutter_iconica_analysis - ref: 6.0.0 - -flutter: diff --git a/packages/flutter_introduction_widget/.gitignore b/packages/flutter_introduction_widget/.gitignore deleted file mode 100644 index e174818..0000000 --- a/packages/flutter_introduction_widget/.gitignore +++ /dev/null @@ -1,43 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# 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 -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.packages -build/ - -example/android/ -example/ios/ -example/macos/ -example/web/ -example/windows/ -example/linux/ -example/.metadata -example/pubspec.lock - -.flutter-plugins -.flutter-plugins-dependencies -.metadata \ No newline at end of file diff --git a/packages/flutter_introduction_widget/CHANGELOG.md b/packages/flutter_introduction_widget/CHANGELOG.md deleted file mode 120000 index 699cc9e..0000000 --- a/packages/flutter_introduction_widget/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -../../CHANGELOG.md \ No newline at end of file diff --git a/packages/flutter_introduction_widget/LICENSE b/packages/flutter_introduction_widget/LICENSE deleted file mode 120000 index 30cff74..0000000 --- a/packages/flutter_introduction_widget/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE \ No newline at end of file diff --git a/packages/flutter_introduction_widget/README.md b/packages/flutter_introduction_widget/README.md deleted file mode 100644 index ea9cf49..0000000 --- a/packages/flutter_introduction_widget/README.md +++ /dev/null @@ -1,65 +0,0 @@ -[![pub package](https://img.shields.io/pub/v/flutter_introduction_widget.svg)](https://github.com/Iconica-Development) [![Build status](https://img.shields.io/github/workflow/status/Iconica-Development/flutter_introduction_widget/CI)](https://github.com/Iconica-Development/flutter_introduction_widget/actions/new) [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://github.com/tenhobi/effective_dart) - -# Introduction Widget -Flutter Introduction Widget for showing a list of introduction pages on a single scrollable page or horizontal pageview. - -![Introduction GIF](../../flutter_introduction_widget.gif) - -## Setup - -To use this package, add `flutter_introduction_widget` as a dependency in your pubspec.yaml file. - -## How to use - -Simple way to use the introduction widget: -```dart -IntroductionScreen( - options: IntroductionOptions( - pages: [ - IntroductionPage( - title: const Text('First page'), - text: const Text('Wow a page'), - graphic: const FlutterLogo(), - ), - IntroductionPage( - title: const Text('Second page'), - text: const Text('Another page'), - graphic: const FlutterLogo(), - ), - IntroductionPage( - title: const Text('Third page'), - text: const Text('The final page of this app'), - graphic: const FlutterLogo(), - backgroundImage: const AssetImage( - 'assets/flutter_introduction_background.jpeg'), - ), - ], - introductionTranslations: const IntroductionTranslations( - skipButton: 'Skip it!', - nextButton: 'Next', - previousButton: 'Previous', - finishButton: 'Finish', - ), - buttonMode: IntroductionScreenButtonMode.text, - buttonBuilder: (context, onPressed, child) => - ElevatedButton(onPressed: onPressed, child: child), - ), - onComplete: () { - debugPrint('We completed the cycle'); - }, -), -``` - -See the [Example Code](example/lib/main.dart) for an example on how to use this package. - -## Issues - -Please file any issues, bugs or feature request as an issue on our [GitHub](https://github.com/Iconica-Development/flutter_introduction_widget) page. Commercial support is available if you need help with integration with your app or services. You can contact us at [support@iconica.nl](mailto:support@iconica.nl). - -## Want to contribute - -If you would like to contribute to the plugin (e.g. by improving the documentation, solving a bug or adding a cool new feature), please carefully review our [contribution guide](./CONTRIBUTING.md) and send us your [pull request](https://github.com/Iconica-Development/flutter_introduction_widget/pulls). - -## Author - -This `flutter_introduction_widget` for Flutter is developed by [Iconica](https://iconica.nl). You can contact us at \ No newline at end of file diff --git a/packages/flutter_introduction_widget/analysis_options.yaml b/packages/flutter_introduction_widget/analysis_options.yaml deleted file mode 100644 index 8ea00ce..0000000 --- a/packages/flutter_introduction_widget/analysis_options.yaml +++ /dev/null @@ -1,9 +0,0 @@ -include: package:flutter_iconica_analysis/analysis_options.yaml - -# Possible to overwrite the rules from the package - -analyzer: - exclude: - -linter: - rules: diff --git a/packages/flutter_introduction_widget/example/.gitignore b/packages/flutter_introduction_widget/example/.gitignore deleted file mode 100644 index 24476c5..0000000 --- a/packages/flutter_introduction_widget/example/.gitignore +++ /dev/null @@ -1,44 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# 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/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/packages/flutter_introduction_widget/example/README.md b/packages/flutter_introduction_widget/example/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/packages/flutter_introduction_widget/example/analysis_options.yaml b/packages/flutter_introduction_widget/example/analysis_options.yaml deleted file mode 100644 index 61b6c4d..0000000 --- a/packages/flutter_introduction_widget/example/analysis_options.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at - # https://dart-lang.github.io/linter/lints/index.html. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/packages/flutter_introduction_widget/example/assets/flutter_introduction_background.jpeg b/packages/flutter_introduction_widget/example/assets/flutter_introduction_background.jpeg deleted file mode 100644 index ffa9d55..0000000 Binary files a/packages/flutter_introduction_widget/example/assets/flutter_introduction_background.jpeg and /dev/null differ diff --git a/packages/flutter_introduction_widget/example/lib/main.dart b/packages/flutter_introduction_widget/example/lib/main.dart deleted file mode 100644 index 678fc22..0000000 --- a/packages/flutter_introduction_widget/example/lib/main.dart +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; -import 'package:flutter_introduction_widget/flutter_introduction_widget.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - // This widget is the root of your application. - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - // This is the theme of your application. - // - // Try running your application with "flutter run". You'll see the - // application has a blue toolbar. Then, without quitting the app, try - // changing the primarySwatch below to Colors.green and then invoke - // "hot reload" (press "r" in the console where you ran "flutter run", - // or simply save your changes to "hot reload" in a Flutter IDE). - // Notice that the counter didn't reset back to zero; the application - // is not restarted. - primarySwatch: Colors.blue, - ), - home: IntroductionScreen( - options: IntroductionOptions( - pages: (context) => [ - const IntroductionPage( - title: Text('Basic Page'), - text: Text( - 'A page with some text and a widget in the middle.', - ), - graphic: FlutterLogo(size: 100), - ), - const IntroductionPage( - title: Text('Layout Shift'), - text: Text( - 'You can change the layout of a page to mix things up.', - ), - graphic: FlutterLogo(size: 100), - layoutStyle: IntroductionLayoutStyle.imageTop, - ), - const IntroductionPage( - title: Text( - 'Decoration', - style: TextStyle( - color: Colors.white, - ), - ), - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topRight, - end: Alignment.bottomLeft, - colors: [ - Colors.yellow, - Colors.red, - Colors.indigo, - Colors.teal, - ], - ), - ), - text: Text( - 'Add a Decoration to make a custom background, like a LinearGradient', - style: TextStyle( - color: Colors.white, - ), - ), - graphic: FlutterLogo( - size: 100, - ), - ), - const IntroductionPage( - title: Text( - 'Background Image', - ), - text: Text( - 'Add a Decoration with a DecorationImage, to add an background image', - ), - decoration: BoxDecoration( - image: DecorationImage( - fit: BoxFit.cover, - image: AssetImage( - 'assets/flutter_introduction_background.jpeg', - ), - ), - ), - ), - ], - introductionTranslations: const IntroductionTranslations( - skipButton: 'Skip it!', - nextButton: 'Next', - previousButton: 'Previous', - finishButton: 'Finish', - ), - tapEnabled: true, - displayMode: IntroductionDisplayMode.multiPageHorizontal, - buttonMode: IntroductionScreenButtonMode.text, - indicatorMode: IndicatorMode.dash, - skippable: true, - buttonBuilder: (context, onPressed, child, buttonType) => - ElevatedButton(onPressed: onPressed, child: child), - ), - onComplete: () { - debugPrint('We completed the cycle'); - }, - ), - ); - } -} diff --git a/packages/flutter_introduction_widget/example/pubspec.yaml b/packages/flutter_introduction_widget/example/pubspec.yaml deleted file mode 100644 index f19ff96..0000000 --- a/packages/flutter_introduction_widget/example/pubspec.yaml +++ /dev/null @@ -1,60 +0,0 @@ -name: example_widget -description: A new Flutter project. - -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -version: 1.0.0+1 - -environment: - sdk: '>=2.18.1 <3.0.0' - -dependencies: - flutter: - sdk: flutter - flutter_introduction_widget: - path: ../ - -dev_dependencies: - flutter_test: - sdk: flutter - - flutter_lints: ^3.0.1 - - -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - assets: - - assets/ - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/flutter_introduction_widget/lib/flutter_introduction_widget.dart b/packages/flutter_introduction_widget/lib/flutter_introduction_widget.dart deleted file mode 100644 index 8a4e2cd..0000000 --- a/packages/flutter_introduction_widget/lib/flutter_introduction_widget.dart +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -export 'src/config/introduction.dart'; -export 'src/introduction.dart'; diff --git a/packages/flutter_introduction_widget/lib/src/config/default_introduction_pages.dart b/packages/flutter_introduction_widget/lib/src/config/default_introduction_pages.dart deleted file mode 100644 index 5ab605c..0000000 --- a/packages/flutter_introduction_widget/lib/src/config/default_introduction_pages.dart +++ /dev/null @@ -1,85 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_introduction_widget/flutter_introduction_widget.dart'; - -List defaultIntroductionPages(BuildContext context) { - var theme = Theme.of(context); - return [ - IntroductionPage( - title: Column( - children: [ - const SizedBox(height: 50), - Text( - 'welcome to iconinstagram', - style: theme.textTheme.headlineLarge, - ), - const SizedBox(height: 6), - ], - ), - graphic: const Image( - image: AssetImage( - 'assets/first.png', - package: 'flutter_introduction_widget', - ), - ), - text: Text( - 'Welcome to the world of Instagram, where creativity' - ' knows no bounds and connections are made' - ' through captivating visuals.', - textAlign: TextAlign.center, - style: theme.textTheme.bodyMedium, - ), - ), - IntroductionPage( - title: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(height: 50), - Text( - 'discover iconinstagram', - style: theme.textTheme.headlineLarge, - ), - const SizedBox(height: 6), - ], - ), - text: Text( - 'Dive into the vibrant world of' - ' Instagram and discover endless possibilities.' - ' From stunning photography to engaging videos,' - ' Instagram offers a diverse range of content to explore and enjoy.', - textAlign: TextAlign.center, - style: theme.textTheme.bodyMedium, - ), - graphic: const Image( - image: AssetImage( - 'assets/second.png', - package: 'flutter_introduction_widget', - ), - ), - ), - IntroductionPage( - title: Column( - children: [ - const SizedBox(height: 50), - Text( - 'elevate your experience', - style: theme.textTheme.headlineLarge, - ), - const SizedBox(height: 6), - ], - ), - graphic: const Image( - image: AssetImage( - 'assets/third.png', - package: 'flutter_introduction_widget', - ), - ), - text: Text( - 'Whether promoting your business, or connecting' - ' with friends and family, Instagram provides the' - ' tools and platform to make your voice heard.', - textAlign: TextAlign.center, - style: theme.textTheme.bodyMedium, - ), - ), - ]; -} diff --git a/packages/flutter_introduction_widget/lib/src/config/introduction.dart b/packages/flutter_introduction_widget/lib/src/config/introduction.dart deleted file mode 100644 index 4f0ea30..0000000 --- a/packages/flutter_introduction_widget/lib/src/config/introduction.dart +++ /dev/null @@ -1,286 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; -import 'package:flutter_introduction_widget/src/config/default_introduction_pages.dart'; - -enum IntroductionScreenMode { showNever, showAlways, showOnce } - -enum IntroductionScreenButtonMode { text, icon, disabled, singleFinish } - -enum IntroductionLayoutStyle { - imageCenter, - imageTop, - imageBottom, -} - -enum IndicatorMode { dot, dash, custom } - -enum IntroductionDisplayMode { - singleScrollablePageVertical, - multiPageHorizontal -} - -enum IntroductionControlMode { - previousNextButton, - singleButton, -} - -enum IntroductionButtonType { - next, - previous, - finish, - skip, -} - -class IntroductionPage { - /// Creates an introduction page with data used in the introduction screen for - /// each page. - /// - /// The values for [title] and [text] are optional in this, but will use a - /// default translation key when built. - /// - /// The [background] is fully optional and if not provided will show the - /// [ThemeData.colorScheme.background] as default. - const IntroductionPage({ - this.title, - this.text, - this.graphic, - this.decoration, - this.layoutStyle, - }); - final Widget? title; - final Widget? text; - final Widget? graphic; - final BoxDecoration? decoration; - final IntroductionLayoutStyle? layoutStyle; -} - -class IntroductionOptions { - const IntroductionOptions({ - this.introductionTranslations = const IntroductionTranslations(), - this.introductionButtonTextstyles = const IntroductionButtonTextstyles(), - this.indicatorMode = IndicatorMode.dot, - this.indicatorBuilder, - this.layoutStyle = IntroductionLayoutStyle.imageBottom, - this.pages = defaultIntroductionPages, - this.buttonMode = IntroductionScreenButtonMode.text, - this.tapEnabled = false, - this.mode = IntroductionScreenMode.showNever, - this.textAlign = TextAlign.center, - this.displayMode = IntroductionDisplayMode.multiPageHorizontal, - this.skippable = false, - this.buttonBuilder, - this.controlMode = IntroductionControlMode.previousNextButton, - this.dotSize = 12, - this.dotSpacing = 24, - this.dotColor, - }) : assert( - !(identical(indicatorMode, IndicatorMode.custom) && - indicatorBuilder == null), - 'When indicator mode is set to custom, ' - 'make sure to define indicatorBuilder', - ); - - /// Determine when the introduction screens needs to be shown. - /// - /// [IntroductionScreenMode.showNever] To disable introduction screens. - /// - /// [IntroductionScreenMode.showAlways] To always show the introduction - /// screens on startup. - /// - /// [IntroductionScreenMode.showOnce] To only show the introduction screens - /// once on startup. - final IntroductionScreenMode mode; - - /// List of introduction pages to set the text, icons or images for the - /// introduction screens. - final List Function(BuildContext context) pages; - - /// Determines whether the user can tap the screen to go to the next - /// introduction screen. - final bool tapEnabled; - - /// Determines what kind of buttons are used to navigate to the next - /// introduction screen. - /// Introduction screens can always be navigated by swiping (or tapping if - /// [tapEnabled] is enabled). - /// - /// [IntroductionScreenButtonMode.text] Use text buttons (text can be set by - /// setting the translation key or using the default appshell translations). - /// - /// [IntroductionScreenButtonMode.icon] Use icon buttons (icons can be - /// changed by providing a icon library) - /// - /// [IntroductionScreenButtonMode.disabled] Disable buttons. - final IntroductionScreenButtonMode buttonMode; - - /// Determines the position of the provided images or icons that are set - /// using [pages]. - /// Every introduction page provided with a image or icon will use the same - /// layout setting. - /// - /// [IntroductionLayoutStyle.imageCenter] Image/icon will be at the center of the introduction page. - /// - /// [IntroductionLayoutStyle.imageTop] Image/icon will be at the top of the introduction page. - /// - /// [IntroductionLayoutStyle.imageBottom] Image/icon will be at the bottom of the introduction page. - final IntroductionLayoutStyle layoutStyle; - - /// Determines the style of the page indicator shown at the bottom on the - /// introduction pages. - /// - /// [IndicatorMode.dot] Shows a dot for each page. - /// - /// [IndicatorMode.dash] Shows a dash for each page. - /// - /// [IndicatorMode.custom] calls indicatorBuilder for the indicator - final IndicatorMode indicatorMode; - - /// Builder that is called when [indicatorMode] is set - /// to [IndicatorMode.custom] - final Widget Function( - BuildContext, - PageController, - int, - int, - )? indicatorBuilder; - - /// Determines whether the user can skip the introduction pages using a button - /// in the header - final bool skippable; - - /// Determines whether the introduction screens should be shown in a single - final TextAlign textAlign; - - /// [IntroductionDisplayMode.multiPageHorizontal] Configured introduction - /// pages will be shown on seperate screens and can be navigated using using - /// buttons (if enabled) or swiping. - /// - /// !Unimplemented! [IntroductionDisplayMode.singleScrollablePageVertical] - /// All configured introduction pages will be shown on a single scrollable - /// page. - /// - final IntroductionDisplayMode displayMode; - - /// When [IntroductionDisplayMode.multiPageHorizontal] is selected multiple - /// controlMode can be selected. - /// - /// [IntroductionControlMode.previousNextButton] shows two buttons at the - /// bottom of the screen to return or proceed. The skip button is placed at - /// the top left of the screen. - /// - /// [IntroductionControlMode.singleButton] contains one button at the bottom - /// of the screen to proceed. Underneath is clickable text to skip if the - /// current page is the first page. If the current page is any different it - /// return to the previous screen. - /// - final IntroductionControlMode controlMode; - - /// A builder that can be used to replace the default text buttons when - /// [IntroductionScreenButtonMode.text] is provided to [buttonMode] - final Widget Function( - BuildContext, - VoidCallback, - Widget, - IntroductionButtonType, - )? buttonBuilder; - - /// The translations for all buttons on the introductionpages - /// - /// See [IntroductionTranslations] for more information - /// The following buttons have a translation: - /// - Skip - /// - Next - /// - Previous - /// - Finish - final IntroductionTranslations introductionTranslations; - - /// The textstyles for all buttons on the introductionpages - /// - /// See [IntroductionButtonTextstyles] for more information - /// The following buttons have a textstyle: - /// - Skip - /// - Next - /// - Previous - /// - Finish - final IntroductionButtonTextstyles introductionButtonTextstyles; - - /// The size of the dots in the indicator. Default is 12 - final double dotSize; - - /// The distance between the center of each dot. Default is 24 - final double dotSpacing; - - /// The color of the dots in the indicator. Default is the primary color of - /// the theme - final Color? dotColor; - - IntroductionOptions copyWith({ - IntroductionScreenMode? mode, - List Function(BuildContext context)? pages, - bool? tapEnabled, - IntroductionScreenButtonMode? buttonMode, - IntroductionLayoutStyle? layoutStyle, - IndicatorMode? indicatorMode, - Widget Function( - BuildContext, - PageController, - int, - int, - )? indicatorBuilder, - bool? skippable, - TextAlign? textAlign, - IntroductionDisplayMode? displayMode, - IntroductionControlMode? controlMode, - Widget Function(BuildContext, VoidCallback, Widget, IntroductionButtonType)? - buttonBuilder, - IntroductionTranslations? introductionTranslations, - IntroductionButtonTextstyles? introductionButtonTextstyles, - }) => - IntroductionOptions( - mode: mode ?? this.mode, - pages: pages ?? this.pages, - tapEnabled: tapEnabled ?? this.tapEnabled, - buttonMode: buttonMode ?? this.buttonMode, - layoutStyle: layoutStyle ?? this.layoutStyle, - indicatorMode: indicatorMode ?? this.indicatorMode, - indicatorBuilder: indicatorBuilder ?? this.indicatorBuilder, - skippable: skippable ?? this.skippable, - textAlign: textAlign ?? this.textAlign, - displayMode: displayMode ?? this.displayMode, - controlMode: controlMode ?? this.controlMode, - buttonBuilder: buttonBuilder ?? this.buttonBuilder, - introductionTranslations: - introductionTranslations ?? this.introductionTranslations, - introductionButtonTextstyles: - introductionButtonTextstyles ?? this.introductionButtonTextstyles, - ); -} - -class IntroductionTranslations { - const IntroductionTranslations({ - this.skipButton = 'Skip', - this.nextButton = 'Next', - this.previousButton = 'Previous', - this.finishButton = 'Get started', - }); - final String skipButton; - final String nextButton; - final String previousButton; - final String finishButton; -} - -class IntroductionButtonTextstyles { - const IntroductionButtonTextstyles({ - this.skipButtonStyle, - this.nextButtonStyle, - this.previousButtonStyle, - this.finishButtonStyle, - }); - final TextStyle? skipButtonStyle; - final TextStyle? nextButtonStyle; - final TextStyle? previousButtonStyle; - final TextStyle? finishButtonStyle; -} diff --git a/packages/flutter_introduction_widget/lib/src/introduction.dart b/packages/flutter_introduction_widget/lib/src/introduction.dart deleted file mode 100644 index f594365..0000000 --- a/packages/flutter_introduction_widget/lib/src/introduction.dart +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; -import 'package:flutter_introduction_widget/src/config/introduction.dart'; -import 'package:flutter_introduction_widget/src/types/page_introduction.dart'; -import 'package:flutter_introduction_widget/src/types/single_introduction.dart'; - -const kAnimationDuration = Duration(milliseconds: 300); - -class IntroductionScreen extends StatelessWidget { - const IntroductionScreen({ - required this.options, - required this.onComplete, - super.key, - this.physics, - this.onNext, - this.onPrevious, - this.onSkip, - }); - - /// The options used to build the introduction screen - final IntroductionOptions options; - - /// A function called when the introductionSceen changes - final VoidCallback onComplete; - - /// A function called when the introductionScreen is skipped - final VoidCallback? onSkip; - final ScrollPhysics? physics; - - /// A function called when the introductionScreen moved to the next page - /// where the page provided is the page where the user currently moved to - final void Function(IntroductionPage)? onNext; - - /// A function called when the introductionScreen moved to the previous page - /// where the page provided is the page where the user currently moved to - final void Function(IntroductionPage)? onPrevious; - - @override - Widget build(BuildContext context) => Scaffold( - backgroundColor: Colors.transparent, - body: Builder( - builder: (context) { - switch (options.displayMode) { - case IntroductionDisplayMode.multiPageHorizontal: - return MultiPageIntroductionScreen( - onComplete: onComplete, - physics: physics, - onSkip: onSkip, - onPrevious: onPrevious, - onNext: onNext, - options: options, - ); - case IntroductionDisplayMode.singleScrollablePageVertical: - return SingleIntroductionPage( - options: options, - ); - } - }, - ), - ); -} diff --git a/packages/flutter_introduction_widget/lib/src/types/page_introduction.dart b/packages/flutter_introduction_widget/lib/src/types/page_introduction.dart deleted file mode 100644 index 2fde74f..0000000 --- a/packages/flutter_introduction_widget/lib/src/types/page_introduction.dart +++ /dev/null @@ -1,810 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:flutter_introduction_widget/src/config/introduction.dart'; -import 'package:flutter_introduction_widget/src/introduction.dart'; -import 'package:flutter_introduction_widget/src/widgets/background.dart'; -import 'package:flutter_introduction_widget/src/widgets/indicator.dart'; -import 'package:flutter_introduction_widget/src/widgets/page_content.dart'; - -/// A screen widget for displaying a multi-page introduction. -/// -/// This widget provides a multi-page introduction experience with options -/// for handling navigation and completion callbacks. -class MultiPageIntroductionScreen extends StatefulWidget { - /// Creates a new instance of [MultiPageIntroductionScreen]. - const MultiPageIntroductionScreen({ - required this.options, - required this.onComplete, - this.physics, - this.onNext, - this.onPrevious, - this.onSkip, - super.key, - }); - - /// Callback function triggered when the introduction is completed. - final VoidCallback onComplete; - - /// Callback function triggered when the "Next" button is pressed. - final void Function(IntroductionPage)? onNext; - - /// Callback function triggered when the "Previous" button is pressed. - final void Function(IntroductionPage)? onPrevious; - - /// Callback function triggered when the "Skip" button is pressed. - final VoidCallback? onSkip; - - /// Physics for the scrolling behavior. - final ScrollPhysics? physics; - - /// Introduction options specifying the configuration of the introduction. - final IntroductionOptions options; - - @override - State createState() => - _MultiPageIntroductionScreenState(); -} - -/// State class for [MultiPageIntroductionScreen]. -/// -/// Manages the state and behavior of the [MultiPageIntroductionScreen] widget. -class _MultiPageIntroductionScreenState - extends State { - final PageController _controller = PageController(); - final ValueNotifier _currentPage = ValueNotifier(0); - - @override - void initState() { - super.initState(); - _controller.addListener(_handleScroll); - } - - void _handleScroll() { - _currentPage.value = _controller.page?.round() ?? 0; - } - - @override - void dispose() { - _controller.removeListener(_handleScroll); - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - var pages = widget.options.pages.call(context); - var translations = widget.options.introductionTranslations; - return Stack( - children: [ - NotificationListener( - onNotification: (notification) { - if (notification is OverscrollNotification) { - if (notification.overscroll > 8) { - widget.onComplete.call(); - } - } - // add bouncing scroll physics support - if (notification is ScrollUpdateNotification) { - var offset = notification.metrics.pixels; - if (offset > notification.metrics.maxScrollExtent + 8) { - widget.onComplete.call(); - } - } - return false; - }, - child: PageView( - controller: _controller, - physics: widget.physics, - children: List.generate( - pages.length, - (index) => ExplainerPage( - onTap: () { - widget.onNext?.call(pages[_currentPage.value]); - }, - controller: _controller, - page: pages[index], - options: widget.options, - index: index, - ), - ), - ), - ), - SafeArea( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (widget.options.controlMode == - IntroductionControlMode.previousNextButton) ...[ - Padding( - padding: const EdgeInsets.only(right: 16.0), - child: SizedBox( - height: 64, - child: AnimatedBuilder( - animation: _controller, - builder: (context, _) => Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - if (widget.options.skippable && !_isLast(pages)) ...[ - TextButton( - onPressed: widget.onComplete, - child: Text(translations.skipButton), - ), - ], - ], - ), - ), - ), - ), - ] else ...[ - const SizedBox.shrink(), - ], - Align( - alignment: Alignment.bottomCenter, - child: Column( - children: [ - AnimatedBuilder( - animation: _currentPage, - builder: (context, _) => Indicator( - options: widget.options, - indicatorBuilder: widget.options.indicatorBuilder, - mode: widget.options.indicatorMode, - controller: _controller, - count: pages.length, - index: _currentPage.value, - dotSize: widget.options.dotSize, - dotSpacing: widget.options.dotSpacing, - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - vertical: 40, - horizontal: 20, - ), - child: AnimatedBuilder( - animation: _controller, - builder: (context, _) { - if (widget.options.controlMode == - IntroductionControlMode.singleButton) { - return IntroductionOneButton( - controller: _controller, - next: _isNext(pages), - previous: _isPrevious, - last: _isLast(pages), - options: widget.options, - onFinish: widget.onComplete, - onNext: () { - widget.onNext?.call(pages[_currentPage.value]); - }, - onPrevious: () { - widget.onNext?.call(pages[_currentPage.value]); - }, - ); - } - - return IntroductionTwoButtons( - controller: _controller, - next: _isNext(pages), - previous: _isPrevious, - last: _isLast(pages), - options: widget.options, - onFinish: widget.onComplete, - onNext: () { - widget.onNext?.call(pages[_currentPage.value]); - }, - onPrevious: () { - widget.onNext?.call(pages[_currentPage.value]); - }, - ); - }, - ), - ), - ], - ), - ), - ], - ), - ), - AnimatedBuilder( - animation: _controller, - builder: (context, _) => IntroductionIconButtons( - controller: _controller, - next: _isNext(pages), - previous: _isPrevious, - last: _isLast(pages), - options: widget.options, - onFinish: widget.onComplete, - onNext: () { - widget.onNext?.call(pages[_currentPage.value]); - }, - onPrevious: () { - widget.onNext?.call(pages[_currentPage.value]); - }, - ), - ), - ], - ); - } - - bool _isLast(List pages) => - _currentPage.value == pages.length - 1; - - bool get _isPrevious => _currentPage.value > 0; - - bool _isNext(List pages) => - _currentPage.value < pages.length - 1; -} - -class ExplainerPage extends StatelessWidget { - const ExplainerPage({ - required this.page, - required this.options, - required this.index, - required this.controller, - this.onTap, - super.key, - }); - - final IntroductionPage page; - final IntroductionOptions options; - final PageController controller; - final int index; - final VoidCallback? onTap; - - @override - Widget build(BuildContext context) { - var theme = Theme.of(context); - return Background( - background: page.decoration, - child: SafeArea( - child: Column( - children: [ - const SizedBox( - height: 64, - ), - Expanded( - child: IntroductionPageContent( - onTap: () { - if (options.tapEnabled) { - onTap?.call(); - } - }, - title: Padding( - padding: const EdgeInsets.symmetric(horizontal: 32), - child: DefaultTextStyle( - style: theme.textTheme.titleMedium!, - child: page.title ?? Text('introduction.$index.title'), - ), - ), - text: Padding( - padding: const EdgeInsets.symmetric(horizontal: 32), - child: DefaultTextStyle( - style: theme.textTheme.bodyMedium!, - child: page.text ?? Text('introduction.$index.description'), - ), - ), - graphic: Expanded( - child: Padding( - padding: const EdgeInsets.all(32), - child: page.graphic, - ), - ), - layoutStyle: page.layoutStyle ?? options.layoutStyle, - ), - ), - const SizedBox( - height: 144, - ), - ], - ), - ), - ); - } -} - -class IntroductionTwoButtons extends StatelessWidget { - const IntroductionTwoButtons({ - required this.options, - required this.controller, - required this.next, - required this.last, - required this.previous, - required this.onFinish, - required this.onNext, - required this.onPrevious, - super.key, - }); - - final IntroductionOptions options; - final PageController controller; - final VoidCallback? onFinish; - final VoidCallback? onNext; - final VoidCallback? onPrevious; - - final bool previous; - final bool next; - final bool last; - - Future _previous() async { - await controller.previousPage( - duration: kAnimationDuration, - curve: Curves.easeInOut, - ); - onPrevious?.call(); - } - - @override - Widget build(BuildContext context) { - var translations = options.introductionTranslations; - var showFinishButton = - options.buttonMode == IntroductionScreenButtonMode.singleFinish; - var theme = Theme.of(context); - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (options.buttonMode == IntroductionScreenButtonMode.text) ...[ - Flexible( - child: Padding( - padding: const EdgeInsets.only(right: 6), - child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 180, - ), - child: Opacity( - opacity: previous ? 1 : 0, - child: IgnorePointer( - ignoring: !previous, - child: options.buttonBuilder?.call( - context, - _previous, - Text( - translations.previousButton, - style: options.introductionButtonTextstyles - .previousButtonStyle ?? - theme.textTheme.bodyMedium, - ), - IntroductionButtonType.previous, - ) ?? - InkWell( - onTap: _previous, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: const Color( - 0xff979797, - ), - ), - ), - child: Center( - child: Padding( - padding: - const EdgeInsets.symmetric(vertical: 4), - child: Text( - translations.previousButton, - style: options.introductionButtonTextstyles - .previousButtonStyle ?? - theme.textTheme.bodyMedium, - ), - ), - ), - ), - ), - ), - ), - ), - ), - ), - if (next) ...[ - Flexible( - child: Padding( - padding: const EdgeInsets.only(left: 6), - child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 180, - ), - child: options.buttonBuilder?.call( - context, - _next, - Text( - translations.nextButton, - style: options.introductionButtonTextstyles - .nextButtonStyle ?? - theme.textTheme.bodyMedium, - ), - IntroductionButtonType.next, - ) ?? - InkWell( - onTap: _next, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: const Color( - 0xff979797, - ), - ), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: Text( - translations.nextButton, - style: options.introductionButtonTextstyles - .nextButtonStyle ?? - theme.textTheme.bodyMedium, - ), - ), - ), - ), - ), - ), - ), - ), - ] else if (last) ...[ - Flexible( - child: Padding( - padding: const EdgeInsets.only(left: 6), - child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 180, - ), - child: options.buttonBuilder?.call( - context, - () { - onFinish?.call(); - }, - Text( - translations.finishButton, - style: options.introductionButtonTextstyles - .finishButtonStyle ?? - theme.textTheme.bodyMedium, - ), - IntroductionButtonType.finish, - ) ?? - InkWell( - onTap: () { - onFinish?.call(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: const Color( - 0xff979797, - ), - ), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: Text( - translations.finishButton, - style: options.introductionButtonTextstyles - .finishButtonStyle ?? - theme.textTheme.bodyMedium, - ), - ), - ), - ), - ), - ), - ), - ), - ] else ...[ - const SizedBox.shrink(), - ], - ] else if (showFinishButton) ...[ - const SizedBox.shrink(), - Expanded( - child: Visibility( - visible: last, - maintainSize: true, - maintainAnimation: true, - maintainState: true, - maintainInteractivity: false, - child: Align( - child: Flexible( - child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 180, - ), - child: options.buttonBuilder?.call( - context, - () { - onFinish?.call(); - }, - Text( - translations.finishButton, - style: options.introductionButtonTextstyles - .finishButtonStyle ?? - theme.textTheme.bodyMedium, - ), - IntroductionButtonType.finish, - ) ?? - InkWell( - onTap: () { - onFinish?.call(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: const Color( - 0xff979797, - ), - ), - ), - child: Center( - child: Padding( - padding: - const EdgeInsets.symmetric(vertical: 4), - child: Text( - translations.finishButton, - style: options.introductionButtonTextstyles - .finishButtonStyle ?? - theme.textTheme.bodyMedium, - ), - ), - ), - ), - ), - ), - ), - ), - ), - ), - const SizedBox.shrink(), - ], - ], - ); - } - - Future _next() async { - await controller.nextPage( - duration: kAnimationDuration, - curve: Curves.easeInOut, - ); - onNext?.call(); - } -} - -class IntroductionOneButton extends StatelessWidget { - const IntroductionOneButton({ - required this.options, - required this.controller, - required this.next, - required this.last, - required this.previous, - required this.onFinish, - required this.onNext, - required this.onPrevious, - super.key, - }); - - /// Options specifying the configuration of the introduction. - final IntroductionOptions options; - - /// Controller for managing the pages of the introduction. - final PageController controller; - - /// Callback function triggered when the introduction is completed. - final VoidCallback? onFinish; - - /// Callback function triggered when the "Next" button is pressed. - final VoidCallback? onNext; - - /// Callback function triggered when the "Previous" button is pressed. - final VoidCallback? onPrevious; - - /// Indicates whether there are previous pages. - final bool previous; - - /// Indicates whether there are next pages. - final bool next; - - /// Indicates whether this is the last page. - final bool last; - - /// Handles the navigation to the previous page. - Future _previous() async { - await controller.previousPage( - duration: kAnimationDuration, - curve: Curves.easeInOut, - ); - onPrevious?.call(); - } - - @override - Widget build(BuildContext context) { - var translations = options.introductionTranslations; - - return Column( - children: [ - if (options.buttonMode == IntroductionScreenButtonMode.text) ...[ - if (last) ...[ - options.buttonBuilder?.call( - context, - () { - onFinish?.call(); - }, - Text( - translations.finishButton, - style: - options.introductionButtonTextstyles.finishButtonStyle, - ), - IntroductionButtonType.finish, - ) ?? - TextButton( - onPressed: () { - onFinish?.call(); - }, - child: Text( - translations.finishButton, - style: - options.introductionButtonTextstyles.finishButtonStyle, - ), - ), - ] else ...[ - options.buttonBuilder?.call( - context, - _next, - Text( - translations.nextButton, - style: options.introductionButtonTextstyles.nextButtonStyle, - ), - IntroductionButtonType.next, - ) ?? - TextButton( - onPressed: _next, - child: Text( - translations.nextButton, - style: options.introductionButtonTextstyles.nextButtonStyle, - ), - ), - ], - if (previous) ...[ - options.buttonBuilder?.call( - context, - _previous, - Text( - translations.previousButton, - style: options - .introductionButtonTextstyles.previousButtonStyle, - ), - IntroductionButtonType.previous, - ) ?? - TextButton( - onPressed: _previous, - child: Text( - translations.previousButton, - style: options - .introductionButtonTextstyles.previousButtonStyle, - ), - ), - ] else ...[ - options.buttonBuilder?.call( - context, - () { - onFinish?.call(); - }, - Text( - translations.finishButton, - style: - options.introductionButtonTextstyles.finishButtonStyle, - ), - IntroductionButtonType.skip, - ) ?? - TextButton( - onPressed: () { - onFinish?.call(); - }, - child: Text( - translations.finishButton, - style: - options.introductionButtonTextstyles.finishButtonStyle, - ), - ), - ], - ], - ], - ); - } - - Future _next() async { - await controller.nextPage( - duration: kAnimationDuration, - curve: Curves.easeInOut, - ); - onNext?.call(); - } -} - -class IntroductionIconButtons extends StatelessWidget { - const IntroductionIconButtons({ - required this.options, - required this.controller, - required this.next, - required this.last, - required this.previous, - required this.onFinish, - required this.onNext, - required this.onPrevious, - super.key, - }); - - /// Options specifying the configuration of the introduction. - final IntroductionOptions options; - - /// Controller for managing the pages of the introduction. - final PageController controller; - - /// Callback function triggered when the introduction is completed. - final VoidCallback? onFinish; - - /// Callback function triggered when the "Next" button is pressed. - final VoidCallback? onNext; - - /// Callback function triggered when the "Previous" button is pressed. - final VoidCallback? onPrevious; - - /// Indicates whether there are previous pages. - final bool previous; - - /// Indicates whether there are next pages. - final bool next; - - /// Indicates whether this is the last page. - final bool last; - - /// Handles the navigation to the previous page. - Future _previous() async { - await controller.previousPage( - duration: kAnimationDuration, - curve: Curves.easeInOut, - ); - onPrevious?.call(); - } - - @override - Widget build(BuildContext context) => Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (options.buttonMode == IntroductionScreenButtonMode.icon) ...[ - if (previous) ...[ - IconButton( - iconSize: 70, - onPressed: _previous, - icon: const Icon(Icons.chevron_left), - ), - ] else - const SizedBox.shrink(), - IconButton( - iconSize: 70, - onPressed: () { - if (next) { - unawaited(_next()); - } else { - onFinish?.call(); - } - }, - icon: const Icon(Icons.chevron_right), - ), - ], - ], - ), - ); - - Future _next() async { - await controller.nextPage( - duration: kAnimationDuration, - curve: Curves.easeInOut, - ); - onNext?.call(); - } -} diff --git a/packages/flutter_introduction_widget/lib/src/types/single_introduction.dart b/packages/flutter_introduction_widget/lib/src/types/single_introduction.dart deleted file mode 100644 index f58b8ca..0000000 --- a/packages/flutter_introduction_widget/lib/src/types/single_introduction.dart +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/cupertino.dart'; - -import 'package:flutter_introduction_widget/src/config/introduction.dart'; - -/// Widget representing a single introduction page. -class SingleIntroductionPage extends StatelessWidget { - /// Constructs a [SingleIntroductionPage] widget. - const SingleIntroductionPage({ - required this.options, - super.key, - }); - - /// Options specifying the configuration of the introduction. - final IntroductionOptions options; - - @override - Widget build(BuildContext context) { - throw UnimplementedError(); - } -} diff --git a/packages/flutter_introduction_widget/lib/src/widgets/background.dart b/packages/flutter_introduction_widget/lib/src/widgets/background.dart deleted file mode 100644 index 204b65e..0000000 --- a/packages/flutter_introduction_widget/lib/src/widgets/background.dart +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; - -/// Widget representing a background with optional decoration. -class Background extends StatelessWidget { - /// Constructs a Background widget. - const Background({ - required this.child, - this.background, - super.key, - }); - - /// Optional decoration for the background. - final BoxDecoration? background; - - /// The widget to be placed on the background. - final Widget child; - - @override - Widget build(BuildContext context) { - var theme = Theme.of(context); - var background = this.background ?? - BoxDecoration( - color: theme.colorScheme.surface, - ); - var size = MediaQuery.of(context).size; - return Container( - width: size.width, - height: size.height, - decoration: background, - child: child, - ); - } -} diff --git a/packages/flutter_introduction_widget/lib/src/widgets/indicator.dart b/packages/flutter_introduction_widget/lib/src/widgets/indicator.dart deleted file mode 100644 index 67f1f3f..0000000 --- a/packages/flutter_introduction_widget/lib/src/widgets/indicator.dart +++ /dev/null @@ -1,221 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:flutter_introduction_widget/src/config/introduction.dart'; -import 'package:flutter_introduction_widget/src/introduction.dart'; - -class Indicator extends StatelessWidget { - const Indicator({ - required this.mode, - required this.controller, - required this.count, - required this.index, - required this.indicatorBuilder, - required this.dotSize, - required this.dotSpacing, - required this.options, - super.key, - }) : assert( - !(mode == IndicatorMode.custom && indicatorBuilder == null), - 'When a custom indicator is used the indicatorBuilder ' - 'must be provided', - ); - - /// The mode of the indicator. - final IndicatorMode mode; - - /// The PageController for which the indicator is displayed. - final PageController controller; - - /// The total number of items managed by the PageController. - final int count; - - /// The index of the current item in the PageController. - final int index; - - /// Builder function for a custom indicator. - final Widget Function(BuildContext, PageController, int, int)? - indicatorBuilder; - - /// The size of the dots. - final double dotSize; - - /// The distance between the center of each dot. - final double dotSpacing; - - final IntroductionOptions options; - - @override - Widget build(BuildContext context) { - var theme = Theme.of(context); - switch (mode) { - case IndicatorMode.custom: - return indicatorBuilder!.call(context, controller, index, count); - case IndicatorMode.dot: - return DotsIndicator( - dotSize: dotSize, - dotSpacing: dotSpacing, - controller: controller, - color: options.dotColor ?? theme.colorScheme.primary, - itemCount: count, - onPageSelected: (int page) { - unawaited( - controller.animateToPage( - page, - duration: kAnimationDuration, - curve: Curves.easeInOut, - ), - ); - }, - ); - case IndicatorMode.dash: - return DashIndicator( - color: theme.colorScheme.primary, - controller: controller, - selectedColor: options.dotColor ?? theme.colorScheme.primary, - itemCount: count, - onPageSelected: (int page) { - unawaited( - controller.animateToPage( - page, - duration: kAnimationDuration, - curve: Curves.easeInOut, - ), - ); - }, - ); - } - } -} - -class DashIndicator extends AnimatedWidget { - const DashIndicator({ - required this.controller, - required this.selectedColor, - required this.itemCount, - required this.onPageSelected, - this.color = Colors.white, - super.key, - }) : super(listenable: controller); - - /// The PageController for which the indicator is displayed. - final PageController controller; - - /// The color of the dashes. - final Color color; - - /// The color of the selected dash. - final Color selectedColor; - - /// The total number of items managed by the PageController. - final int itemCount; - - /// Callback function called when a dash is selected. - final Function(int) onPageSelected; - - int _getPage() { - try { - return controller.page?.round() ?? 0; - } on Exception catch (_) { - return 0; - } - } - - @override - Widget build(BuildContext context) { - var index = _getPage(); - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - for (int i = 0; i < itemCount; i++) ...[ - buildDash(i, selected: index == i), - ], - ], - ); - } - - Widget buildDash(int index, {required bool selected}) => SizedBox( - width: 20, - child: Center( - child: Material( - color: selected ? color : color.withAlpha(125), - type: MaterialType.card, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(2.5), - ), - width: 16, - height: 5, - child: InkWell( - onTap: () => onPageSelected.call(index), - ), - ), - ), - ), - ); -} - -/// An indicator showing the currently selected page of a PageController -class DotsIndicator extends AnimatedWidget { - const DotsIndicator({ - required this.controller, - this.color = Colors.white, - this.itemCount, - this.onPageSelected, - this.dotSize = 8.0, - this.dotSpacing = 24.0, - super.key, - }) : super( - listenable: controller, - ); - - final PageController controller; - - /// The number of items managed by the PageController - final int? itemCount; - - /// Called when a dot is tapped - final ValueChanged? onPageSelected; - - /// The color of the dots. - /// - /// Defaults to `Colors.white`. - final Color color; - - // The base size of the dots - final double dotSize; - final double dotSpacing; - - Widget _buildDot(int index) => SizedBox( - width: dotSpacing, - child: Center( - child: Material( - color: - (((controller.page ?? controller.initialPage).round()) == index - ? color - : color.withAlpha(62)), - type: MaterialType.circle, - child: Container( - decoration: const BoxDecoration( - shape: BoxShape.circle, - ), - width: dotSize, - height: dotSize, - child: InkWell( - onTap: () => onPageSelected!.call(index), - ), - ), - ), - ), - ); - - @override - Widget build(BuildContext context) => Row( - mainAxisAlignment: MainAxisAlignment.center, - children: List.generate(itemCount!, _buildDot), - ); -} diff --git a/packages/flutter_introduction_widget/lib/src/widgets/page_content.dart b/packages/flutter_introduction_widget/lib/src/widgets/page_content.dart deleted file mode 100644 index 5449816..0000000 --- a/packages/flutter_introduction_widget/lib/src/widgets/page_content.dart +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; - -import 'package:flutter_introduction_widget/src/config/introduction.dart'; - -/// Widget representing the content of an introduction page. -class IntroductionPageContent extends StatelessWidget { - /// Constructs an IntroductionPageContent widget. - const IntroductionPageContent({ - required this.title, - required this.text, - required this.graphic, - required this.layoutStyle, - required this.onTap, - super.key, - }); - - /// The title widget. - final Widget? title; - - /// The text widget. - final Widget? text; - - /// The graphic widget. - final Widget? graphic; - - /// The layout style of the content. - final IntroductionLayoutStyle layoutStyle; - - /// Callback function called when the content is tapped. - final VoidCallback onTap; - - @override - Widget build(BuildContext context) => GestureDetector( - onTap: onTap, - child: Column( - children: [ - if (graphic != null && - layoutStyle == IntroductionLayoutStyle.imageTop) - graphic!, - if (title != null) title!, - if (graphic != null && - layoutStyle == IntroductionLayoutStyle.imageCenter) - graphic!, - if (text != null) text!, - if (graphic != null && - layoutStyle == IntroductionLayoutStyle.imageBottom) - graphic!, - ], - ), - ); -} diff --git a/packages/flutter_introduction_widget/pubspec.yaml b/packages/flutter_introduction_widget/pubspec.yaml deleted file mode 100644 index 43ab608..0000000 --- a/packages/flutter_introduction_widget/pubspec.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: flutter_introduction_widget -description: Flutter Introduction Widget for showing a list of introduction pages on a single scrollable page or horizontal pageview -version: 5.0.0 -homepage: https://github.com/Iconica-Development/flutter_introduction_widget - -publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub - -environment: - sdk: ">=3.0.0 <4.0.0" - flutter: ">=1.17.0" - -dependencies: - flutter: - sdk: flutter - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_iconica_analysis: - git: - url: https://github.com/Iconica-Development/flutter_iconica_analysis - ref: 6.0.0 - -flutter: - assets: - - assets/ diff --git a/packages/flutter_introduction_widget/test/flutter_introduction_test.dart b/packages/flutter_introduction_widget/test/flutter_introduction_test.dart deleted file mode 100644 index c62bf12..0000000 --- a/packages/flutter_introduction_widget/test/flutter_introduction_test.dart +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test('test', () { - expect(true, true); - }); -} diff --git a/packages/flutter_introduction_interface/.gitignore b/packages/introduction_repository_interface/.gitignore similarity index 94% rename from packages/flutter_introduction_interface/.gitignore rename to packages/introduction_repository_interface/.gitignore index 35b14c4..ac5aa98 100644 --- a/packages/flutter_introduction_interface/.gitignore +++ b/packages/introduction_repository_interface/.gitignore @@ -19,14 +19,11 @@ migrate_working_dir/ # 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/ +#.vscode/ # Flutter/Dart/Pub related # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. /pubspec.lock **/doc/api/ .dart_tool/ -.packages build/ - -.metadata diff --git a/packages/flutter_introduction_service/analysis_options.yaml b/packages/introduction_repository_interface/analysis_options.yaml similarity index 98% rename from packages/flutter_introduction_service/analysis_options.yaml rename to packages/introduction_repository_interface/analysis_options.yaml index 8ea00ce..31b4b51 100644 --- a/packages/flutter_introduction_service/analysis_options.yaml +++ b/packages/introduction_repository_interface/analysis_options.yaml @@ -4,6 +4,6 @@ include: package:flutter_iconica_analysis/analysis_options.yaml analyzer: exclude: - + linter: rules: diff --git a/packages/introduction_repository_interface/lib/introduction_repository_interface.dart b/packages/introduction_repository_interface/lib/introduction_repository_interface.dart new file mode 100644 index 0000000..28b2c73 --- /dev/null +++ b/packages/introduction_repository_interface/lib/introduction_repository_interface.dart @@ -0,0 +1,19 @@ +/// +// ignore_for_file: directives_ordering + +library introduction_repository_interface; + +// interfaces +export "src/interfaces/introduction_repository_interface.dart"; + +// local +export "src/local/local_introduction_repository.dart"; + +// models +export "src/models/introduction_page_data.dart"; + +// services +export "src/services/introduction_service.dart"; + +// enums +export "src/enums/image_mode.dart"; diff --git a/packages/introduction_repository_interface/lib/src/enums/image_mode.dart b/packages/introduction_repository_interface/lib/src/enums/image_mode.dart new file mode 100644 index 0000000..6bbfd5b --- /dev/null +++ b/packages/introduction_repository_interface/lib/src/enums/image_mode.dart @@ -0,0 +1,4 @@ +enum ImageMode { + asset, + network, +} diff --git a/packages/introduction_repository_interface/lib/src/interfaces/introduction_repository_interface.dart b/packages/introduction_repository_interface/lib/src/interfaces/introduction_repository_interface.dart new file mode 100644 index 0000000..927e5ad --- /dev/null +++ b/packages/introduction_repository_interface/lib/src/interfaces/introduction_repository_interface.dart @@ -0,0 +1,10 @@ +import "package:introduction_repository_interface/introduction_repository_interface.dart"; + +/// Interface for the introduction repository. +abstract class IntroductionRepositoryInterface { + Future> fetchIntroductionPages(); + + Future setCompleted({bool value = true}); + + Future shouldShow(); +} diff --git a/packages/introduction_repository_interface/lib/src/local/local_introduction_repository.dart b/packages/introduction_repository_interface/lib/src/local/local_introduction_repository.dart new file mode 100644 index 0000000..9559875 --- /dev/null +++ b/packages/introduction_repository_interface/lib/src/local/local_introduction_repository.dart @@ -0,0 +1,17 @@ +import "package:introduction_repository_interface/introduction_repository_interface.dart"; + +class LocalIntroductionRepository implements IntroductionRepositoryInterface { + var _completed = false; + @override + Future setCompleted({bool value = true}) async { + _completed = value; + } + + @override + Future shouldShow() async => !_completed; + + @override + Future> fetchIntroductionPages() { + throw Exception(); + } +} diff --git a/packages/introduction_repository_interface/lib/src/models/introduction_page_data.dart b/packages/introduction_repository_interface/lib/src/models/introduction_page_data.dart new file mode 100644 index 0000000..6cef6c4 --- /dev/null +++ b/packages/introduction_repository_interface/lib/src/models/introduction_page_data.dart @@ -0,0 +1,37 @@ +import "package:introduction_repository_interface/src/enums/image_mode.dart"; + +class IntroductionPageData { + const IntroductionPageData({ + required this.id, + required this.title, + required this.description, + required this.graphic, + this.imageMode = ImageMode.asset, + }); + + factory IntroductionPageData.fromJson(Map json) => + IntroductionPageData( + id: json["id"], + title: json["title"], + description: json["description"], + graphic: json["graphic"], + imageMode: + json["imageMode"] == "asset" ? ImageMode.asset : ImageMode.network, + ); + + final int id; + final String title; + final String description; + final String graphic; + final ImageMode imageMode; + + //tojson + + Map toJson() => { + "id": id, + "title": title, + "description": description, + "graphic": graphic, + "imageMode": imageMode == ImageMode.asset ? "asset" : "network", + }; +} diff --git a/packages/introduction_repository_interface/lib/src/services/introduction_service.dart b/packages/introduction_repository_interface/lib/src/services/introduction_service.dart new file mode 100644 index 0000000..52dac1b --- /dev/null +++ b/packages/introduction_repository_interface/lib/src/services/introduction_service.dart @@ -0,0 +1,19 @@ +import "package:introduction_repository_interface/introduction_repository_interface.dart"; + +class IntroductionService { + IntroductionService({ + IntroductionRepositoryInterface? introductionRepositoryInterface, + }) : introductionRepositoryInterface = + introductionRepositoryInterface ?? LocalIntroductionRepository(); + + final IntroductionRepositoryInterface introductionRepositoryInterface; + + Future> fetchIntroductionPages() async => + introductionRepositoryInterface.fetchIntroductionPages(); + + Future setCompleted({bool value = true}) async => + introductionRepositoryInterface.setCompleted(value: value); + + Future shouldShow() async => + introductionRepositoryInterface.shouldShow(); +} diff --git a/packages/introduction_repository_interface/pubspec.yaml b/packages/introduction_repository_interface/pubspec.yaml new file mode 100644 index 0000000..3529137 --- /dev/null +++ b/packages/introduction_repository_interface/pubspec.yaml @@ -0,0 +1,55 @@ +name: introduction_repository_interface +description: "A flutter introduction repository interface" +version: 6.0.0 +homepage: none + +environment: + sdk: ^3.5.3 + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + flutter_iconica_analysis: + git: + url: https://github.com/Iconica-Development/flutter_iconica_analysis + ref: 7.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/shared_preferences_introduction_repository/.flutter-plugins b/packages/shared_preferences_introduction_repository/.flutter-plugins new file mode 100644 index 0000000..fb2ba18 --- /dev/null +++ b/packages/shared_preferences_introduction_repository/.flutter-plugins @@ -0,0 +1,9 @@ +# This is a generated file; do not edit or check into version control. +path_provider_linux=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ +path_provider_windows=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/ +shared_preferences=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/shared_preferences-2.5.2/ +shared_preferences_android=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.5/ +shared_preferences_foundation=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/ +shared_preferences_linux=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/ +shared_preferences_web=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.2/ +shared_preferences_windows=/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/ diff --git a/packages/shared_preferences_introduction_repository/.flutter-plugins-dependencies b/packages/shared_preferences_introduction_repository/.flutter-plugins-dependencies new file mode 100644 index 0000000..ffde978 --- /dev/null +++ b/packages/shared_preferences_introduction_repository/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"shared_preferences_foundation","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"shared_preferences_android","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.5/","native_build":true,"dependencies":[]}],"macos":[{"name":"shared_preferences_foundation","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"path_provider_windows","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"shared_preferences_web","path":"/Users/mikedoornenbal/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.2/","dependencies":[]}]},"dependencyGraph":[{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2025-02-18 10:39:03.115183","version":"3.24.3","swift_package_manager_enabled":false} \ No newline at end of file diff --git a/packages/flutter_introduction_shared_preferences/.gitignore b/packages/shared_preferences_introduction_repository/.gitignore similarity index 87% rename from packages/flutter_introduction_shared_preferences/.gitignore rename to packages/shared_preferences_introduction_repository/.gitignore index 7a69d18..ac5aa98 100644 --- a/packages/flutter_introduction_shared_preferences/.gitignore +++ b/packages/shared_preferences_introduction_repository/.gitignore @@ -19,16 +19,11 @@ migrate_working_dir/ # 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/ +#.vscode/ # Flutter/Dart/Pub related # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. /pubspec.lock **/doc/api/ .dart_tool/ -.packages build/ - -.metadata -.flutter-plugins -.flutter-plugins-dependencies diff --git a/packages/flutter_introduction_shared_preferences/analysis_options.yaml b/packages/shared_preferences_introduction_repository/analysis_options.yaml similarity index 98% rename from packages/flutter_introduction_shared_preferences/analysis_options.yaml rename to packages/shared_preferences_introduction_repository/analysis_options.yaml index 8ea00ce..31b4b51 100644 --- a/packages/flutter_introduction_shared_preferences/analysis_options.yaml +++ b/packages/shared_preferences_introduction_repository/analysis_options.yaml @@ -4,6 +4,6 @@ include: package:flutter_iconica_analysis/analysis_options.yaml analyzer: exclude: - + linter: rules: diff --git a/packages/shared_preferences_introduction_repository/lib/shared_preferences_introduction_repository.dart b/packages/shared_preferences_introduction_repository/lib/shared_preferences_introduction_repository.dart new file mode 100644 index 0000000..f6077a5 --- /dev/null +++ b/packages/shared_preferences_introduction_repository/lib/shared_preferences_introduction_repository.dart @@ -0,0 +1,4 @@ +/// +library shared_preferences_introduction_repository; + +export "src/shared_preferences_introduction_repository.dart"; diff --git a/packages/shared_preferences_introduction_repository/lib/src/shared_preferences_introduction_repository.dart b/packages/shared_preferences_introduction_repository/lib/src/shared_preferences_introduction_repository.dart new file mode 100644 index 0000000..a7677e8 --- /dev/null +++ b/packages/shared_preferences_introduction_repository/lib/src/shared_preferences_introduction_repository.dart @@ -0,0 +1,23 @@ +import "package:introduction_repository_interface/introduction_repository_interface.dart"; +import "package:shared_preferences/shared_preferences.dart"; + +class SharedPreferencesIntroductionRepository + implements IntroductionRepositoryInterface { + @override + Future> fetchIntroductionPages() async { + throw Exception(); + } + + @override + Future setCompleted({bool value = true}) async { + var sharedPrefs = await SharedPreferences.getInstance(); + await sharedPrefs.setBool("_completedIntroduction", value); + } + + @override + Future shouldShow() async { + var sharedPrefs = await SharedPreferences.getInstance(); + var shouldShow = sharedPrefs.getBool("_completedIntroduction") ?? true; + return !shouldShow; + } +} diff --git a/packages/shared_preferences_introduction_repository/pubspec.yaml b/packages/shared_preferences_introduction_repository/pubspec.yaml new file mode 100644 index 0000000..6a17673 --- /dev/null +++ b/packages/shared_preferences_introduction_repository/pubspec.yaml @@ -0,0 +1,57 @@ +name: shared_preferences_introduction_repository +description: "A new Flutter package project." +version: 0.0.1 +publish_to: none + +environment: + sdk: ^3.5.3 + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + shared_preferences: ^2.5.2 + introduction_repository_interface: + path: ../introduction_repository_interface + +dev_dependencies: + flutter_iconica_analysis: + git: + url: https://github.com/Iconica-Development/flutter_iconica_analysis + ref: 7.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +