From 0c0f664608fe0420e81673da37741b8d8beb4fab Mon Sep 17 00:00:00 2001 From: ImranIF Date: Wed, 13 Dec 2023 01:28:56 +0600 Subject: [PATCH 01/19] added collapsible side bar --- .gitignore | 88 +- .metadata | 90 +- .vscode/launch.json | 31 + .vscode/settings.json | 3 + README.md | 164 +- analysis_options.yaml | 58 +- android/.gitignore | 26 +- android/app/build.gradle | 155 +- android/app/google-services.json | 7 + android/app/src/debug/AndroidManifest.xml | 14 +- android/app/src/main/AndroidManifest.xml | 66 +- .../com/kais29/retrieve_me/MainActivity.kt | 12 +- .../res/drawable-v21/launch_background.xml | 24 +- .../main/res/drawable/launch_background.xml | 24 +- .../app/src/main/res/values-night/styles.xml | 36 +- android/app/src/main/res/values/styles.xml | 36 +- android/app/src/profile/AndroidManifest.xml | 14 +- android/build.gradle | 68 +- android/gradle.properties | 6 +- .../gradle/wrapper/gradle-wrapper.properties | 20 +- android/settings.gradle | 22 +- ios/.gitignore | 68 +- ios/Flutter/AppFrameworkInfo.plist | 52 +- ios/Flutter/Debug.xcconfig | 2 +- ios/Flutter/Release.xcconfig | 2 +- ios/Runner.xcodeproj/project.pbxproj | 1226 +++++++-------- .../contents.xcworkspacedata | 14 +- .../xcshareddata/IDEWorkspaceChecks.plist | 16 +- .../xcshareddata/WorkspaceSettings.xcsettings | 16 +- .../xcshareddata/xcschemes/Runner.xcscheme | 196 +-- .../contents.xcworkspacedata | 14 +- .../xcshareddata/IDEWorkspaceChecks.plist | 16 +- .../xcshareddata/WorkspaceSettings.xcsettings | 16 +- ios/Runner/AppDelegate.swift | 26 +- .../AppIcon.appiconset/Contents.json | 244 +-- .../LaunchImage.imageset/Contents.json | 46 +- .../LaunchImage.imageset/README.md | 8 +- ios/Runner/Base.lproj/LaunchScreen.storyboard | 74 +- ios/Runner/Base.lproj/Main.storyboard | 52 +- ios/Runner/GoogleService-Info.plist | 66 +- ios/Runner/Info.plist | 102 +- ios/Runner/Runner-Bridging-Header.h | 2 +- ios/RunnerTests/RunnerTests.swift | 24 +- lib/Components/drawer_item.dart | 9 + lib/Components/drawer_items.dart | 17 + lib/Components/my_button.dart | 64 +- lib/Components/my_textfield.dart | 106 +- lib/Components/navigation_drawer_widget.dart | 196 +++ lib/Components/square_tile.dart | 50 +- lib/firebase_options.dart | 15 +- lib/main.dart | 31 +- lib/pages/login.dart | 435 +++--- lib/pages/postFoundItem.dart | 781 ++++----- lib/pages/postLostItem.dart | 837 +++++----- lib/pages/registration.dart | 618 ++++---- lib/provider/navigation_provider.dart | 11 + lib/tempCodeRunnerFile.dart | 6 +- linux/.gitignore | 2 +- linux/CMakeLists.txt | 278 ++-- linux/flutter/CMakeLists.txt | 176 +-- linux/main.cc | 12 +- linux/my_application.cc | 208 +-- linux/my_application.h | 36 +- macos/.gitignore | 14 +- macos/Flutter/Flutter-Debug.xcconfig | 2 +- macos/Flutter/Flutter-Release.xcconfig | 2 +- macos/Runner.xcodeproj/project.pbxproj | 1390 ++++++++--------- .../xcshareddata/IDEWorkspaceChecks.plist | 16 +- .../xcshareddata/xcschemes/Runner.xcscheme | 196 +-- .../contents.xcworkspacedata | 14 +- .../xcshareddata/IDEWorkspaceChecks.plist | 16 +- macos/Runner/AppDelegate.swift | 18 +- .../AppIcon.appiconset/Contents.json | 136 +- macos/Runner/Base.lproj/MainMenu.xib | 686 ++++---- macos/Runner/Configs/AppInfo.xcconfig | 28 +- macos/Runner/Configs/Debug.xcconfig | 4 +- macos/Runner/Configs/Release.xcconfig | 4 +- macos/Runner/Configs/Warnings.xcconfig | 26 +- macos/Runner/DebugProfile.entitlements | 24 +- macos/Runner/Info.plist | 64 +- macos/Runner/MainFlutterWindow.swift | 30 +- macos/Runner/Release.entitlements | 16 +- macos/RunnerTests/RunnerTests.swift | 24 +- node_modules/.package-lock.json | 24 +- node_modules/g/LICENSE | 38 +- node_modules/g/README.md | 64 +- node_modules/g/index.js | 92 +- node_modules/g/package.json | 22 +- node_modules/g/test.js | 14 +- package-lock.json | 34 +- package.json | 10 +- pubspec.lock | 1156 +++++++------- pubspec.yaml | 199 +-- test/widget_test.dart | 59 +- web/index.html | 118 +- web/manifest.json | 70 +- windows/.gitignore | 34 +- windows/CMakeLists.txt | 204 +-- windows/flutter/CMakeLists.txt | 208 +-- .../flutter/generated_plugin_registrant.cc | 6 + windows/flutter/generated_plugins.cmake | 2 + windows/runner/CMakeLists.txt | 80 +- windows/runner/Runner.rc | 242 +-- windows/runner/flutter_window.cpp | 132 +- windows/runner/flutter_window.h | 66 +- windows/runner/main.cpp | 86 +- windows/runner/resource.h | 32 +- windows/runner/runner.exe.manifest | 40 +- windows/runner/utils.cpp | 130 +- windows/runner/utils.h | 38 +- windows/runner/win32_window.cpp | 576 +++---- windows/runner/win32_window.h | 204 +-- 112 files changed, 7094 insertions(+), 6730 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 lib/Components/drawer_item.dart create mode 100644 lib/Components/drawer_items.dart create mode 100644 lib/Components/navigation_drawer_widget.dart create mode 100644 lib/provider/navigation_provider.dart diff --git a/.gitignore b/.gitignore index 24476c5..70ccb97 100644 --- a/.gitignore +++ b/.gitignore @@ -1,44 +1,44 @@ -# 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 +# 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/.metadata b/.metadata index 30d90a7..973a167 100644 --- a/.metadata +++ b/.metadata @@ -1,45 +1,45 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled. - -version: - revision: 796c8ef79279f9c774545b3771238c3098dbefab - channel: stable - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: 796c8ef79279f9c774545b3771238c3098dbefab - base_revision: 796c8ef79279f9c774545b3771238c3098dbefab - - platform: android - create_revision: 796c8ef79279f9c774545b3771238c3098dbefab - base_revision: 796c8ef79279f9c774545b3771238c3098dbefab - - platform: ios - create_revision: 796c8ef79279f9c774545b3771238c3098dbefab - base_revision: 796c8ef79279f9c774545b3771238c3098dbefab - - platform: linux - create_revision: 796c8ef79279f9c774545b3771238c3098dbefab - base_revision: 796c8ef79279f9c774545b3771238c3098dbefab - - platform: macos - create_revision: 796c8ef79279f9c774545b3771238c3098dbefab - base_revision: 796c8ef79279f9c774545b3771238c3098dbefab - - platform: web - create_revision: 796c8ef79279f9c774545b3771238c3098dbefab - base_revision: 796c8ef79279f9c774545b3771238c3098dbefab - - platform: windows - create_revision: 796c8ef79279f9c774545b3771238c3098dbefab - base_revision: 796c8ef79279f9c774545b3771238c3098dbefab - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: 796c8ef79279f9c774545b3771238c3098dbefab + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: android + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: ios + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: linux + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: macos + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: web + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: windows + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5861b4c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,31 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter: Attach to Device", + "type": "dart", + "request": "attach" + }, + + { + "name": "retrieve_me", + "request": "launch", + "type": "dart" + }, + { + "name": "retrieve_me (profile mode)", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "retrieve_me (release mode)", + "request": "launch", + "type": "dart", + "flutterMode": "release" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..cad7657 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.configureOnOpen": false +} \ No newline at end of file diff --git a/README.md b/README.md index fe95b3d..62c8506 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,82 @@ -# Setup Guide for "Retrieve Me" Project - -Welcome to the setup guide for the "Retrieve Me" project, a Flutter and Firebase-based application developed using Agile methodologies. In this guide, we will walk you through the process of setting up the project on your local machine for development and testing purposes. - -## Prerequisites - -Before you begin, make sure you have the following prerequisites installed on your system: - -1. **Git**: Version control system for cloning the project repository. -2. **Flutter**: SDK for building native applications using the Dart programming language. -3. **Firebase Account**: Access to Firebase console for project configuration. -4. **Android Studio** or **VS Code**: Integrated development environment (IDE) for Flutter development. -5. **Android/iOS Emulator** or a physical device for testing. - -## Step-by-Step Setup Process - -Follow these steps to set up the "Retrieve Me" project on your local machine: - -### 1. Clone the Repository - -Open a terminal and execute the following command to clone the project repository: - -```bash -git clone https://github.com/Md-Kais/retrieve_me.git -``` - -### 2. Set Up Firebase - -1. User have to provide me his EMAIL to access the firebase database. - -### 3. Install Dependencies - -Navigate to the project directory and install the required dependencies using the following command: - -```bash -cd retrieve_me -flutter pub get -``` - -### 4. Run the Application - -Use your preferred IDE (Android Studio or VS Code) to open the project directory. - -#### Running on Android Emulator/Device - -1. Ensure your Android emulator or physical device is connected. -2. Run the app using the IDE's run button or execute the following command in the terminal: - -```bash -flutter run -``` - -#### Running on iOS Simulator/Device - -1. Ensure you have Xcode installed on macOS. -2. Open the `ios/Runner.xcworkspace` file in Xcode. -3. Select your desired simulator or device. -4. Click the run button or use the following command: - -```bash -flutter run -``` - -### 5. Testing - -You can now interact with the "Retrieve Me" app on the emulator or device. Explore its features and functionalities to ensure everything is working as expected. - -## Contributing and Agile Workflow - -If you're interested in contributing to the project, we follow an Agile development workflow using Git. Create a new branch for your feature or bug fix, make your changes, and submit a pull request to the `develop` branch. - -For Agile-related tasks, we use tools like Trello to manage user stories, tasks, and sprints. Feel free to join our Agile boards and participate in the development process. - -## Conclusion - -Congratulations! You've successfully set up the "Retrieve Me" project on your local machine using Agile development practices. You can now start developing, testing, and contributing to the project. If you encounter any issues, refer to the project documentation or reach out to the development team for assistance. - -Happy coding! 🚀 - -## Team Members: -1. Imran Farid -2. Ramisa Zahara Matin +# Setup Guide for "Retrieve Me" Project + +Welcome to the setup guide for the "Retrieve Me" project, a Flutter and Firebase-based application developed using Agile methodologies. In this guide, we will walk you through the process of setting up the project on your local machine for development and testing purposes. + +## Prerequisites + +Before you begin, make sure you have the following prerequisites installed on your system: + +1. **Git**: Version control system for cloning the project repository. +2. **Flutter**: SDK for building native applications using the Dart programming language. +3. **Firebase Account**: Access to Firebase console for project configuration. +4. **Android Studio** or **VS Code**: Integrated development environment (IDE) for Flutter development. +5. **Android/iOS Emulator** or a physical device for testing. + +## Step-by-Step Setup Process + +Follow these steps to set up the "Retrieve Me" project on your local machine: + +### 1. Clone the Repository + +Open a terminal and execute the following command to clone the project repository: + +```bash +git clone https://github.com/Md-Kais/retrieve_me.git +``` + +### 2. Set Up Firebase + +1. User have to provide me his EMAIL to access the firebase database. + +### 3. Install Dependencies + +Navigate to the project directory and install the required dependencies using the following command: + +```bash +cd retrieve_me +flutter pub get +``` + +### 4. Run the Application + +Use your preferred IDE (Android Studio or VS Code) to open the project directory. + +#### Running on Android Emulator/Device + +1. Ensure your Android emulator or physical device is connected. +2. Run the app using the IDE's run button or execute the following command in the terminal: + +```bash +flutter run +``` + +#### Running on iOS Simulator/Device + +1. Ensure you have Xcode installed on macOS. +2. Open the `ios/Runner.xcworkspace` file in Xcode. +3. Select your desired simulator or device. +4. Click the run button or use the following command: + +```bash +flutter run +``` + +### 5. Testing + +You can now interact with the "Retrieve Me" app on the emulator or device. Explore its features and functionalities to ensure everything is working as expected. + +## Contributing and Agile Workflow + +If you're interested in contributing to the project, we follow an Agile development workflow using Git. Create a new branch for your feature or bug fix, make your changes, and submit a pull request to the `develop` branch. + +For Agile-related tasks, we use tools like Trello to manage user stories, tasks, and sprints. Feel free to join our Agile boards and participate in the development process. + +## Conclusion + +Congratulations! You've successfully set up the "Retrieve Me" project on your local machine using Agile development practices. You can now start developing, testing, and contributing to the project. If you encounter any issues, refer to the project documentation or reach out to the development team for assistance. + +Happy coding! 🚀 + +## Team Members: +1. Imran Farid +2. Ramisa Zahara Matin diff --git a/analysis_options.yaml b/analysis_options.yaml index 61b6c4d..a7acf24 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,29 +1,29 @@ -# 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 +# 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/android/.gitignore b/android/.gitignore index 6f56801..5d99765 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -1,13 +1,13 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties -**/*.keystore -**/*.jks +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/android/app/build.gradle b/android/app/build.gradle index 80d7e7a..1f4f37d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,77 +1,78 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -// START: FlutterFire Configuration -apply plugin: 'com.google.gms.google-services' -// END: FlutterFire Configuration -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - namespace "com.kais29.retrieve_me" - compileSdkVersion flutter.compileSdkVersion - ndkVersion flutter.ndkVersion - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.kais29.retrieve_me" - // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - multiDexEnabled true - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'com.android.support:multidex:1.0.3' -} +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +// START: FlutterFire Configuration +apply plugin: 'com.google.gms.google-services' +// END: FlutterFire Configuration +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + namespace "com.kais29.retrieve_me" + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.kais29.retrieve_me" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion 19 + // minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + multiDexEnabled true + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.android.support:multidex:1.0.3' +} diff --git a/android/app/google-services.json b/android/app/google-services.json index 0db0d80..7c9c1c0 100644 --- a/android/app/google-services.json +++ b/android/app/google-services.json @@ -29,6 +29,13 @@ { "client_id": "106875158936-97c5fo3suetjk4ogbpjpb0f9sd3gvsmv.apps.googleusercontent.com", "client_type": 3 + }, + { + "client_id": "106875158936-crekq3denfoplf602lg59j9fo17okm2r.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.kais29.retrieveMe" + } } ] } diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 399f698..8ffe024 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,7 +1,7 @@ - - - - + + + + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index f703a28..cbad2af 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,33 +1,33 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/kais29/retrieve_me/MainActivity.kt b/android/app/src/main/kotlin/com/kais29/retrieve_me/MainActivity.kt index 228c444..0f364d5 100644 --- a/android/app/src/main/kotlin/com/kais29/retrieve_me/MainActivity.kt +++ b/android/app/src/main/kotlin/com/kais29/retrieve_me/MainActivity.kt @@ -1,6 +1,6 @@ -package com.kais29.retrieve_me - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} +package com.kais29.retrieve_me + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml index f74085f..1cb7aa2 100644 --- a/android/app/src/main/res/drawable-v21/launch_background.xml +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -1,12 +1,12 @@ - - - - - - - - + + + + + + + + diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml index 304732f..8403758 100644 --- a/android/app/src/main/res/drawable/launch_background.xml +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -1,12 +1,12 @@ - - - - - - - - + + + + + + + + diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml index 06952be..360a160 100644 --- a/android/app/src/main/res/values-night/styles.xml +++ b/android/app/src/main/res/values-night/styles.xml @@ -1,18 +1,18 @@ - - - - - - - + + + + + + + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index cb1ef88..5fac679 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -1,18 +1,18 @@ - - - - - - - + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml index 399f698..8ffe024 100644 --- a/android/app/src/profile/AndroidManifest.xml +++ b/android/app/src/profile/AndroidManifest.xml @@ -1,7 +1,7 @@ - - - - + + + + diff --git a/android/build.gradle b/android/build.gradle index 4da596e..ceedffd 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,34 +1,34 @@ -buildscript { - ext.kotlin_version = '1.7.10' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' - // START: FlutterFire Configuration - classpath 'com.google.gms:google-services:4.3.14' - // END: FlutterFire Configuration - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} +buildscript { + ext.kotlin_version = '1.7.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.3.0' + // START: FlutterFire Configuration + classpath 'com.google.gms:google-services:4.3.14' + // END: FlutterFire Configuration + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/android/gradle.properties b/android/gradle.properties index 94adc3a..46c1f16 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 3ecad22..7af8143 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,10 +1,10 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https://services.gradle.org/distributions/gradle-7.5-all.zip - - -# distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip - - +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https://services.gradle.org/distributions/gradle-7.5-all.zip + + +# distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip + + diff --git a/android/settings.gradle b/android/settings.gradle index 44e62bc..33f0745 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,11 +1,11 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/ios/.gitignore b/ios/.gitignore index 7a7f987..ad322bc 100644 --- a/ios/.gitignore +++ b/ios/.gitignore @@ -1,34 +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 +**/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/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9625e10..0d9747f 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -1,26 +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 - 11.0 - - + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee..0b2d479 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1 @@ -#include "Generated.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee..0b2d479 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1 @@ -#include "Generated.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index d1cf13d..fcca5de 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -1,613 +1,613 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; -/* 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 */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 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; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 331C8082294A63A400263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 331C8082294A63A400263BE5 /* RunnerTests */, - ); - 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 = ( - 331C807D294A63A400263BE5 /* Sources */, - 331C807E294A63A400263BE5 /* Frameworks */, - 331C807F294A63A400263BE5 /* Resources */, - ); - 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 = ( - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1300; - 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"; - }; -/* 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; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe; - 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 = AE0B7B92F70575B8D7E0D07E /* 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.kais29.retrieveMe.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 = 89B67EB44CE7B6631473024E /* 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.kais29.retrieveMe.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 = 640959BDD8F10B91D80A66BE /* 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.kais29.retrieveMe.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; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.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)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe; - 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 */; -} +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; +/* 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 */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 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; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + 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 = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807E294A63A400263BE5 /* Frameworks */, + 331C807F294A63A400263BE5 /* Resources */, + ); + 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 = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + 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"; + }; +/* 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; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe; + 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 = AE0B7B92F70575B8D7E0D07E /* 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.kais29.retrieveMe.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 = 89B67EB44CE7B6631473024E /* 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.kais29.retrieveMe.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 = 640959BDD8F10B91D80A66BE /* 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.kais29.retrieveMe.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; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.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)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe; + 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/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 919434a..c4b79bd 100644 --- a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -1,7 +1,7 @@ - - - - - + + + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist index 18d9810..fc6bf80 100644 --- a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -1,8 +1,8 @@ - - - - - IDEDidComputeMac32BitWarning - - - + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings index f9b0d7c..af0309c 100644 --- a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -1,8 +1,8 @@ - - - - - PreviewsEnabled - - - + + + + + PreviewsEnabled + + + diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index e42adcb..c77b648 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,98 +1,98 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..59c6d39 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -1,7 +1,7 @@ - - - - - + + + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist index 18d9810..fc6bf80 100644 --- a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -1,8 +1,8 @@ - - - - - IDEDidComputeMac32BitWarning - - - + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings index f9b0d7c..af0309c 100644 --- a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -1,8 +1,8 @@ - - - - - PreviewsEnabled - - - + + + + + PreviewsEnabled + + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 70693e4..3763683 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,13 +1,13 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d36b1fa..1950fd8 100644 --- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,122 +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" - } -} +{ + "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/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json index 0bedcf2..d08a4de 100644 --- a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -1,23 +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" - } -} +{ + "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/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md index 89c2725..65a94b5 100644 --- a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -1,5 +1,5 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - +# 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/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard index f2e259c..497371e 100644 --- a/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard index f3c2851..bbb83ca 100644 --- a/ios/Runner/Base.lproj/Main.storyboard +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist index 27cd182..8445fec 100644 --- a/ios/Runner/GoogleService-Info.plist +++ b/ios/Runner/GoogleService-Info.plist @@ -1,34 +1,34 @@ - - - - - CLIENT_ID - 106875158936-crekq3denfoplf602lg59j9fo17okm2r.apps.googleusercontent.com - REVERSED_CLIENT_ID - com.googleusercontent.apps.106875158936-crekq3denfoplf602lg59j9fo17okm2r - API_KEY - AIzaSyCRvgqsJSXUdsuy3cTApKiNmZiKyoZI7_g - GCM_SENDER_ID - 106875158936 - PLIST_VERSION - 1 - BUNDLE_ID - com.kais29.retrieveMe - PROJECT_ID - retrieve-me - STORAGE_BUCKET - retrieve-me.appspot.com - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 1:106875158936:ios:4a0909e3bfce3955b62bed - + + + + + CLIENT_ID + 106875158936-crekq3denfoplf602lg59j9fo17okm2r.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.106875158936-crekq3denfoplf602lg59j9fo17okm2r + API_KEY + AIzaSyCRvgqsJSXUdsuy3cTApKiNmZiKyoZI7_g + GCM_SENDER_ID + 106875158936 + PLIST_VERSION + 1 + BUNDLE_ID + com.kais29.retrieveMe + PROJECT_ID + retrieve-me + STORAGE_BUCKET + retrieve-me.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:106875158936:ios:4a0909e3bfce3955b62bed + \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 4ddd1f8..9fe37df 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -1,51 +1,51 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Retrieve Me - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - retrieve_me - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - - + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Retrieve Me + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + retrieve_me + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h index 308a2a5..fae207f 100644 --- a/ios/Runner/Runner-Bridging-Header.h +++ b/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" +#import "GeneratedPluginRegistrant.h" diff --git a/ios/RunnerTests/RunnerTests.swift b/ios/RunnerTests/RunnerTests.swift index 86a7c3b..4d206de 100644 --- a/ios/RunnerTests/RunnerTests.swift +++ b/ios/RunnerTests/RunnerTests.swift @@ -1,12 +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. - } - -} +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/lib/Components/drawer_item.dart b/lib/Components/drawer_item.dart new file mode 100644 index 0000000..c791e76 --- /dev/null +++ b/lib/Components/drawer_item.dart @@ -0,0 +1,9 @@ +//import material ui +import 'package:flutter/material.dart'; + +class DrawerItem { + final String title; + final IconData icon; + + const DrawerItem({required this.title, required this.icon}); +} diff --git a/lib/Components/drawer_items.dart b/lib/Components/drawer_items.dart new file mode 100644 index 0000000..62cbf3e --- /dev/null +++ b/lib/Components/drawer_items.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; +import 'drawer_item.dart'; + +final itemsFirst = [ + const DrawerItem(title: 'Post Lost Item', icon: Icons.phone_android_outlined), + const DrawerItem(title: 'Post Found Item', icon: Icons.people), + const DrawerItem(title: 'Item Case History', icon: Icons.history) +]; + +final itemsSecond = [ + const DrawerItem(title: 'Chat', icon: Icons.chat), + const DrawerItem(title: 'Settings', icon: Icons.settings), +]; + +final itemsThird = [ + const DrawerItem(title: 'Logout', icon: Icons.logout), +]; diff --git a/lib/Components/my_button.dart b/lib/Components/my_button.dart index 0a55334..aa46672 100644 --- a/lib/Components/my_button.dart +++ b/lib/Components/my_button.dart @@ -1,32 +1,32 @@ -import 'package:flutter/material.dart'; - -class MyButton extends StatelessWidget { - final Function()? onTap; - - const MyButton({super.key, required this.onTap}); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onTap, - child: Container( - padding: const EdgeInsets.all(25), - margin: const EdgeInsets.symmetric(horizontal: 25), - decoration: BoxDecoration( - color: Colors.blueAccent, - borderRadius: BorderRadius.circular(8), - ), - child: const Center( - child: Text( - "Sign In", - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - ), - ); - } -} +import 'package:flutter/material.dart'; + +class MyButton extends StatelessWidget { + final Function()? onTap; + + const MyButton({super.key, required this.onTap}); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: Container( + padding: const EdgeInsets.all(25), + margin: const EdgeInsets.symmetric(horizontal: 25), + decoration: BoxDecoration( + color: Colors.blueAccent, + borderRadius: BorderRadius.circular(8), + ), + child: const Center( + child: Text( + "Sign In", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + ), + ); + } +} diff --git a/lib/Components/my_textfield.dart b/lib/Components/my_textfield.dart index e076b88..55e330c 100644 --- a/lib/Components/my_textfield.dart +++ b/lib/Components/my_textfield.dart @@ -1,53 +1,53 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - -class MyTextField extends StatelessWidget { - final TextEditingController controller; - final String hintText; - final bool obscureText; - final IconData prefixIcon; - final String labelText; - final List? inputFormatters; // Added inputFormatters - final TextInputType? keyboardType; // Made keyboardType optional - - const MyTextField({ - required this.controller, - required this.hintText, - required this.obscureText, - required this.prefixIcon, - required this.labelText, - this.inputFormatters, // Pass inputFormatters as an optional parameter - this.keyboardType, // Pass keyboardType as an optional parameter - }); - - @override - Widget build(BuildContext context) { - return Container( - width: MediaQuery.of(context).size.width * 0.75, - child: TextFormField( - controller: controller, - obscureText: obscureText, - keyboardType: keyboardType, // Use keyboardType here (can be null) - inputFormatters: - inputFormatters, // Use inputFormatters here (can be null) - style: TextStyle(color: Color.fromRGBO(150, 255, 210, 75)), - decoration: InputDecoration( - labelText: labelText, - labelStyle: TextStyle(color: Color.fromARGB(255, 223, 206, 206)), - prefixIcon: Icon(prefixIcon), - prefixIconColor: Color.fromRGBO(255, 255, 255, 100), - border: OutlineInputBorder( - borderSide: BorderSide( - color: Color.fromARGB(255, 156, 178, 197), // Border color - ), - borderRadius: BorderRadius.all( - Radius.circular(15.0), // Border radius - ), - ), - hintText: hintText, - hintStyle: TextStyle(color: Color.fromRGBO(200, 130, 50, 50)), - ), - ), - ); - } -} +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class MyTextField extends StatelessWidget { + final TextEditingController controller; + final String hintText; + final bool obscureText; + final IconData prefixIcon; + final String labelText; + final List? inputFormatters; // Added inputFormatters + final TextInputType? keyboardType; // Made keyboardType optional + + const MyTextField({super.key, + required this.controller, + required this.hintText, + required this.obscureText, + required this.prefixIcon, + required this.labelText, + this.inputFormatters, // Pass inputFormatters as an optional parameter + this.keyboardType, // Pass keyboardType as an optional parameter + }); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + child: TextFormField( + controller: controller, + obscureText: obscureText, + keyboardType: keyboardType, // Use keyboardType here (can be null) + inputFormatters: + inputFormatters, // Use inputFormatters here (can be null) + style: const TextStyle(color: Color.fromRGBO(150, 255, 210, 75)), + decoration: InputDecoration( + labelText: labelText, + labelStyle: const TextStyle(color: Color.fromARGB(255, 223, 206, 206)), + prefixIcon: Icon(prefixIcon), + prefixIconColor: const Color.fromRGBO(255, 255, 255, 100), + border: const OutlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB(255, 156, 178, 197), // Border color + ), + borderRadius: BorderRadius.all( + Radius.circular(15.0), // Border radius + ), + ), + hintText: hintText, + hintStyle: const TextStyle(color: Color.fromRGBO(200, 130, 50, 50)), + ), + ), + ); + } +} diff --git a/lib/Components/navigation_drawer_widget.dart b/lib/Components/navigation_drawer_widget.dart new file mode 100644 index 0000000..6bd93a6 --- /dev/null +++ b/lib/Components/navigation_drawer_widget.dart @@ -0,0 +1,196 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:provider/provider.dart'; +import 'package:retrieve_me/Components/drawer_item.dart'; +import 'package:retrieve_me/Components/drawer_items.dart'; +import 'package:retrieve_me/pages/postFoundItem.dart'; +import 'package:retrieve_me/pages/postLostItem.dart'; + +import '../pages/login.dart'; +import '../provider/navigation_provider.dart'; + +class NavigationDrawerWidget extends StatelessWidget { + final padding = const EdgeInsets.symmetric(horizontal: 20); + + const NavigationDrawerWidget({super.key}); + + @override + Widget build(BuildContext context) { + final provider = Provider.of(context); + const safeArea = EdgeInsets.symmetric(horizontal: 15, vertical: 20); + final isCollapsed = provider.isCollapsed; + + return SizedBox( + width: isCollapsed ? MediaQuery.of(context).size.width * 0.15 : null, + child: Drawer( + child: Container( + color: const Color(0xFF1a2f45), + child: Column( + children: [ + Container( + padding: + const EdgeInsets.symmetric(vertical: 15).add(safeArea), + width: double.infinity, + color: const Color.fromARGB(255, 9, 0, 56), + child: buildHeader(isCollapsed), + ), + const SizedBox(height: 24), + Container( + // padding: padding, + child: buildListItems( + items: itemsFirst, isCollapsed: isCollapsed), + ), + const SizedBox(height: 12), + const Divider(color: Colors.white70), + const SizedBox(height: 12), + Container( + // padding: padding, + child: buildListItems( + items: itemsSecond, isCollapsed: isCollapsed), + ), + const SizedBox(height: 12), + const Divider(color: Colors.white70), + const SizedBox(height: 12), + Container( + // padding: padding, + child: buildListItems( + items: itemsThird, isCollapsed: isCollapsed), + ), + const Spacer(), + buildCollapseIcon(context, isCollapsed), + const SizedBox(height: 16), + ], + )), + ), + ); + } + + Widget buildHeader(bool isCollapsed) => isCollapsed + ? const FlutterLogo(size: 48) + : Row( + children: [ + const SizedBox(width: 24), + const FlutterLogo(size: 48), + const SizedBox(width: 20), + Text('Retrieve-Me', + style: GoogleFonts.lato( + textStyle: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24, + color: Color.fromARGB(255, 5, 121, 179), + ), + )), + ], + ); + + Widget buildCollapseIcon(BuildContext context, bool isCollapsed) { + const double size = 52; + final icon = isCollapsed ? Icons.arrow_forward_ios : Icons.arrow_back_ios; + final alignment = isCollapsed ? Alignment.center : Alignment.centerRight; + final margin = isCollapsed ? null : const EdgeInsets.only(right: 16); + final width = isCollapsed ? double.infinity : size; + return Container( + alignment: alignment, + margin: margin, + child: Material( + color: Colors.transparent, + child: InkWell( + child: SizedBox( + width: width, + height: size, + child: Icon(icon, color: Colors.white), + ), + onTap: () { + final provider = + Provider.of(context, listen: false); + provider.toggleCollapsed(); + }, + ))); + } + + buildListItems( + {required List items, required bool isCollapsed}) => + ListView.separated( + padding: isCollapsed ? EdgeInsets.zero : padding, + shrinkWrap: true, + primary: false, + itemCount: items.length, + separatorBuilder: (context, index) => const SizedBox(height: 16), + itemBuilder: (context, index) { + final item = items[index]; + + return buildMenuItem( + isCollapsed: isCollapsed, + text: item.title, + icon: item.icon, + onClicked: () => selectItem(context, index, item.title), + ); + }, + ); + + buildMenuItem( + {required bool isCollapsed, + required String text, + required IconData icon, + VoidCallback? onClicked}) { + const color = Colors.white; + final leading = Icon(icon, color: color); + + return Material( + color: Colors.transparent, + child: isCollapsed + ? ListTile( + leading: leading, + onTap: onClicked, + ) + : ListTile( + leading: leading, + title: Text(text, + style: const TextStyle(color: color, fontSize: 16)), + onTap: onClicked, + )); + } + + selectItem(BuildContext context, int index, String itemTitle) { + navigateTo(page) => Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (context) => page, + )); + switch (itemTitle) { + case 'Post Lost Item': + navigateTo(const PostLostItemPage()); + break; + case 'Post Found Item': + navigateTo(const PostFoundItemPage()); + break; + case 'Logout': + navigateTo(LoginPage()); + break; + } + // switch (index) { + // case 0: + // selectItem(BuildContext context, int index) { + // final navigateTo = + // (page) => Navigator.of(context).push(MaterialPageRoute( + // builder: (context) => page, + // )); + + // if (Navigator.of(context).canPop()) { + // Navigator.of(context).pop(); + // } + + // switch (index) { + // case 0: + // if (ModalRoute.of(context)?.settings.name != '/postLostItem') { + // navigateTo(PostLostItemPage()); + // } + // break; + // case 1: + // if (ModalRoute.of(context)?.settings.name != '/postFoundItem') { + // navigateTo(PostFoundItemPage()); + // } + // break; + // } + // } + // } + } +} diff --git a/lib/Components/square_tile.dart b/lib/Components/square_tile.dart index ae4f5a6..7534962 100644 --- a/lib/Components/square_tile.dart +++ b/lib/Components/square_tile.dart @@ -1,25 +1,25 @@ -import 'package:flutter/material.dart'; - -class SquareTile extends StatelessWidget { - final String imagePath; - const SquareTile({ - super.key, - required this.imagePath, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.all(20), - decoration: BoxDecoration( - border: Border.all(color: Colors.white), - borderRadius: BorderRadius.circular(16), - color: Colors.grey[200], - ), - child: Image.asset( - imagePath, - height: 40, - ), - ); - } -} +import 'package:flutter/material.dart'; + +class SquareTile extends StatelessWidget { + final String imagePath; + const SquareTile({ + super.key, + required this.imagePath, + }); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + border: Border.all(color: Colors.white), + borderRadius: BorderRadius.circular(16), + color: Colors.grey[200], + ), + child: Image.asset( + imagePath, + height: 40, + ), + ); + } +} diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart index 526890b..195c355 100644 --- a/lib/firebase_options.dart +++ b/lib/firebase_options.dart @@ -25,10 +25,7 @@ class DefaultFirebaseOptions { case TargetPlatform.iOS: return ios; case TargetPlatform.macOS: - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for macos - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); + return macos; case TargetPlatform.windows: throw UnsupportedError( 'DefaultFirebaseOptions have not been configured for windows - ' @@ -72,4 +69,14 @@ class DefaultFirebaseOptions { iosClientId: '106875158936-crekq3denfoplf602lg59j9fo17okm2r.apps.googleusercontent.com', iosBundleId: 'com.kais29.retrieveMe', ); + + static const FirebaseOptions macos = FirebaseOptions( + apiKey: 'AIzaSyCRvgqsJSXUdsuy3cTApKiNmZiKyoZI7_g', + appId: '1:106875158936:ios:dddb3b93084d9675b62bed', + messagingSenderId: '106875158936', + projectId: 'retrieve-me', + storageBucket: 'retrieve-me.appspot.com', + iosClientId: '106875158936-v949vjjbj2ef67l3lb0iq5d91j7f4usl.apps.googleusercontent.com', + iosBundleId: 'com.kais29.retrieveMe.RunnerTests', + ); } diff --git a/lib/main.dart b/lib/main.dart index ae84a3d..835f56d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,16 +1,15 @@ -import 'package:flutter/material.dart'; -import 'package:retrieve_me/pages/login.dart'; -import 'package:retrieve_me/pages/registration.dart'; - -void main() { - WidgetsFlutterBinding.ensureInitialized(); - runApp(MaterialApp( - title: 'Retrieve-Me', - theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo), - useMaterial3: true, - ), - // home: const RegistrationPage(), - home: LoginPage(), - )); -} +import 'package:flutter/material.dart'; +import 'package:retrieve_me/pages/login.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + runApp(MaterialApp( + title: 'Retrieve-Me', + theme: ThemeData( + colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo), + useMaterial3: true, + ), + // home: const RegistrationPage(), + home: LoginPage(), + )); +} diff --git a/lib/pages/login.dart b/lib/pages/login.dart index 6f9ae08..d09ffd8 100644 --- a/lib/pages/login.dart +++ b/lib/pages/login.dart @@ -1,217 +1,218 @@ -import 'dart:js'; - -import 'package:firebase_core/firebase_core.dart'; -import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:retrieve_me/Components/my_button.dart'; -import 'package:retrieve_me/Components/my_textfield.dart'; -import 'package:retrieve_me/Components/square_tile.dart'; -import 'package:retrieve_me/firebase_options.dart'; -import 'package:retrieve_me/pages/postLostItem.dart'; -import 'package:retrieve_me/pages/registration.dart'; - -class LoginPage extends StatelessWidget { - LoginPage({Key? key}); - - // text editing controllers - TextEditingController emailController = TextEditingController(); - TextEditingController passwordController = TextEditingController(); - // sign user in method - Future signUserIn(BuildContext context) async { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => PostLostItemPage(), - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: FutureBuilder( - future: Firebase.initializeApp( - options: DefaultFirebaseOptions.currentPlatform, - ), - builder: (context, snapshot) { - return Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color.fromARGB(255, 45, 44, 46), - Color.fromARGB(255, 5, 63, 111) - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: SingleChildScrollView( - child: Column( - children: [ - Container( - width: MediaQuery.of(context).size.width * 0.8, - child: DrawerHeader( - child: Align( - alignment: Alignment.centerLeft, - child: Text( - 'LOG IN', - style: GoogleFonts.oswald( - textStyle: TextStyle( - fontSize: 35, - color: Colors.white, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - ), - SizedBox(height: 50), // Removed 'const' - - // welcome back, you've been missed! - Text( - 'Welcome back you\'ve been missed!', - style: TextStyle( - color: Colors.grey[700], - fontSize: 16, - ), - ), - - SizedBox(height: 25), // Removed 'const' - - // username textfield - - SizedBox(height: 16), - MyTextField( - controller: emailController, - hintText: 'johnKais@email.com', - obscureText: false, - prefixIcon: Icons.email, - labelText: 'Email', - keyboardType: TextInputType.emailAddress, - ), - SizedBox(height: 16), - MyTextField( - controller: passwordController, - hintText: '', - obscureText: true, - prefixIcon: Icons.lock, - labelText: 'Password', - keyboardType: TextInputType.text, - ), - - SizedBox(height: 10), // Removed 'const' - - // forgot password? - Padding( - padding: const EdgeInsets.symmetric(horizontal: 25.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - 'Forgot Password?', - style: TextStyle(color: Colors.grey[600]), - ), - ], - ), - ), - - SizedBox(height: 25), - - // sign in button - MyButton( - onTap: (){ - signUserIn(context); - } - ), - - SizedBox(height: 50), // Removed 'const' - - // or continue with - Padding( - padding: const EdgeInsets.symmetric(horizontal: 25.0), - child: Row( - children: [ - Expanded( - child: Divider( - thickness: 0.5, - color: Colors.grey[400], - ), - ), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 10.0), - child: Text( - 'Or continue with', - style: TextStyle(color: Colors.grey[700]), - ), - ), - Expanded( - child: Divider - ( - thickness: 0.5, - color: Colors.grey[400], - ), - ), - ], - ), - ), - - SizedBox(height: 50), // Removed 'const' - - // google + apple sign in buttons - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - // google button - SquareTile(imagePath: 'lib/images/google.png'), - - SizedBox(width: 25), - - // apple button - SquareTile(imagePath: 'lib/images/github.png') - ], - ), - - SizedBox(height: 50), // Removed 'const' - - // not a member? register now - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Not a member?', - style: TextStyle(color: Colors.grey[700]), - ), - SizedBox(width: 4), - GestureDetector( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => RegistrationPage(), - ), - ); - }, - child: Text( - 'Register now', - style: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ) - ], - ), - ), - ), - ), - ); - }, - ), - ); - } -} +// import 'dart:js'; + +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:provider/provider.dart'; +import 'package:retrieve_me/Components/my_button.dart'; +import 'package:retrieve_me/Components/my_textfield.dart'; +import 'package:retrieve_me/Components/square_tile.dart'; +import 'package:retrieve_me/firebase_options.dart'; +import 'package:retrieve_me/pages/postLostItem.dart'; +import 'package:retrieve_me/pages/registration.dart'; +import 'package:retrieve_me/provider/navigation_provider.dart'; + +class LoginPage extends StatelessWidget { + // text editing controllers + TextEditingController emailController = TextEditingController(); + TextEditingController passwordController = TextEditingController(); + // sign user in method + Future signUserIn(BuildContext context) async { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const PostLostItemPage(), + ), + ); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (context) => NavigationProvider(), + child: Scaffold( + body: FutureBuilder( + future: Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ), + builder: (context, snapshot) { + return Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111) + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: SingleChildScrollView( + child: Column( + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + child: DrawerHeader( + child: Align( + alignment: Alignment.centerLeft, + child: Text( + 'LOG IN', + style: GoogleFonts.oswald( + textStyle: const TextStyle( + fontSize: 35, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ), + ), + const SizedBox(height: 50), // Removed 'const' + + // welcome back, you've been missed! + Text( + 'Welcome back you\'ve been missed!', + style: TextStyle( + color: Colors.grey[700], + fontSize: 16, + ), + ), + + const SizedBox(height: 25), // Removed 'const' + + // username textfield + + const SizedBox(height: 16), + MyTextField( + controller: emailController, + hintText: 'johnKais@email.com', + obscureText: false, + prefixIcon: Icons.email, + labelText: 'Email', + keyboardType: TextInputType.emailAddress, + ), + const SizedBox(height: 16), + MyTextField( + controller: passwordController, + hintText: '', + obscureText: true, + prefixIcon: Icons.lock, + labelText: 'Password', + keyboardType: TextInputType.text, + ), + + const SizedBox(height: 10), // Removed 'const' + + // forgot password? + Padding( + padding: const EdgeInsets.symmetric(horizontal: 25.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + 'Forgot Password?', + style: TextStyle(color: Colors.grey[600]), + ), + ], + ), + ), + + const SizedBox(height: 25), + + // sign in button + MyButton(onTap: () { + signUserIn(context); + }), + + const SizedBox(height: 50), // Removed 'const' + + // or continue with + Padding( + padding: const EdgeInsets.symmetric(horizontal: 25.0), + child: Row( + children: [ + Expanded( + child: Divider( + thickness: 0.5, + color: Colors.grey[400], + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10.0), + child: Text( + 'Or continue with', + style: TextStyle(color: Colors.grey[700]), + ), + ), + Expanded( + child: Divider( + thickness: 0.5, + color: Colors.grey[400], + ), + ), + ], + ), + ), + + const SizedBox(height: 50), // Removed 'const' + + // google + apple sign in buttons + const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // google button + SquareTile(imagePath: 'lib/images/google.png'), + + SizedBox(width: 25), + + // apple button + SquareTile(imagePath: 'lib/images/github.png') + ], + ), + + const SizedBox(height: 50), // Removed 'const' + + // not a member? register now + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Not a member?', + style: TextStyle(color: Colors.grey[700]), + ), + const SizedBox(width: 4), + GestureDetector( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => + const RegistrationPage(), + ), + ); + }, + child: const Text( + 'Register now', + style: TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ) + ], + ), + ), + ), + ), + ); + }, + ), + ), + ); + } +} diff --git a/lib/pages/postFoundItem.dart b/lib/pages/postFoundItem.dart index 15f68e9..52c40cc 100644 --- a/lib/pages/postFoundItem.dart +++ b/lib/pages/postFoundItem.dart @@ -1,381 +1,400 @@ -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:flutter/material.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:flutter/services.dart'; -import 'package:retrieve_me/pages/login.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:date_time_picker/date_time_picker.dart'; -import 'package:retrieve_me/pages/postLostItem.dart'; -import '../Components/my_textfield.dart'; -import '../firebase_options.dart'; - -class PostFoundItemPage extends StatefulWidget { - @override - State createState() => - _PostFoundItemPageState(); -} - -class _PostFoundItemPageState extends State { - XFile? selectedImage; - TextEditingController whatWasFound = TextEditingController(); - TextEditingController itemCategory = TextEditingController(); - TextEditingController additionalInfo = TextEditingController(); - TextEditingController cityController = TextEditingController(); - TextEditingController divisionController = TextEditingController(); - TextEditingController unionVillageController = TextEditingController(); - TextEditingController streetHouseController = TextEditingController(); - DateTime? dateTimeController = DateTime.now(); - - void _insertImage() async { - final selector = ImagePicker(); - final selectedFile = await selector.pickImage(source: ImageSource.gallery); - - if (selectedFile != null) { - setState(() { - selectedImage = selectedFile; - }); - } - } - - bool areAllFieldsFilled() { - return whatWasFound.text.isNotEmpty && - itemCategory.text.isNotEmpty && - additionalInfo.text.isNotEmpty && - cityController.text.isNotEmpty && - divisionController.text.isNotEmpty && - unionVillageController.text.isNotEmpty && - streetHouseController.text.isNotEmpty && - selectedImage != null && - dateTimeController != null; - } - - Future submitFoundItem() async { - if(areAllFieldsFilled()) { - try { - // Create a Firestore instance - FirebaseFirestore firestore = FirebaseFirestore.instance; - CollectionReference collectionReference = firestore.collection( - 'FoundProduct'); - - Timestamp dateTimeTimestamp = Timestamp.fromDate(dateTimeController!); - - // Define a map with the data to be saved - Map foundItemData = { - 'FoundItem': whatWasFound.text, - 'Category': itemCategory.text, - 'DateTime': dateTimeTimestamp, - 'Description': additionalInfo.text, - 'CityLocation': cityController.text, - 'DivisionLocation': divisionController.text, - 'UnionVillageLocation': unionVillageController.text, - 'StreetHouseLocation': streetHouseController.text, - }; - await collectionReference.add(foundItemData); - - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Found Item Posted!', textAlign: TextAlign.center), - content: - Text('You have successfully created your Found Item post!'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text('Okay'), - ), - ], - ), - ); - - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: (context) => LoginPage(), - // ), - // ); - } catch (e) { - showDialog( - context: context, - builder: (context) => - AlertDialog( - content: - Text('Error submitting lost item info'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text('Okay'), - ), - ], - ), - ); - } - } - else{ - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Error'), - content: - Text('Please fill all the required fields before submitting!'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text('Okay'), - ), - ], - ), - ); - } - } - - - @override - Widget build(BuildContext context) { - return Scaffold( - body: FutureBuilder( - future: Firebase.initializeApp( - options: DefaultFirebaseOptions.currentPlatform, - ), - builder: (context, snapshot){ - return Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color.fromARGB(255, 45, 44, 46), - Color.fromARGB(255, 5, 63, 111) - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: Center( - child: Padding(padding: const EdgeInsets.all(15.0), - child: SingleChildScrollView( - child: Column( - children: [ - // Lost/Found radio button group - Container( - width: MediaQuery.of(context).size.width * 0.8, - child: DrawerHeader( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => PostLostItemPage(), - ), - ); - }, - child: Text( - ' Lost ', - style: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 1.2, - ), - ), - ), - GestureDetector( - child: Text( - ' Found ', - style: TextStyle( - color: Colors.grey, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 2, - ), - ), - ) - ], - ), - ), - ), - const SizedBox(height: 16), - Container( - width: MediaQuery.of(context).size.width * 0.75, - height: MediaQuery.of(context).size.height * 0.075, - child: TextButton( - onPressed: _insertImage, - style: TextButton.styleFrom( - backgroundColor: Colors.cyan, - shadowColor: Colors.green, - ), - child: const Text('Insert Found Product Image', style: TextStyle( - color: Colors.brown, - fontWeight: FontWeight.bold, - ) - ), - ), - ), - const SizedBox(height: 16), - Container( - width: MediaQuery.of(context).size.width * 0.75, - child: Align( - alignment: Alignment.center, - child: DateTimePicker( - // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, - type: DateTimePickerType.dateTimeSeparate, - dateMask: 'd MMM, yyyy', - initialValue: DateTime.now().toString(), - firstDate: DateTime(2000), - lastDate: DateTime(2099), - icon: Icon(Icons.date_range_sharp), - dateLabelText: 'Date', - style: TextStyle(color: Colors.deepOrangeAccent, - fontWeight: FontWeight.bold,), - timeLabelText: "Hour", - selectableDayPredicate: (date){ - return true; - }, - onChanged: (value) => { - dateTimeController = DateTime.parse(value), - // dateTimeController = value as DateTimePicker, - }, - decoration: InputDecoration( - border: OutlineInputBorder( - borderSide: BorderSide( - color: Color.fromARGB(255, 156, 178, 197), // Border color - ), - borderRadius: BorderRadius.all( - Radius.circular(15.0), // Border radius - ), - ), - ) - , - ), - ) - ), - - const SizedBox(height: 16), - MyTextField( - controller: whatWasFound, - hintText: '', - obscureText: false, - prefixIcon: Icons.cases, - labelText: 'What was Found', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - MyTextField( - controller: itemCategory, - hintText: 'Mobile', - obscureText: false, - prefixIcon: Icons.miscellaneous_services, - labelText: 'Item Category', - keyboardType: TextInputType.emailAddress, - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - Container( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: divisionController, - hintText: 'Chittagong', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Division', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z. ]')) - ], - ), - ), - Container( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: cityController, - hintText: 'Hathazari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'City', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z. ]')) - ], - ), - ) - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - Container( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: streetHouseController, - hintText: 'Road no: 3, House no: 7', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Street/House No.', - keyboardType: TextInputType.streetAddress, - ), - ), - Container( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: unionVillageController, - hintText: 'Fatikchhari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Union/Village', - keyboardType: TextInputType.streetAddress, - ), - ) - ], - ), - const SizedBox(height: 16), - MyTextField( - controller: additionalInfo, - hintText: 'Context and description of item', - obscureText: false, - prefixIcon: Icons.info_outlined, - labelText: 'Additional Info', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - BackButton(style: ElevatedButton.styleFrom( - backgroundColor: Colors.greenAccent, - )), - const SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(width: 16), - SizedBox( - height: MediaQuery.of(context).size.height * 0.05, - width: MediaQuery.of(context).size.width * 0.250, - child: ElevatedButton( - onPressed: submitFoundItem, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - // splashFactory: InkRipple.splashFactory, - ), - child: const Text('Submit', style: TextStyle( - color: Colors.deepPurple, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 0.90, - ), - ), - ), - ), - ], - ), - ] - ), - ), - ), - ), - // }, - ); - } - ), - ); - } -} \ No newline at end of file +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/material.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:date_time_picker/date_time_picker.dart'; +import '../Components/my_textfield.dart'; +import '../Components/navigation_drawer_widget.dart'; +import '../firebase_options.dart'; +import '../provider/navigation_provider.dart'; + +GlobalKey _sKey = GlobalKey(); + +class PostFoundItemPage extends StatefulWidget { + const PostFoundItemPage({super.key}); + + @override + State createState() => _PostFoundItemPageState(); +} + +class _PostFoundItemPageState extends State { + XFile? selectedImage; + TextEditingController whatWasFound = TextEditingController(); + TextEditingController itemCategory = TextEditingController(); + TextEditingController additionalInfo = TextEditingController(); + TextEditingController cityController = TextEditingController(); + TextEditingController divisionController = TextEditingController(); + TextEditingController unionVillageController = TextEditingController(); + TextEditingController streetHouseController = TextEditingController(); + DateTime? dateTimeController = DateTime.now(); + + void _insertImage() async { + final selector = ImagePicker(); + final selectedFile = await selector.pickImage(source: ImageSource.gallery); + + if (selectedFile != null) { + setState(() { + selectedImage = selectedFile; + }); + } + } + + bool areAllFieldsFilled() { + return whatWasFound.text.isNotEmpty && + itemCategory.text.isNotEmpty && + additionalInfo.text.isNotEmpty && + cityController.text.isNotEmpty && + divisionController.text.isNotEmpty && + unionVillageController.text.isNotEmpty && + streetHouseController.text.isNotEmpty && + selectedImage != null && + dateTimeController != null; + } + + Future submitFoundItem() async { + if (areAllFieldsFilled()) { + try { + // Create a Firestore instance + FirebaseFirestore firestore = FirebaseFirestore.instance; + CollectionReference collectionReference = + firestore.collection('FoundProduct'); + + Timestamp dateTimeTimestamp = Timestamp.fromDate(dateTimeController!); + + // Define a map with the data to be saved + Map foundItemData = { + 'FoundItem': whatWasFound.text, + 'Category': itemCategory.text, + 'DateTime': dateTimeTimestamp, + 'Description': additionalInfo.text, + 'CityLocation': cityController.text, + 'DivisionLocation': divisionController.text, + 'UnionVillageLocation': unionVillageController.text, + 'StreetHouseLocation': streetHouseController.text, + }; + await collectionReference.add(foundItemData); + + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Found Item Posted!', textAlign: TextAlign.center), + content: + const Text('You have successfully created your Found Item post!'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Okay'), + ), + ], + ), + ); + + // Navigator.of(context).push( + // MaterialPageRoute( + // builder: (context) => LoginPage(), + // ), + // ); + } catch (e) { + showDialog( + context: context, + builder: (context) => AlertDialog( + content: const Text('Error submitting lost item info'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Okay'), + ), + ], + ), + ); + } + } else { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Error'), + content: + const Text('Please fill all the required fields before submitting!'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Okay'), + ), + ], + ), + ); + } + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (context) => NavigationProvider(), + child: Scaffold( + drawer: const NavigationDrawerWidget(), + key: _sKey, + body: FutureBuilder( + future: Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ), + builder: (context, snapshot) { + return Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111) + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: Center( + child: Padding( + padding: const EdgeInsets.all(15.0), + child: SingleChildScrollView( + child: Column(children: [ + // Lost/Found radio button group + Container( + child: IconButton( + onPressed: () { + _sKey.currentState!.openDrawer(); + }, + icon: const Icon( + Icons.menu, + color: Colors.white, + size: 30, + )), + ), + SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + child: DrawerHeader( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + GestureDetector( + onTap: () { + // Navigator.pop(context); + // Navigator.of(context).push( + // MaterialPageRoute( + // builder: (context) => PostLostItemPage(), + // ), + // ); + }, + child: const Text( + ' Lost ', + style: TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 1.2, + ), + ), + ), + GestureDetector( + child: const Text( + ' Found ', + style: TextStyle( + color: Colors.grey, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 2, + ), + ), + ) + ], + ), + ), + ), + const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + height: MediaQuery.of(context).size.height * 0.075, + child: TextButton( + onPressed: _insertImage, + style: TextButton.styleFrom( + backgroundColor: Colors.cyan, + shadowColor: Colors.green, + ), + child: const Text('Insert Found Product Image', + style: TextStyle( + color: Colors.brown, + fontWeight: FontWeight.bold, + )), + ), + ), + const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + child: Align( + alignment: Alignment.center, + child: DateTimePicker( + // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, + type: DateTimePickerType.dateTimeSeparate, + dateMask: 'd MMM, yyyy', + initialValue: DateTime.now().toString(), + firstDate: DateTime(2000), + lastDate: DateTime(2099), + icon: const Icon(Icons.date_range_sharp), + dateLabelText: 'Date', + style: const TextStyle( + color: Colors.deepOrangeAccent, + fontWeight: FontWeight.bold, + ), + timeLabelText: "Hour", + selectableDayPredicate: (date) { + return true; + }, + onChanged: (value) => { + dateTimeController = DateTime.parse(value), + // dateTimeController = value as DateTimePicker, + }, + decoration: const InputDecoration( + border: OutlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB( + 255, 156, 178, 197), // Border color + ), + borderRadius: BorderRadius.all( + Radius.circular(15.0), // Border radius + ), + ), + ), + ), + )), + + const SizedBox(height: 16), + MyTextField( + controller: whatWasFound, + hintText: '', + obscureText: false, + prefixIcon: Icons.cases, + labelText: 'What was Found', + keyboardType: TextInputType.text, + ), + const SizedBox(height: 16), + MyTextField( + controller: itemCategory, + hintText: 'Mobile', + obscureText: false, + prefixIcon: Icons.miscellaneous_services, + labelText: 'Item Category', + keyboardType: TextInputType.emailAddress, + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + // City + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: divisionController, + hintText: 'Chittagong', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Division', + keyboardType: TextInputType.streetAddress, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[a-zA-Z. ]')) + ], + ), + ), + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: cityController, + hintText: 'Hathazari', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'City', + keyboardType: TextInputType.streetAddress, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[a-zA-Z. ]')) + ], + ), + ) + ], + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + // City + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: streetHouseController, + hintText: 'Road no: 3, House no: 7', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Street/House No.', + keyboardType: TextInputType.streetAddress, + ), + ), + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: unionVillageController, + hintText: 'Fatikchhari', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Union/Village', + keyboardType: TextInputType.streetAddress, + ), + ) + ], + ), + const SizedBox(height: 16), + MyTextField( + controller: additionalInfo, + hintText: 'Context and description of item', + obscureText: false, + prefixIcon: Icons.info_outlined, + labelText: 'Additional Info', + keyboardType: TextInputType.text, + ), + const SizedBox(height: 16), + BackButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.greenAccent, + )), + const SizedBox(height: 32), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(width: 16), + SizedBox( + height: MediaQuery.of(context).size.height * 0.05, + width: MediaQuery.of(context).size.width * 0.250, + child: ElevatedButton( + onPressed: submitFoundItem, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Submit', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.90, + ), + ), + ), + ), + ], + ), + ]), + ), + ), + ), + // }, + ); + }), + ), + ); + } +} diff --git a/lib/pages/postLostItem.dart b/lib/pages/postLostItem.dart index fd17ab5..e9dd26c 100644 --- a/lib/pages/postLostItem.dart +++ b/lib/pages/postLostItem.dart @@ -1,402 +1,435 @@ -import 'dart:math'; - -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:flutter/material.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:flutter/services.dart'; -import 'package:retrieve_me/pages/login.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:date_time_picker/date_time_picker.dart'; -import 'package:retrieve_me/pages/postFoundItem.dart'; -import '../Components/my_textfield.dart'; -import '../firebase_options.dart'; - -class ScaleSize { - static double textScaleFactor(BuildContext context, {double maxTextScaleFactor = 2}) { - final width = MediaQuery.of(context).size.width; - double val = (width / 1400) * maxTextScaleFactor; - return max(1, min(val, maxTextScaleFactor)); - } -} - -class PostLostItemPage extends StatefulWidget { - @override - State createState() => - _PostLostItemPageState(); -} - -class _PostLostItemPageState extends State { - XFile? selectedImage; - TextEditingController whatWasLost = TextEditingController(); - TextEditingController itemCategory = TextEditingController(); - TextEditingController additionalInfo = TextEditingController(); - TextEditingController cityController = TextEditingController(); - TextEditingController divisionController = TextEditingController(); - TextEditingController unionVillageController = TextEditingController(); - TextEditingController streetHouseController = TextEditingController(); - DateTime? dateTimeController = DateTime.now(); - - void _insertImage() async { - final selector = ImagePicker(); - final selectedFile = await selector.pickImage(source: ImageSource.gallery); - - if (selectedFile != null) { - setState(() { - selectedImage = selectedFile; - }); - } - } - bool areAllFieldsFilled() { - return whatWasLost.text.isNotEmpty && - itemCategory.text.isNotEmpty && - additionalInfo.text.isNotEmpty && - cityController.text.isNotEmpty && - divisionController.text.isNotEmpty && - unionVillageController.text.isNotEmpty && - streetHouseController.text.isNotEmpty && - selectedImage != null && - dateTimeController != null; - } - - Future submitLostItem() async { - if(areAllFieldsFilled()) { - try { - // Create a Firestore instance - FirebaseFirestore firestore = FirebaseFirestore.instance; - CollectionReference collectionReference = firestore.collection( - 'LostProduct'); - - Timestamp dateTimeTimestamp = Timestamp.fromDate(dateTimeController!); - - // Define a map with the data to be saved - Map lostItemData = { - 'LostItem': whatWasLost.text, - 'Category': itemCategory.text, - 'DateTime': dateTimeTimestamp, - 'Description': additionalInfo.text, - 'CityLocation': cityController.text, - 'DivisionLocation': divisionController.text, - 'UnionVillageLocation': unionVillageController.text, - 'StreetHouseLocation': streetHouseController.text, - }; - await collectionReference.add(lostItemData); - - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Lost Item Posted!', textAlign: TextAlign.center), - content: - Text('You have successfully created your Lost Item post!'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text('Okay'), - ), - ], - ), - ); - - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: (context) => LoginPage(), - // ), - // ); - } catch (e) { - showDialog( - context: context, - builder: (context) => - AlertDialog( - content: - Text('Error submitting lost item info'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text('Okay'), - ), - ], - ), - ); - } - } - else{ - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Error'), - content: - Text('Please fill all the required fields before submitting!'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text('Okay'), - ), - ], - ), - ); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: FutureBuilder( - future: Firebase.initializeApp( - options: DefaultFirebaseOptions.currentPlatform, - ), - builder: (context, snapshot){ - return Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color.fromARGB(255, 45, 44, 46), - Color.fromARGB(255, 5, 63, 111) - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: Center( - child: Padding(padding: const EdgeInsets.all(15.0), - child: SingleChildScrollView( - child: Column( - children: [ - Container( - width: MediaQuery.of(context).size.width * 0.8, - child: DrawerHeader( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - child: Text( - ' Lost ', - textScaleFactor: ScaleSize.textScaleFactor(context), - style: TextStyle( - color: Colors.grey, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 2, - ), - ), - ), - GestureDetector( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => PostFoundItemPage(), - ), - ); - }, - child: Text( - ' Found ', - textScaleFactor: ScaleSize.textScaleFactor(context), - style: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 1, - ), - ), - ) - ], - ), - ) - ), - // Lost/Found radio button group - - const SizedBox(height: 16), - Container( - width: MediaQuery.of(context).size.width * 0.75, - height: MediaQuery.of(context).size.height * 0.075, - child: TextButton( - onPressed: _insertImage, - style: TextButton.styleFrom( - backgroundColor: Colors.cyan, - shadowColor: Colors.green, - ), - child: const Text('Insert Lost Product Image', style: TextStyle( - color: Colors.brown, - fontWeight: FontWeight.bold, - ) - ), - ), - ), - const SizedBox(height: 16), - Container( - width: MediaQuery.of(context).size.width * 0.75, - child: Align( - alignment: Alignment.center, - child: DateTimePicker( - // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, - type: DateTimePickerType.dateTimeSeparate, // Adjust the type based on your requirements - dateMask: 'd MMM, yyyy', - initialValue: DateTime.now().toString(), - firstDate: DateTime(2000), // Adjust the firstDate based on your requirements - lastDate: DateTime(2099), - icon: Icon(Icons.date_range_sharp), - dateLabelText: 'Date', - style: TextStyle( - color: Colors.deepOrangeAccent, - fontWeight: FontWeight.bold, - ), - timeLabelText: "Hour", - selectableDayPredicate: (date) { - return true; - }, - onChanged: (value) => { - dateTimeController = DateTime.parse(value), - // dateTimeController = value as DateTimePicker, - }, - decoration: InputDecoration( - border: OutlineInputBorder( - borderSide: BorderSide( - color: Color.fromARGB(255, 156, 178, 197), // Border color - ), - borderRadius: BorderRadius.all( - Radius.circular(15.0), // Border radius - ), - ), - ) - , - ), - ), - ), - - const SizedBox(height: 16), - MyTextField( - controller: whatWasLost, - hintText: 'Walton Primo RX7', - obscureText: false, - prefixIcon: Icons.cases, - labelText: 'What was Lost', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - MyTextField( - controller: itemCategory, - hintText: 'Mobile', - obscureText: false, - prefixIcon: Icons.miscellaneous_services, - labelText: 'Item Category', - keyboardType: TextInputType.emailAddress, - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - Container( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: divisionController, - hintText: 'Chittagong', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Division', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z. ]')) - ], - ), - ), - Container( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: cityController, - hintText: 'Hathazari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'City', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z. ]')) - ], - ), - ) - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - Container( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: streetHouseController, - hintText: 'Road no: 3, House no: 7', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Street/House No.', - keyboardType: TextInputType.streetAddress, - ), - ), - Container( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: unionVillageController, - hintText: 'Fatikchhari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Union/Village', - keyboardType: TextInputType.streetAddress, - ), - ) - ], - ), - const SizedBox(height: 16), - MyTextField( - controller: additionalInfo, - hintText: 'Context and description of item', - obscureText: false, - prefixIcon: Icons.info_outlined, - labelText: 'Additional Info', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - - BackButton( - onPressed:() => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => LoginPage(), - ), - ), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.greenAccent, - )), - const SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(width: 16), - SizedBox( - height: MediaQuery.of(context).size.height * 0.05, - width: MediaQuery.of(context).size.width * 0.250, - child: ElevatedButton( - onPressed: submitLostItem, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - // splashFactory: InkRipple.splashFactory, - ), - child: const Text('Submit', style: TextStyle( - color: Colors.deepPurple, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 0.90, - ), - ), - ), - ), - ], - ), - - ] - ), - ), - ), - ), - // }, - ); - } - ), - ); - } -} \ No newline at end of file +import 'dart:math'; + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/material.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; +import 'package:retrieve_me/pages/login.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:date_time_picker/date_time_picker.dart'; +import '../Components/my_textfield.dart'; +import '../Components/navigation_drawer_widget.dart'; +import '../firebase_options.dart'; +import '../provider/navigation_provider.dart'; + +GlobalKey _sKey = GlobalKey(); + +class ScaleSize { + static double textScaleFactor(BuildContext context, + {double maxTextScaleFactor = 2}) { + final width = MediaQuery.of(context).size.width; + double val = (width / 1400) * maxTextScaleFactor; + return max(1, min(val, maxTextScaleFactor)); + } +} + +class PostLostItemPage extends StatefulWidget { + const PostLostItemPage({super.key}); + + @override + State createState() => _PostLostItemPageState(); +} + +class _PostLostItemPageState extends State { + XFile? selectedImage; + TextEditingController whatWasLost = TextEditingController(); + TextEditingController itemCategory = TextEditingController(); + TextEditingController additionalInfo = TextEditingController(); + TextEditingController cityController = TextEditingController(); + TextEditingController divisionController = TextEditingController(); + TextEditingController unionVillageController = TextEditingController(); + TextEditingController streetHouseController = TextEditingController(); + DateTime? dateTimeController = DateTime.now(); + + void _insertImage() async { + final selector = ImagePicker(); + final selectedFile = await selector.pickImage(source: ImageSource.gallery); + + if (selectedFile != null) { + setState(() { + selectedImage = selectedFile; + }); + } + } + + bool areAllFieldsFilled() { + return whatWasLost.text.isNotEmpty && + itemCategory.text.isNotEmpty && + additionalInfo.text.isNotEmpty && + cityController.text.isNotEmpty && + divisionController.text.isNotEmpty && + unionVillageController.text.isNotEmpty && + streetHouseController.text.isNotEmpty && + selectedImage != null && + dateTimeController != null; + } + + Future submitLostItem() async { + if (areAllFieldsFilled()) { + try { + // Create a Firestore instance + FirebaseFirestore firestore = FirebaseFirestore.instance; + CollectionReference collectionReference = + firestore.collection('LostProduct'); + + Timestamp dateTimeTimestamp = Timestamp.fromDate(dateTimeController!); + + // Define a map with the data to be saved + Map lostItemData = { + 'LostItem': whatWasLost.text, + 'Category': itemCategory.text, + 'DateTime': dateTimeTimestamp, + 'Description': additionalInfo.text, + 'CityLocation': cityController.text, + 'DivisionLocation': divisionController.text, + 'UnionVillageLocation': unionVillageController.text, + 'StreetHouseLocation': streetHouseController.text, + }; + await collectionReference.add(lostItemData); + + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Lost Item Posted!', textAlign: TextAlign.center), + content: const Text('You have successfully created your Lost Item post!'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Okay'), + ), + ], + ), + ); + + // Navigator.of(context).push( + // MaterialPageRoute( + // builder: (context) => LoginPage(), + // ), + // ); + } catch (e) { + showDialog( + context: context, + builder: (context) => AlertDialog( + content: const Text('Error submitting lost item info'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Okay'), + ), + ], + ), + ); + } + } else { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Error'), + content: + const Text('Please fill all the required fields before submitting!'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Okay'), + ), + ], + ), + ); + } + } + +// ... + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (context) => + NavigationProvider(), // Replace YourProviderClass with your actual provider class + child: Scaffold( + drawer: const NavigationDrawerWidget(), + key: _sKey, + // appBar: AppBar( + // title: const Text('Post Lost Item'), + // centerTitle: true, + // backgroundColor: Colors.indigo, + // ), + body: FutureBuilder( + future: Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ), + builder: (context, snapshot) { + // Your widget tree here + return Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111) + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: Center( + child: Padding( + padding: const EdgeInsets.all(15.0), + child: SingleChildScrollView( + child: Column(children: [ + Container( + child: IconButton( + onPressed: () { + _sKey.currentState!.openDrawer(); + }, + icon: const Icon( + Icons.menu, + color: Colors.white, + size: 30, + )), + ), + SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + child: DrawerHeader( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + GestureDetector( + child: Text( + ' Lost ', + textScaleFactor: + ScaleSize.textScaleFactor(context), + style: const TextStyle( + color: Colors.grey, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 2, + ), + ), + ), + GestureDetector( + onTap: () { + // Navigator.of(context).push( + // MaterialPageRoute( + // builder: (context) => + // PostFoundItemPage(), + // ), + // ); + // Navigator.pop(context); + }, + child: Text( + ' Found ', + textScaleFactor: + ScaleSize.textScaleFactor(context), + style: const TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 1, + ), + ), + ) + ], + ), + )), + // Lost/Found radio button group + + const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + height: MediaQuery.of(context).size.height * 0.075, + child: TextButton( + onPressed: _insertImage, + style: TextButton.styleFrom( + backgroundColor: Colors.cyan, + shadowColor: Colors.green, + ), + child: const Text('Insert Lost Product Image', + style: TextStyle( + color: Colors.brown, + fontWeight: FontWeight.bold, + )), + ), + ), + const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + child: Align( + alignment: Alignment.center, + child: DateTimePicker( + // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, + type: DateTimePickerType + .dateTimeSeparate, // Adjust the type based on your requirements + dateMask: 'd MMM, yyyy', + initialValue: DateTime.now().toString(), + firstDate: DateTime( + 2000), // Adjust the firstDate based on your requirements + lastDate: DateTime(2099), + icon: const Icon(Icons.date_range_sharp), + dateLabelText: 'Date', + style: const TextStyle( + color: Colors.deepOrangeAccent, + fontWeight: FontWeight.bold, + ), + timeLabelText: "Hour", + selectableDayPredicate: (date) { + return true; + }, + onChanged: (value) => { + dateTimeController = DateTime.parse(value), + // dateTimeController = value as DateTimePicker, + }, + decoration: const InputDecoration( + border: OutlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB( + 255, 156, 178, 197), // Border color + ), + borderRadius: BorderRadius.all( + Radius.circular(15.0), // Border radius + ), + ), + ), + ), + ), + ), + + const SizedBox(height: 16), + MyTextField( + controller: whatWasLost, + hintText: 'Walton Primo RX7', + obscureText: false, + prefixIcon: Icons.cases, + labelText: 'What was Lost', + keyboardType: TextInputType.text, + ), + const SizedBox(height: 16), + MyTextField( + controller: itemCategory, + hintText: 'Mobile', + obscureText: false, + prefixIcon: Icons.miscellaneous_services, + labelText: 'Item Category', + keyboardType: TextInputType.emailAddress, + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + // City + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: divisionController, + hintText: 'Chittagong', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Division', + keyboardType: TextInputType.streetAddress, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[a-zA-Z. ]')) + ], + ), + ), + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: cityController, + hintText: 'Hathazari', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'City', + keyboardType: TextInputType.streetAddress, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[a-zA-Z. ]')) + ], + ), + ) + ], + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + // City + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: streetHouseController, + hintText: 'Road no: 3, House no: 7', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Street/House No.', + keyboardType: TextInputType.streetAddress, + ), + ), + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: unionVillageController, + hintText: 'Fatikchhari', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Union/Village', + keyboardType: TextInputType.streetAddress, + ), + ) + ], + ), + const SizedBox(height: 16), + MyTextField( + controller: additionalInfo, + hintText: 'Context and description of item', + obscureText: false, + prefixIcon: Icons.info_outlined, + labelText: 'Additional Info', + keyboardType: TextInputType.text, + ), + const SizedBox(height: 16), + + BackButton( + onPressed: () => Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => LoginPage(), + ), + ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.greenAccent, + )), + const SizedBox(height: 32), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(width: 16), + SizedBox( + height: MediaQuery.of(context).size.height * 0.05, + width: MediaQuery.of(context).size.width * 0.250, + child: ElevatedButton( + onPressed: submitLostItem, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Submit', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.90, + ), + ), + ), + ), + ], + ), + ]), + ), + ), + ), + // }, + ); + }, + ), + ), + ); + } +} diff --git a/lib/pages/registration.dart b/lib/pages/registration.dart index 73fcdbf..50df821 100644 --- a/lib/pages/registration.dart +++ b/lib/pages/registration.dart @@ -1,307 +1,311 @@ -import 'dart:js_util'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:retrieve_me/Components/my_textfield.dart'; -import 'package:retrieve_me/pages/login.dart'; -import '../firebase_options.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:google_fonts/google_fonts.dart'; - -class RegistrationPage extends StatefulWidget { - const RegistrationPage({super.key}); - - @override - RegistrationPageState createState() => RegistrationPageState(); -} - -class RegistrationPageState extends State { - // TextEditingController registrationController = TextEditingController(); - TextEditingController firstNameController = TextEditingController(); - TextEditingController lastNameController = TextEditingController(); - TextEditingController contactNumberController = TextEditingController(); - TextEditingController addressController = TextEditingController(); - TextEditingController emailController = TextEditingController(); - TextEditingController passwordController = TextEditingController(); - - XFile? selectedImage; - - Future _submitRegistration() async { - if (_areAllFieldsFilled()) { - final firstName = firstNameController.text; - final lastName = lastNameController.text; - final contactNumber = contactNumberController.text; - final email = emailController.text; - final password = passwordController.text; - await FirebaseAuth.instance - .createUserWithEmailAndPassword( - email: email, - password: password, - ); - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Registered Sucessfully!'), - content: - Text('You have created a new account now!'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text('Okay'), - ), - ], - ), - ); - //route to new page - // confirm registration and insert to database - // Navigator.push( - // context, - // MaterialPageRoute(builder: (context) => ConfirmedRegistration()), - // ); - } else { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Error'), - content: - Text('Please fill all the required fields before submitting!'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text('Okay'), - ), - ], - ), - ); - } - } - - void _insertImage() async { - final selector = ImagePicker(); - final selectedFile = await selector.pickImage(source: ImageSource.gallery); - - if (selectedFile != null) { - setState(() { - selectedImage = selectedFile; - }); - } - } - - bool _areAllFieldsFilled() { - return firstNameController.text.isNotEmpty && - lastNameController.text.isNotEmpty && - contactNumberController.text.isNotEmpty && - addressController.text.isNotEmpty && - emailController.text.isNotEmpty && - passwordController.text.isNotEmpty && - selectedImage != null; - } - - void _resetFields() { - firstNameController.clear(); - lastNameController.clear(); - contactNumberController.clear(); - addressController.clear(); - emailController.clear(); - passwordController.clear(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: FutureBuilder( - future: Firebase.initializeApp( - options: DefaultFirebaseOptions.currentPlatform, - ), - builder: (context, snapshot) { - return Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color.fromARGB(255, 45, 44, 46), - Color.fromARGB(255, 5, 63, 111) - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: SingleChildScrollView( - child: Column( - children: [ - Container( - width: MediaQuery.of(context).size.width * 0.8, - child: DrawerHeader( - child: Align( - alignment: Alignment.centerLeft, - child: Text( - 'REGISTRATION', - style: GoogleFonts.oswald( - // Google font - textStyle: TextStyle( - fontSize: 35, - color: Colors.white, - fontWeight: FontWeight.bold), - ), - ), - ), - ), - ), - const SizedBox(height: 16), - MyTextField( - controller: firstNameController, - hintText: 'John', - obscureText: false, - prefixIcon: Icons.person, - labelText: 'First Name', - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z. ]')) - ], - ), - - const SizedBox(height: 16), - MyTextField( - controller: lastNameController, - hintText: 'Doe', - obscureText: false, - prefixIcon: Icons.person, - labelText: 'Last Name', - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z. ]')) - ], - ), - const SizedBox(height: 16), - MyTextField( - controller: contactNumberController, - hintText: '01765432109', // You can provide a hint text here - obscureText: false, // Set to true for password fields - prefixIcon: Icons.phone, - labelText: 'Contact Number', - keyboardType: TextInputType.phone, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], // Allow digits only - ), - const SizedBox(height: 16), - MyTextField( - controller: addressController, - hintText: 'Zero Point, Chittagong University Road, New Mooring Chittagong', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Address', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - MyTextField( - controller: emailController, - hintText: 'johnKais@email.com', - obscureText: false, - prefixIcon: Icons.email, - labelText: 'Email', - keyboardType: TextInputType.emailAddress, - ), - const SizedBox(height: 16), - MyTextField( - controller: passwordController, - hintText: '', - obscureText: true, - prefixIcon: Icons.lock, - labelText: 'Password', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - Container( - width: MediaQuery.of(context).size.width * 0.75, - height: MediaQuery.of(context).size.height * 0.075, - child: TextButton( - onPressed: _insertImage, - style: TextButton.styleFrom( - backgroundColor: Colors.cyan, - shadowColor: Colors.green, - ), - child: const Text('Insert Profile Image', style: TextStyle( - color: Colors.brown, - fontWeight: FontWeight.bold, - )), - ), - ), - const SizedBox(height: 36), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - height: MediaQuery.of(context).size.height * 0.05, - width: MediaQuery.of(context).size.width * 0.250, - child: ElevatedButton( - onPressed: _resetFields, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black, - ), - child: const Text('Reset', style: TextStyle( - color: Colors.deepPurpleAccent, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 0.90, - )), - ), - ), - const SizedBox(width: 16), - SizedBox( - height: MediaQuery.of(context).size.height * 0.05, - width: MediaQuery.of(context).size.width * 0.250, - child: ElevatedButton( - onPressed: _submitRegistration, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - // splashFactory: InkRipple.splashFactory, - ), - child: const Text('Register', style: TextStyle( - color: Colors.deepPurple, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 0.90, - ), - ), - ), - ), - ], - ), - const SizedBox(height: 30), // - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Already a member?', - style: TextStyle(color: Colors.grey[500]), - ), - const SizedBox(width:4), - GestureDetector( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => LoginPage(), - ), - ); - }, - child: Text( - ' Log In ', - style: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ) - ], - ), - ), - ), - ), - ); - }, - )); - } -} +// import 'dart:js_util'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:retrieve_me/Components/my_textfield.dart'; +import 'package:retrieve_me/pages/login.dart'; +import '../firebase_options.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class RegistrationPage extends StatefulWidget { + const RegistrationPage({super.key}); + + @override + RegistrationPageState createState() => RegistrationPageState(); +} + +class RegistrationPageState extends State { + // TextEditingController registrationController = TextEditingController(); + TextEditingController firstNameController = TextEditingController(); + TextEditingController lastNameController = TextEditingController(); + TextEditingController contactNumberController = TextEditingController(); + TextEditingController addressController = TextEditingController(); + TextEditingController emailController = TextEditingController(); + TextEditingController passwordController = TextEditingController(); + + XFile? selectedImage; + + Future _submitRegistration() async { + if (_areAllFieldsFilled()) { + final firstName = firstNameController.text; + final lastName = lastNameController.text; + final contactNumber = contactNumberController.text; + final email = emailController.text; + final password = passwordController.text; + await FirebaseAuth.instance.createUserWithEmailAndPassword( + email: email, + password: password, + ); + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Registered Sucessfully!'), + content: const Text('You have created a new account now!'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Okay'), + ), + ], + ), + ); + //route to new page + // confirm registration and insert to database + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => ConfirmedRegistration()), + // ); + } else { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Error'), + content: + const Text('Please fill all the required fields before submitting!'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Okay'), + ), + ], + ), + ); + } + } + + void _insertImage() async { + final selector = ImagePicker(); + final selectedFile = await selector.pickImage(source: ImageSource.gallery); + + if (selectedFile != null) { + setState(() { + selectedImage = selectedFile; + }); + } + } + + bool _areAllFieldsFilled() { + return firstNameController.text.isNotEmpty && + lastNameController.text.isNotEmpty && + contactNumberController.text.isNotEmpty && + addressController.text.isNotEmpty && + emailController.text.isNotEmpty && + passwordController.text.isNotEmpty && + selectedImage != null; + } + + void _resetFields() { + firstNameController.clear(); + lastNameController.clear(); + contactNumberController.clear(); + addressController.clear(); + emailController.clear(); + passwordController.clear(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: FutureBuilder( + future: Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ), + builder: (context, snapshot) { + return Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111) + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: SingleChildScrollView( + child: Column( + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + child: DrawerHeader( + child: Align( + alignment: Alignment.centerLeft, + child: Text( + 'REGISTRATION', + style: GoogleFonts.oswald( + // Google font + textStyle: const TextStyle( + fontSize: 35, + color: Colors.white, + fontWeight: FontWeight.bold), + ), + ), + ), + ), + ), + const SizedBox(height: 16), + MyTextField( + controller: firstNameController, + hintText: 'John', + obscureText: false, + prefixIcon: Icons.person, + labelText: 'First Name', + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z. ]')) + ], + ), + + const SizedBox(height: 16), + MyTextField( + controller: lastNameController, + hintText: 'Doe', + obscureText: false, + prefixIcon: Icons.person, + labelText: 'Last Name', + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z. ]')) + ], + ), + const SizedBox(height: 16), + MyTextField( + controller: contactNumberController, + hintText: + '01765432109', // You can provide a hint text here + obscureText: false, // Set to true for password fields + prefixIcon: Icons.phone, + labelText: 'Contact Number', + keyboardType: TextInputType.phone, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], // Allow digits only + ), + const SizedBox(height: 16), + MyTextField( + controller: addressController, + hintText: + 'Zero Point, Chittagong University Road, New Mooring Chittagong', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Address', + keyboardType: TextInputType.text, + ), + const SizedBox(height: 16), + MyTextField( + controller: emailController, + hintText: 'johnKais@email.com', + obscureText: false, + prefixIcon: Icons.email, + labelText: 'Email', + keyboardType: TextInputType.emailAddress, + ), + const SizedBox(height: 16), + MyTextField( + controller: passwordController, + hintText: '', + obscureText: true, + prefixIcon: Icons.lock, + labelText: 'Password', + keyboardType: TextInputType.text, + ), + const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + height: MediaQuery.of(context).size.height * 0.075, + child: TextButton( + onPressed: _insertImage, + style: TextButton.styleFrom( + backgroundColor: Colors.cyan, + shadowColor: Colors.green, + ), + child: const Text('Insert Profile Image', + style: TextStyle( + color: Colors.brown, + fontWeight: FontWeight.bold, + )), + ), + ), + const SizedBox(height: 36), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + height: MediaQuery.of(context).size.height * 0.05, + width: MediaQuery.of(context).size.width * 0.250, + child: ElevatedButton( + onPressed: _resetFields, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black, + ), + child: const Text('Reset', + style: TextStyle( + color: Colors.deepPurpleAccent, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.90, + )), + ), + ), + const SizedBox(width: 16), + SizedBox( + height: MediaQuery.of(context).size.height * 0.05, + width: MediaQuery.of(context).size.width * 0.250, + child: ElevatedButton( + onPressed: _submitRegistration, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Register', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.90, + ), + ), + ), + ), + ], + ), + const SizedBox(height: 30), // + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Already a member?', + style: TextStyle(color: Colors.grey[500]), + ), + const SizedBox(width: 4), + GestureDetector( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => LoginPage(), + ), + ); + }, + child: const Text( + ' Log In ', + style: TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ) + ], + ), + ), + ), + ), + ); + }, + )); + } +} diff --git a/lib/provider/navigation_provider.dart b/lib/provider/navigation_provider.dart new file mode 100644 index 0000000..9660388 --- /dev/null +++ b/lib/provider/navigation_provider.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; + +class NavigationProvider extends ChangeNotifier { + bool _isCollapsed = false; + + bool get isCollapsed => _isCollapsed; + void toggleCollapsed() { + _isCollapsed = !_isCollapsed; + notifyListeners(); + } +} diff --git a/lib/tempCodeRunnerFile.dart b/lib/tempCodeRunnerFile.dart index ec13e0c..6655c53 100644 --- a/lib/tempCodeRunnerFile.dart +++ b/lib/tempCodeRunnerFile.dart @@ -1,4 +1,4 @@ -required this.title}); - - // This widget is the home page of your application. It is stateful, meaning +// required this.title}); + + // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defin \ No newline at end of file diff --git a/linux/.gitignore b/linux/.gitignore index d3896c9..c7ea17f 100644 --- a/linux/.gitignore +++ b/linux/.gitignore @@ -1 +1 @@ -flutter/ephemeral +flutter/ephemeral diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 976ef5b..7f4e8ae 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -1,139 +1,139 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.10) -project(runner LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "retrieve_me") -# The unique GTK application identifier for this application. See: -# https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.kais29.retrieve_me") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Load bundled libraries from the lib/ directory relative to the binary. -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Root filesystem for cross-building. -if(FLUTTER_TARGET_PLATFORM_SYSROOT) - set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endif() - -# Define build configuration options. -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") -endif() - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_14) - target_compile_options(${TARGET} PRIVATE -Wall -Werror) - target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") - target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Define the application target. To change its name, change BINARY_NAME above, -# not the value here, or `flutter run` will no longer work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) - -# Only the install-generated bundle's copy of the executable will launch -# correctly, since the resources must in the right relative locations. To avoid -# people trying to run the unbundled copy, put it in a subdirectory instead of -# the default top-level location. -set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# By default, "installing" just makes a relocatable bundle in the build -# directory. -set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -# Start with a clean build bundle directory every time. -install(CODE " - file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") - " COMPONENT Runtime) - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "retrieve_me") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.kais29.retrieve_me") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/CMakeLists.txt b/linux/flutter/CMakeLists.txt index d5bd016..27860e8 100644 --- a/linux/flutter/CMakeLists.txt +++ b/linux/flutter/CMakeLists.txt @@ -1,88 +1,88 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.10) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. - -# Serves the same purpose as list(TRANSFORM ... PREPEND ...), -# which isn't available in 3.10. -function(list_prepend LIST_NAME PREFIX) - set(NEW_LIST "") - foreach(element ${${LIST_NAME}}) - list(APPEND NEW_LIST "${PREFIX}${element}") - endforeach(element) - set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) -endfunction() - -# === Flutter Library === -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) -pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) - -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "fl_basic_message_channel.h" - "fl_binary_codec.h" - "fl_binary_messenger.h" - "fl_dart_project.h" - "fl_engine.h" - "fl_json_message_codec.h" - "fl_json_method_codec.h" - "fl_message_codec.h" - "fl_method_call.h" - "fl_method_channel.h" - "fl_method_codec.h" - "fl_method_response.h" - "fl_plugin_registrar.h" - "fl_plugin_registry.h" - "fl_standard_message_codec.h" - "fl_standard_method_codec.h" - "fl_string_codec.h" - "fl_value.h" - "fl_view.h" - "flutter_linux.h" -) -list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") -target_link_libraries(flutter INTERFACE - PkgConfig::GTK - PkgConfig::GLIB - PkgConfig::GIO -) -add_dependencies(flutter flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} -) +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/main.cc b/linux/main.cc index e7c5c54..4340ffc 100644 --- a/linux/main.cc +++ b/linux/main.cc @@ -1,6 +1,6 @@ -#include "my_application.h" - -int main(int argc, char** argv) { - g_autoptr(MyApplication) app = my_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); -} +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/linux/my_application.cc b/linux/my_application.cc index afb319d..79d3b0f 100644 --- a/linux/my_application.cc +++ b/linux/my_application.cc @@ -1,104 +1,104 @@ -#include "my_application.h" - -#include -#ifdef GDK_WINDOWING_X11 -#include -#endif - -#include "flutter/generated_plugin_registrant.h" - -struct _MyApplication { - GtkApplication parent_instance; - char** dart_entrypoint_arguments; -}; - -G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) - -// Implements GApplication::activate. -static void my_application_activate(GApplication* application) { - MyApplication* self = MY_APPLICATION(application); - GtkWindow* window = - GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); - - // Use a header bar when running in GNOME as this is the common style used - // by applications and is the setup most users will be using (e.g. Ubuntu - // desktop). - // If running on X and not using GNOME then just use a traditional title bar - // in case the window manager does more exotic layout, e.g. tiling. - // If running on Wayland assume the header bar will work (may need changing - // if future cases occur). - gboolean use_header_bar = TRUE; -#ifdef GDK_WINDOWING_X11 - GdkScreen* screen = gtk_window_get_screen(window); - if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } - } -#endif - if (use_header_bar) { - GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); - gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "retrieve_me"); - gtk_header_bar_set_show_close_button(header_bar, TRUE); - gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } else { - gtk_window_set_title(window, "retrieve_me"); - } - - gtk_window_set_default_size(window, 1280, 720); - gtk_widget_show(GTK_WIDGET(window)); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); - - FlView* view = fl_view_new(project); - gtk_widget_show(GTK_WIDGET(view)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - - fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - - gtk_widget_grab_focus(GTK_WIDGET(view)); -} - -// Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { - MyApplication* self = MY_APPLICATION(application); - // Strip out the first argument as it is the binary name. - self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); - - g_autoptr(GError) error = nullptr; - if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; - } - - g_application_activate(application); - *exit_status = 0; - - return TRUE; -} - -// Implements GObject::dispose. -static void my_application_dispose(GObject* object) { - MyApplication* self = MY_APPLICATION(object); - g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); - G_OBJECT_CLASS(my_application_parent_class)->dispose(object); -} - -static void my_application_class_init(MyApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; - G_OBJECT_CLASS(klass)->dispose = my_application_dispose; -} - -static void my_application_init(MyApplication* self) {} - -MyApplication* my_application_new() { - return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, - nullptr)); -} +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "retrieve_me"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "retrieve_me"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/linux/my_application.h b/linux/my_application.h index 72271d5..8f20fb5 100644 --- a/linux/my_application.h +++ b/linux/my_application.h @@ -1,18 +1,18 @@ -#ifndef FLUTTER_MY_APPLICATION_H_ -#define FLUTTER_MY_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, - GtkApplication) - -/** - * my_application_new: - * - * Creates a new Flutter-based application. - * - * Returns: a new #MyApplication. - */ -MyApplication* my_application_new(); - -#endif // FLUTTER_MY_APPLICATION_H_ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/macos/.gitignore b/macos/.gitignore index 746adbb..d4e0569 100644 --- a/macos/.gitignore +++ b/macos/.gitignore @@ -1,7 +1,7 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b..f022c34 100644 --- a/macos/Flutter/Flutter-Debug.xcconfig +++ b/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1 @@ -#include "ephemeral/Flutter-Generated.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/Flutter-Release.xcconfig b/macos/Flutter/Flutter-Release.xcconfig index c2efd0b..f022c34 100644 --- a/macos/Flutter/Flutter-Release.xcconfig +++ b/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1 @@ -#include "ephemeral/Flutter-Generated.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 415d2a1..c4e31a1 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -1,695 +1,695 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC10EC2044A3C60003C045; - remoteInfo = Runner; - }; - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* retrieve_me.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "retrieve_me.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 331C80D2294CF70F00263BE5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C80D6294CF71000263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C80D7294CF71000263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 331C80D6294CF71000263BE5 /* RunnerTests */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* retrieve_me.app */, - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C80D4294CF70F00263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - 331C80D1294CF70F00263BE5 /* Sources */, - 331C80D2294CF70F00263BE5 /* Frameworks */, - 331C80D3294CF70F00263BE5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 331C80DA294CF71000263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* retrieve_me.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C80D4294CF70F00263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 33CC10EC2044A3C60003C045; - }; - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 331C80D4294CF70F00263BE5 /* RunnerTests */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C80D3294CF70F00263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C80D1294CF70F00263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC10EC2044A3C60003C045 /* Runner */; - targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; - }; - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 331C80DB294CF71000263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/retrieve_me.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/retrieve_me"; - }; - name = Debug; - }; - 331C80DC294CF71000263BE5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/retrieve_me.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/retrieve_me"; - }; - name = Release; - }; - 331C80DD294CF71000263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/retrieve_me.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/retrieve_me"; - }; - name = Profile; - }; - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - 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_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - 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_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - 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_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - 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_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - 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_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - 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_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - 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_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C80DB294CF71000263BE5 /* Debug */, - 331C80DC294CF71000263BE5 /* Release */, - 331C80DD294CF71000263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* retrieve_me.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "retrieve_me.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* retrieve_me.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* retrieve_me.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/retrieve_me.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/retrieve_me"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/retrieve_me.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/retrieve_me"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/retrieve_me.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/retrieve_me"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + 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_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + 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_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + 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_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + 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_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + 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_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + 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_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + 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_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist index 18d9810..fc6bf80 100644 --- a/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -1,8 +1,8 @@ - - - - - IDEDidComputeMac32BitWarning - - - + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index de9be95..44518d3 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,98 +1,98 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/Runner.xcworkspace/contents.xcworkspacedata b/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..59c6d39 100644 --- a/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -1,7 +1,7 @@ - - - - - + + + + + diff --git a/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist index 18d9810..fc6bf80 100644 --- a/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ b/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -1,8 +1,8 @@ - - - - - IDEDidComputeMac32BitWarning - - - + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index d53ef64..553a135 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -1,9 +1,9 @@ -import Cocoa -import FlutterMacOS - -@NSApplicationMain -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } -} +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index a2ec33f..8d4e7cb 100644 --- a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,68 +1,68 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/macos/Runner/Base.lproj/MainMenu.xib b/macos/Runner/Base.lproj/MainMenu.xib index 80e867a..4632c69 100644 --- a/macos/Runner/Base.lproj/MainMenu.xib +++ b/macos/Runner/Base.lproj/MainMenu.xib @@ -1,343 +1,343 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig index 6726f32..ef14b3c 100644 --- a/macos/Runner/Configs/AppInfo.xcconfig +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -1,14 +1,14 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = retrieve_me - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2023 com.kais29. All rights reserved. +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = retrieve_me + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.kais29.retrieveMe + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 com.kais29. All rights reserved. diff --git a/macos/Runner/Configs/Debug.xcconfig b/macos/Runner/Configs/Debug.xcconfig index 36b0fd9..b398823 100644 --- a/macos/Runner/Configs/Debug.xcconfig +++ b/macos/Runner/Configs/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Release.xcconfig b/macos/Runner/Configs/Release.xcconfig index dff4f49..d93e5dc 100644 --- a/macos/Runner/Configs/Release.xcconfig +++ b/macos/Runner/Configs/Release.xcconfig @@ -1,2 +1,2 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Warnings.xcconfig b/macos/Runner/Configs/Warnings.xcconfig index 42bcbf4..fb4d7d3 100644 --- a/macos/Runner/Configs/Warnings.xcconfig +++ b/macos/Runner/Configs/Warnings.xcconfig @@ -1,13 +1,13 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/macos/Runner/DebugProfile.entitlements b/macos/Runner/DebugProfile.entitlements index dddb8a3..51d0967 100644 --- a/macos/Runner/DebugProfile.entitlements +++ b/macos/Runner/DebugProfile.entitlements @@ -1,12 +1,12 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist index 4789daa..3733c1a 100644 --- a/macos/Runner/Info.plist +++ b/macos/Runner/Info.plist @@ -1,32 +1,32 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/macos/Runner/MainFlutterWindow.swift b/macos/Runner/MainFlutterWindow.swift index 3cc05eb..ab30cba 100644 --- a/macos/Runner/MainFlutterWindow.swift +++ b/macos/Runner/MainFlutterWindow.swift @@ -1,15 +1,15 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/macos/Runner/Release.entitlements b/macos/Runner/Release.entitlements index 852fa1a..04336df 100644 --- a/macos/Runner/Release.entitlements +++ b/macos/Runner/Release.entitlements @@ -1,8 +1,8 @@ - - - - - com.apple.security.app-sandbox - - - + + + + + com.apple.security.app-sandbox + + + diff --git a/macos/RunnerTests/RunnerTests.swift b/macos/RunnerTests/RunnerTests.swift index 5418c9f..ba12981 100644 --- a/macos/RunnerTests/RunnerTests.swift +++ b/macos/RunnerTests/RunnerTests.swift @@ -1,12 +1,12 @@ -import FlutterMacOS -import Cocoa -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. - } - -} +import FlutterMacOS +import Cocoa +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/node_modules/.package-lock.json b/node_modules/.package-lock.json index e5e26f4..190b760 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -1,12 +1,12 @@ -{ - "name": "retrieve_me", - "lockfileVersion": 3, - "requires": true, - "packages": { - "node_modules/g": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/g/-/g-2.0.1.tgz", - "integrity": "sha512-Fi6Ng5fZ/ANLQ15H11hCe+09sgUoNvDEBevVgx3KoYOhsH5iLNPn54hx0jPZ+3oSWr+xajnp2Qau9VmPsc7hTA==" - } - } -} +{ + "name": "retrieve_me", + "lockfileVersion": 3, + "requires": true, + "packages": { + "node_modules/g": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/g/-/g-2.0.1.tgz", + "integrity": "sha512-Fi6Ng5fZ/ANLQ15H11hCe+09sgUoNvDEBevVgx3KoYOhsH5iLNPn54hx0jPZ+3oSWr+xajnp2Qau9VmPsc7hTA==" + } + } +} diff --git a/node_modules/g/LICENSE b/node_modules/g/LICENSE index 8952fa5..170f9ab 100644 --- a/node_modules/g/LICENSE +++ b/node_modules/g/LICENSE @@ -1,19 +1,19 @@ -Copyright 2011 Sleepless Software Inc. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. +Copyright 2011 Sleepless Software Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/node_modules/g/README.md b/node_modules/g/README.md index 4b990ab..781f64e 100644 --- a/node_modules/g/README.md +++ b/node_modules/g/README.md @@ -1,32 +1,32 @@ - -# g - -Let's you easily get some module functions made into globals: - - require("g")("util"); - inspect(["foo"]); - -or - - require("g")("log5"); - I("Hi mom"); - - -## Yes, I know ... - -Yes, I know. -It rubs you the wrong way. -It goes against everything you've been taught. -It's sick and wrong. -It's dangerous and irresponsible. -It's immoral and a crime against humanity. - -So ... - -THIS IS NOT FOR PRODUCTION SOFTWARE. -ONLY USE IT FOR PROTOTYPING AND PROOF-OF-CONCEPT WORK. -DO NOT USE THIS FOR ANYTHING TRULY IMPORTANT. - -Okay? We good? Alright then. - - + +# g + +Let's you easily get some module functions made into globals: + + require("g")("util"); + inspect(["foo"]); + +or + + require("g")("log5"); + I("Hi mom"); + + +## Yes, I know ... + +Yes, I know. +It rubs you the wrong way. +It goes against everything you've been taught. +It's sick and wrong. +It's dangerous and irresponsible. +It's immoral and a crime against humanity. + +So ... + +THIS IS NOT FOR PRODUCTION SOFTWARE. +ONLY USE IT FOR PROTOTYPING AND PROOF-OF-CONCEPT WORK. +DO NOT USE THIS FOR ANYTHING TRULY IMPORTANT. + +Okay? We good? Alright then. + + diff --git a/node_modules/g/index.js b/node_modules/g/index.js index f4ae660..0668688 100644 --- a/node_modules/g/index.js +++ b/node_modules/g/index.js @@ -1,46 +1,46 @@ -/* -Copyright 2015 Sleepless Software Inc. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. -*/ - - -G = function(mod) { - if(typeof mod === "string") { - mod = require(mod) - } - for(k in mod) { - global[k] = mod[k] - } - return mod -} - - - -if((typeof process) !== 'undefined') { - // we're in node.js (versus browser) - module.exports = G - - if(require && require.main === module) { - // this module is being executed directly; run test - require('./test.js') - } - -} - +/* +Copyright 2015 Sleepless Software Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +*/ + + +G = function(mod) { + if(typeof mod === "string") { + mod = require(mod) + } + for(k in mod) { + global[k] = mod[k] + } + return mod +} + + + +if((typeof process) !== 'undefined') { + // we're in node.js (versus browser) + module.exports = G + + if(require && require.main === module) { + // this module is being executed directly; run test + require('./test.js') + } + +} + diff --git a/node_modules/g/package.json b/node_modules/g/package.json index 4c8fb34..9e501c4 100644 --- a/node_modules/g/package.json +++ b/node_modules/g/package.json @@ -1,11 +1,11 @@ -{ - "name": "g", - "version": "2.0.1", - "description" : "Globalize module functions", - "author": "Joe Hitchens (sleepless.com)", - "license": { - "type": "MIT", - "url": "https://github.com/sleeplessinc/g/raw/master/LICENSE" - }, - "repository": "git://github.com/sleeplessinc/g.git" -} +{ + "name": "g", + "version": "2.0.1", + "description" : "Globalize module functions", + "author": "Joe Hitchens (sleepless.com)", + "license": { + "type": "MIT", + "url": "https://github.com/sleeplessinc/g/raw/master/LICENSE" + }, + "repository": "git://github.com/sleeplessinc/g.git" +} diff --git a/node_modules/g/test.js b/node_modules/g/test.js index cb4463d..38db2f5 100644 --- a/node_modules/g/test.js +++ b/node_modules/g/test.js @@ -1,7 +1,7 @@ - - -require("./index.js")("util"); - -console.log(inspect({"Woot!":"Test complete."})); - - + + +require("./index.js")("util"); + +console.log(inspect({"Woot!":"Test complete."})); + + diff --git a/package-lock.json b/package-lock.json index f2b2bbb..42a6689 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ -{ - "name": "retrieve_me", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "g": "^2.0.1" - } - }, - "node_modules/g": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/g/-/g-2.0.1.tgz", - "integrity": "sha512-Fi6Ng5fZ/ANLQ15H11hCe+09sgUoNvDEBevVgx3KoYOhsH5iLNPn54hx0jPZ+3oSWr+xajnp2Qau9VmPsc7hTA==" - } - } -} +{ + "name": "retrieve_me", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "g": "^2.0.1" + } + }, + "node_modules/g": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/g/-/g-2.0.1.tgz", + "integrity": "sha512-Fi6Ng5fZ/ANLQ15H11hCe+09sgUoNvDEBevVgx3KoYOhsH5iLNPn54hx0jPZ+3oSWr+xajnp2Qau9VmPsc7hTA==" + } + } +} diff --git a/package.json b/package.json index 406654f..a98906e 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ -{ - "dependencies": { - "g": "^2.0.1" - } -} +{ + "dependencies": { + "g": "^2.0.1" + } +} diff --git a/pubspec.lock b/pubspec.lock index 6e60760..675ce6e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,570 +1,586 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _flutterfire_internals: - dependency: transitive - description: - name: _flutterfire_internals - sha256: d84d98f1992976775f83083523a34c5d22fea191eec3abb2bd09537fb623c2e0 - url: "https://pub.dev" - source: hosted - version: "1.3.7" - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - characters: - dependency: transitive - description: - name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" - url: "https://pub.dev" - source: hosted - version: "1.3.0" - clock: - dependency: transitive - description: - name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dev" - source: hosted - version: "1.1.1" - cloud_firestore: - dependency: "direct main" - description: - name: cloud_firestore - sha256: "1179ae4c69e2ea18179d844d70fc6ed2f082a2bbeb7fa62d35a2a24e2992bd4d" - url: "https://pub.dev" - source: hosted - version: "4.9.3" - cloud_firestore_platform_interface: - dependency: transitive - description: - name: cloud_firestore_platform_interface - sha256: acdcf0743bbdd0e6b342f3d2033e15d260a2c6f9434dd34b008b8f1c35e62b23 - url: "https://pub.dev" - source: hosted - version: "5.16.2" - cloud_firestore_web: - dependency: transitive - description: - name: cloud_firestore_web - sha256: "321bb0732c8d782a49aede96805e59609e05cf98b6c34370faa04103f46a4a3a" - url: "https://pub.dev" - source: hosted - version: "3.7.2" - collection: - dependency: transitive - description: - name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 - url: "https://pub.dev" - source: hosted - version: "1.17.2" - cross_file: - dependency: transitive - description: - name: cross_file - sha256: fd832b5384d0d6da4f6df60b854d33accaaeb63aa9e10e736a87381f08dee2cb - url: "https://pub.dev" - source: hosted - version: "0.3.3+5" - crypto: - dependency: transitive - description: - name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab - url: "https://pub.dev" - source: hosted - version: "3.0.3" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d - url: "https://pub.dev" - source: hosted - version: "1.0.6" - date_time_picker: - dependency: "direct main" - description: - name: date_time_picker - sha256: "6923c568bcb67a66ab7e083708d0adbcae8214b41bb84d49febc17e89e06fc4a" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - ffi: - dependency: transitive - description: - name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - file_selector_linux: - dependency: transitive - description: - name: file_selector_linux - sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" - url: "https://pub.dev" - source: hosted - version: "0.9.2+1" - file_selector_macos: - dependency: transitive - description: - name: file_selector_macos - sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6 - url: "https://pub.dev" - source: hosted - version: "0.9.3+3" - file_selector_platform_interface: - dependency: transitive - description: - name: file_selector_platform_interface - sha256: "0aa47a725c346825a2bd396343ce63ac00bda6eff2fbc43eabe99737dede8262" - url: "https://pub.dev" - source: hosted - version: "2.6.1" - file_selector_windows: - dependency: transitive - description: - name: file_selector_windows - sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0 - url: "https://pub.dev" - source: hosted - version: "0.9.3+1" - firebase_analytics: - dependency: "direct main" - description: - name: firebase_analytics - sha256: "6a8b509b81760dca2abe70c46811f3824c150e9a3f85982f062624a7bae31857" - url: "https://pub.dev" - source: hosted - version: "10.5.1" - firebase_analytics_platform_interface: - dependency: transitive - description: - name: firebase_analytics_platform_interface - sha256: acb9cb733fff14041c030ec9c71fc9be6c9d60dbe8932b2a38bc1428d638a915 - url: "https://pub.dev" - source: hosted - version: "3.7.1" - firebase_analytics_web: - dependency: transitive - description: - name: firebase_analytics_web - sha256: "56ee5baf213cae47eab0ec926261dfecb9d7089ee28edf38dca3ad0ca01601c7" - url: "https://pub.dev" - source: hosted - version: "0.5.5+1" - firebase_auth: - dependency: "direct main" - description: - name: firebase_auth - sha256: "95c74884ff25eafcbbbcd5506b738e68ee98ff54d09522a6092a2fb95d02ee7a" - url: "https://pub.dev" - source: hosted - version: "4.10.1" - firebase_auth_platform_interface: - dependency: transitive - description: - name: firebase_auth_platform_interface - sha256: "05d2636673e145d2b5eccc452c009808af4c15e8b402f34bb8fec63f2c76e86b" - url: "https://pub.dev" - source: hosted - version: "6.19.1" - firebase_auth_web: - dependency: transitive - description: - name: firebase_auth_web - sha256: "4b8374da5d8969f99453ebd65074c1d379fe781bb3680fa7f65a4d3ac4ec87b3" - url: "https://pub.dev" - source: hosted - version: "5.8.2" - firebase_core: - dependency: "direct main" - description: - name: firebase_core - sha256: "95580fa07c8ca3072a2bb1fecd792616a33f8683477d25b7d29d3a6a399e6ece" - url: "https://pub.dev" - source: hosted - version: "2.17.0" - firebase_core_platform_interface: - dependency: transitive - description: - name: firebase_core_platform_interface - sha256: b63e3be6c96ef5c33bdec1aab23c91eb00696f6452f0519401d640938c94cba2 - url: "https://pub.dev" - source: hosted - version: "4.8.0" - firebase_core_web: - dependency: transitive - description: - name: firebase_core_web - sha256: e8c408923cd3a25bd342c576a114f2126769cd1a57106a4edeaa67ea4a84e962 - url: "https://pub.dev" - source: hosted - version: "2.8.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 - url: "https://pub.dev" - source: hosted - version: "2.0.3" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - sha256: f185ac890306b5779ecbd611f52502d8d4d63d27703ef73161ca0407e815f02c - url: "https://pub.dev" - source: hosted - version: "2.0.16" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - google_fonts: - dependency: "direct main" - description: - name: google_fonts - sha256: e20ff62b158b96f392bfc8afe29dee1503c94fbea2cbe8186fd59b756b8ae982 - url: "https://pub.dev" - source: hosted - version: "5.1.0" - http: - dependency: transitive - description: - name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - image_picker: - dependency: "direct main" - description: - name: image_picker - sha256: b6951e25b795d053a6ba03af5f710069c99349de9341af95155d52665cb4607c - url: "https://pub.dev" - source: hosted - version: "0.8.9" - image_picker_android: - dependency: transitive - description: - name: image_picker_android - sha256: "0c7b83bbe2980c8a8e36e974f055e11e51675784e13a4762889feed0f3937ff2" - url: "https://pub.dev" - source: hosted - version: "0.8.8+1" - image_picker_for_web: - dependency: transitive - description: - name: image_picker_for_web - sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - image_picker_ios: - dependency: transitive - description: - name: image_picker_ios - sha256: c5538cacefacac733c724be7484377923b476216ad1ead35a0d2eadcdc0fc497 - url: "https://pub.dev" - source: hosted - version: "0.8.8+2" - image_picker_linux: - dependency: transitive - description: - name: image_picker_linux - sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" - url: "https://pub.dev" - source: hosted - version: "0.2.1+1" - image_picker_macos: - dependency: transitive - description: - name: image_picker_macos - sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" - url: "https://pub.dev" - source: hosted - version: "0.2.1+1" - image_picker_platform_interface: - dependency: transitive - description: - name: image_picker_platform_interface - sha256: ed9b00e63977c93b0d2d2b343685bed9c324534ba5abafbb3dfbd6a780b1b514 - url: "https://pub.dev" - source: hosted - version: "2.9.1" - image_picker_windows: - dependency: transitive - description: - name: image_picker_windows - sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" - url: "https://pub.dev" - source: hosted - version: "0.2.1+1" - intl: - dependency: transitive - description: - name: intl - sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" - url: "https://pub.dev" - source: hosted - version: "0.17.0" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" - lints: - dependency: transitive - description: - name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - matcher: - dependency: transitive - description: - name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" - url: "https://pub.dev" - source: hosted - version: "0.12.16" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" - url: "https://pub.dev" - source: hosted - version: "0.5.0" - meta: - dependency: transitive - description: - name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - mime: - dependency: transitive - description: - name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e - url: "https://pub.dev" - source: hosted - version: "1.0.4" - path: - dependency: transitive - description: - name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" - url: "https://pub.dev" - source: hosted - version: "1.8.3" - path_provider: - dependency: transitive - description: - name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa - url: "https://pub.dev" - source: hosted - version: "2.1.1" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" - url: "https://pub.dev" - source: hosted - version: "2.3.1" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" - url: "https://pub.dev" - source: hosted - version: "2.2.1" - platform: - dependency: transitive - description: - name: platform - sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d - url: "https://pub.dev" - source: hosted - version: "2.1.6" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 - url: "https://pub.dev" - source: hosted - version: "1.11.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" - url: "https://pub.dev" - source: hosted - version: "0.6.0" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c - url: "https://pub.dev" - source: hosted - version: "1.3.2" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - web: - dependency: transitive - description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 - url: "https://pub.dev" - source: hosted - version: "0.1.4-beta" - win32: - dependency: transitive - description: - name: win32 - sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3" - url: "https://pub.dev" - source: hosted - version: "5.0.9" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" - url: "https://pub.dev" - source: hosted - version: "1.0.3" -sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" - flutter: ">=3.7.0" +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: f5628cd9c92ed11083f425fd1f8f1bc60ecdda458c81d73b143aeda036c35fe7 + url: "https://pub.dev" + source: hosted + version: "1.3.16" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + cloud_firestore: + dependency: "direct main" + description: + name: cloud_firestore + sha256: "50e33a5cd62f7ed0e8290802a7e68e090d27738f65256977162c127303ad82ea" + url: "https://pub.dev" + source: hosted + version: "4.13.5" + cloud_firestore_platform_interface: + dependency: transitive + description: + name: cloud_firestore_platform_interface + sha256: dedbd776c04429f85726e5cfb6f929d8405da241ceec32baa7d31b7d062dad53 + url: "https://pub.dev" + source: hosted + version: "6.0.9" + cloud_firestore_web: + dependency: transitive + description: + name: cloud_firestore_web + sha256: fd60d31f4eb104295256edc2e0bee631dc2b3283c5087701c513bfa9f27b711a + url: "https://pub.dev" + source: hosted + version: "3.8.9" + collapsible_sidebar: + dependency: "direct main" + description: + name: collapsible_sidebar + sha256: cdaa339abbd14ded6c23ce7b4577767e444029be487659bfe97f4a88d8cb47d7 + url: "https://pub.dev" + source: hosted + version: "2.0.7" + collection: + dependency: transitive + description: + name: collection + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" + source: hosted + version: "1.17.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "2f9d2cbccb76127ba28528cb3ae2c2326a122446a83de5a056aaa3880d3882c5" + url: "https://pub.dev" + source: hosted + version: "0.3.3+7" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + url: "https://pub.dev" + source: hosted + version: "1.0.6" + date_time_picker: + dependency: "direct main" + description: + name: date_time_picker + sha256: "6923c568bcb67a66ab7e083708d0adbcae8214b41bb84d49febc17e89e06fc4a" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" + url: "https://pub.dev" + source: hosted + version: "0.9.2+1" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6 + url: "https://pub.dev" + source: hosted + version: "0.9.3+3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: "0aa47a725c346825a2bd396343ce63ac00bda6eff2fbc43eabe99737dede8262" + url: "https://pub.dev" + source: hosted + version: "2.6.1" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0 + url: "https://pub.dev" + source: hosted + version: "0.9.3+1" + firebase_analytics: + dependency: "direct main" + description: + name: firebase_analytics + sha256: "5e92d510eacd66c354718fd9cc8f66ffdfa025640b645c4742297fb973770508" + url: "https://pub.dev" + source: hosted + version: "10.7.4" + firebase_analytics_platform_interface: + dependency: transitive + description: + name: firebase_analytics_platform_interface + sha256: "72977325a72af5ebb8e53b5c5533cb2e33eec481cd46210cfe5427f5efba55d8" + url: "https://pub.dev" + source: hosted + version: "3.8.4" + firebase_analytics_web: + dependency: transitive + description: + name: firebase_analytics_web + sha256: "8b9710be7e292e2a5ad34fff449d4b668c5808fb339649e69181727a4534f579" + url: "https://pub.dev" + source: hosted + version: "0.5.5+11" + firebase_auth: + dependency: "direct main" + description: + name: firebase_auth + sha256: a87cfdd16b2bd04ca4a61e8b8d95daafaae487aa4c6533c9497199d631eefe6f + url: "https://pub.dev" + source: hosted + version: "4.15.2" + firebase_auth_platform_interface: + dependency: transitive + description: + name: firebase_auth_platform_interface + sha256: "4ca90755469fd20bf32070a3ff4dcb6256cfafc47230cc021261acced672ed3c" + url: "https://pub.dev" + source: hosted + version: "7.0.8" + firebase_auth_web: + dependency: transitive + description: + name: firebase_auth_web + sha256: "8eb2b4d35ed46405783c135cdf7c4c2d2769abe09cee60fcd8080c0475a9e8b5" + url: "https://pub.dev" + source: hosted + version: "5.8.11" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "96607c0e829a581c2a483c658f04e8b159964c3bae2730f73297070bc85d40bb" + url: "https://pub.dev" + source: hosted + version: "2.24.2" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: c437ae5d17e6b5cc7981cf6fd458a5db4d12979905f9aafd1fea930428a9fe63 + url: "https://pub.dev" + source: hosted + version: "5.0.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: d585bdf3c656c3f7821ba1bd44da5f13365d22fcecaf5eb75c4295246aaa83c0 + url: "https://pub.dev" + source: hosted + version: "2.10.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + url: "https://pub.dev" + source: hosted + version: "2.0.3" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + url: "https://pub.dev" + source: hosted + version: "2.0.17" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: e20ff62b158b96f392bfc8afe29dee1503c94fbea2cbe8186fd59b756b8ae982 + url: "https://pub.dev" + source: hosted + version: "5.1.0" + http: + dependency: transitive + description: + name: http + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: b6951e25b795d053a6ba03af5f710069c99349de9341af95155d52665cb4607c + url: "https://pub.dev" + source: hosted + version: "0.8.9" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: d6a6e78821086b0b737009b09363018309bbc6de3fd88cc5c26bc2bb44a4957f + url: "https://pub.dev" + source: hosted + version: "0.8.8+2" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "76ec722aeea419d03aa915c2c96bf5b47214b053899088c9abb4086ceecf97a7" + url: "https://pub.dev" + source: hosted + version: "0.8.8+4" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: ed9b00e63977c93b0d2d2b343685bed9c324534ba5abafbb3dfbd6a780b1b514 + url: "https://pub.dev" + source: hosted + version: "2.9.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + intl: + dependency: transitive + description: + name: intl + sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + url: "https://pub.dev" + source: hosted + version: "0.17.0" + js: + dependency: "direct main" + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + lints: + dependency: transitive + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + url: "https://pub.dev" + source: hosted + version: "0.12.15" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + url: "https://pub.dev" + source: hosted + version: "2.1.1" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + url: "https://pub.dev" + source: hosted + version: "2.3.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + platform: + dependency: transitive + description: + name: platform + sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" + url: "https://pub.dev" + source: hosted + version: "3.1.3" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 + url: "https://pub.dev" + source: hosted + version: "2.1.7" + provider: + dependency: "direct main" + description: + name: provider + sha256: "59471e0a4595e264625d3496af567ac85bdae1148ec985aff1e0555786f53ecf" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.dev" + source: hosted + version: "0.5.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + win32: + dependency: transitive + description: + name: win32 + sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3" + url: "https://pub.dev" + source: hosted + version: "5.0.9" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" + url: "https://pub.dev" + source: hosted + version: "1.0.3" +sdks: + dart: ">=3.0.5 <4.0.0" + flutter: ">=3.7.0" diff --git a/pubspec.yaml b/pubspec.yaml index eeab23c..925c2c7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,98 +1,101 @@ -name: retrieve_me -description: A new Flutter project. -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -# In Windows, build-name is used as the major, minor, and patch parts -# of the product and file versions while build-number is used as the build suffix. -version: 1.0.0+1 - -environment: - sdk: '>=3.0.5 <4.0.0' - -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - date_time_picker: ^2.1.0 - cupertino_icons: ^1.0.2 - firebase_core: ^2.15.0 - firebase_auth: ^4.7.2 - cloud_firestore: ^4.8.4 - firebase_analytics: ^10.4.4 - image_picker: ^0.8.4 - google_fonts: ^5.1.0 - -dev_dependencies: - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^2.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -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: - - lib/images/ - # - images/a_dot_burr.jpeg - # - 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 +name: retrieve_me +description: A new Flutter project. +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: '>=3.0.5 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + date_time_picker: ^2.1.0 + cupertino_icons: ^1.0.2 + firebase_core: ^2.15.0 + firebase_auth: ^4.7.2 + cloud_firestore: ^4.8.4 + firebase_analytics: ^10.4.4 + image_picker: ^0.8.4 + google_fonts: ^5.1.0 + js: ^0.6.2 + collapsible_sidebar: ^2.0.7 + provider: ^5.0.0 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +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: + - lib/images/ + # - images/a_dot_burr.jpeg + # - 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/test/widget_test.dart b/test/widget_test.dart index d2eb599..7f65500 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -1,30 +1,29 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:retrieve_me/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + // await tester.pumpWidget(const MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/web/index.html b/web/index.html index 8314b53..ff7f4d9 100644 --- a/web/index.html +++ b/web/index.html @@ -1,59 +1,59 @@ - - - - - - - - - - - - - - - - - - - - retrieve_me - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + retrieve_me + + + + + + + + + + diff --git a/web/manifest.json b/web/manifest.json index 76f8495..60afa7e 100644 --- a/web/manifest.json +++ b/web/manifest.json @@ -1,35 +1,35 @@ -{ - "name": "retrieve_me", - "short_name": "retrieve_me", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} +{ + "name": "retrieve_me", + "short_name": "retrieve_me", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/windows/.gitignore b/windows/.gitignore index d492d0d..ec4098a 100644 --- a/windows/.gitignore +++ b/windows/.gitignore @@ -1,17 +1,17 @@ -flutter/ephemeral/ - -# Visual Studio user-specific files. -*.suo -*.user -*.userosscache -*.sln.docstates - -# Visual Studio build-related files. -x64/ -x86/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index 55aa8ad..230b3cc 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -1,102 +1,102 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.14) -project(retrieve_me LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "retrieve_me") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Define build configuration option. -get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(IS_MULTICONFIG) - set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" - CACHE STRING "" FORCE) -else() - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") - endif() -endif() -# Define settings for the Profile build mode. -set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") -set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") - -# Use Unicode for all projects. -add_definitions(-DUNICODE -D_UNICODE) - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_17) - target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") - target_compile_options(${TARGET} PRIVATE /EHsc) - target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") - target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# Support files are copied into place next to the executable, so that it can -# run in place. This is done instead of making a separate bundle (as on Linux) -# so that building and running from within Visual Studio will work. -set(BUILD_BUNDLE_DIR "$") -# Make the "install" step default, as it's required to run. -set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -if(PLUGIN_BUNDLED_LIBRARIES) - install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - CONFIGURATIONS Profile;Release - COMPONENT Runtime) +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(retrieve_me LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "retrieve_me") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt index 930d207..3f71e17 100644 --- a/windows/flutter/CMakeLists.txt +++ b/windows/flutter/CMakeLists.txt @@ -1,104 +1,104 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.14) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. -set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") - -# === Flutter Library === -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "flutter_export.h" - "flutter_windows.h" - "flutter_messenger.h" - "flutter_plugin_registrar.h" - "flutter_texture_registrar.h" -) -list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") -add_dependencies(flutter flutter_assemble) - -# === Wrapper === -list(APPEND CPP_WRAPPER_SOURCES_CORE - "core_implementations.cc" - "standard_codec.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_PLUGIN - "plugin_registrar.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_APP - "flutter_engine.cc" - "flutter_view_controller.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") - -# Wrapper sources needed for a plugin. -add_library(flutter_wrapper_plugin STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} -) -apply_standard_settings(flutter_wrapper_plugin) -set_target_properties(flutter_wrapper_plugin PROPERTIES - POSITION_INDEPENDENT_CODE ON) -set_target_properties(flutter_wrapper_plugin PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) -target_include_directories(flutter_wrapper_plugin PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_plugin flutter_assemble) - -# Wrapper sources needed for the runner. -add_library(flutter_wrapper_app STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_APP} -) -apply_standard_settings(flutter_wrapper_app) -target_link_libraries(flutter_wrapper_app PUBLIC flutter) -target_include_directories(flutter_wrapper_app PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_app flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") -set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} - ${PHONY_OUTPUT} - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} -) +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 30fedc8..4a46c81 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,12 +6,18 @@ #include "generated_plugin_registrant.h" +#include #include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + CloudFirestorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("CloudFirestorePluginCApi")); FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); + FirebaseAuthPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi")); FirebaseCorePluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 9278389..e0beee3 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,7 +3,9 @@ # list(APPEND FLUTTER_PLUGIN_LIST + cloud_firestore file_selector_windows + firebase_auth firebase_core ) diff --git a/windows/runner/CMakeLists.txt b/windows/runner/CMakeLists.txt index 394917c..2041a04 100644 --- a/windows/runner/CMakeLists.txt +++ b/windows/runner/CMakeLists.txt @@ -1,40 +1,40 @@ -cmake_minimum_required(VERSION 3.14) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} WIN32 - "flutter_window.cpp" - "main.cpp" - "utils.cpp" - "win32_window.cpp" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" - "Runner.rc" - "runner.exe.manifest" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the build version. -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") - -# Disable Windows macros that collide with C++ standard library functions. -target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") - -# Add dependency libraries and include directories. Add any application-specific -# dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) -target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc index edfe272..2ae2acf 100644 --- a/windows/runner/Runner.rc +++ b/windows/runner/Runner.rc @@ -1,121 +1,121 @@ -// Microsoft Visual C++ generated resource script. -// -#pragma code_page(65001) -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_APP_ICON ICON "resources\\app_icon.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) -#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD -#else -#define VERSION_AS_NUMBER 1,0,0,0 -#endif - -#if defined(FLUTTER_VERSION) -#define VERSION_AS_STRING FLUTTER_VERSION -#else -#define VERSION_AS_STRING "1.0.0" -#endif - -VS_VERSION_INFO VERSIONINFO - FILEVERSION VERSION_AS_NUMBER - PRODUCTVERSION VERSION_AS_NUMBER - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904e4" - BEGIN - VALUE "CompanyName", "com.kais29" "\0" - VALUE "FileDescription", "retrieve_me" "\0" - VALUE "FileVersion", VERSION_AS_STRING "\0" - VALUE "InternalName", "retrieve_me" "\0" - VALUE "LegalCopyright", "Copyright (C) 2023 com.kais29. All rights reserved." "\0" - VALUE "OriginalFilename", "retrieve_me.exe" "\0" - VALUE "ProductName", "retrieve_me" "\0" - VALUE "ProductVersion", VERSION_AS_STRING "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1252 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.kais29" "\0" + VALUE "FileDescription", "retrieve_me" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "retrieve_me" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 com.kais29. All rights reserved." "\0" + VALUE "OriginalFilename", "retrieve_me.exe" "\0" + VALUE "ProductName", "retrieve_me" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp index b25e363..490813d 100644 --- a/windows/runner/flutter_window.cpp +++ b/windows/runner/flutter_window.cpp @@ -1,66 +1,66 @@ -#include "flutter_window.h" - -#include - -#include "flutter/generated_plugin_registrant.h" - -FlutterWindow::FlutterWindow(const flutter::DartProject& project) - : project_(project) {} - -FlutterWindow::~FlutterWindow() {} - -bool FlutterWindow::OnCreate() { - if (!Win32Window::OnCreate()) { - return false; - } - - RECT frame = GetClientArea(); - - // The size here must match the window dimensions to avoid unnecessary surface - // creation / destruction in the startup path. - flutter_controller_ = std::make_unique( - frame.right - frame.left, frame.bottom - frame.top, project_); - // Ensure that basic setup of the controller was successful. - if (!flutter_controller_->engine() || !flutter_controller_->view()) { - return false; - } - RegisterPlugins(flutter_controller_->engine()); - SetChildContent(flutter_controller_->view()->GetNativeWindow()); - - flutter_controller_->engine()->SetNextFrameCallback([&]() { - this->Show(); - }); - - return true; -} - -void FlutterWindow::OnDestroy() { - if (flutter_controller_) { - flutter_controller_ = nullptr; - } - - Win32Window::OnDestroy(); -} - -LRESULT -FlutterWindow::MessageHandler(HWND hwnd, UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - // Give Flutter, including plugins, an opportunity to handle window messages. - if (flutter_controller_) { - std::optional result = - flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, - lparam); - if (result) { - return *result; - } - } - - switch (message) { - case WM_FONTCHANGE: - flutter_controller_->engine()->ReloadSystemFonts(); - break; - } - - return Win32Window::MessageHandler(hwnd, message, wparam, lparam); -} +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/windows/runner/flutter_window.h b/windows/runner/flutter_window.h index 6da0652..28c2383 100644 --- a/windows/runner/flutter_window.h +++ b/windows/runner/flutter_window.h @@ -1,33 +1,33 @@ -#ifndef RUNNER_FLUTTER_WINDOW_H_ -#define RUNNER_FLUTTER_WINDOW_H_ - -#include -#include - -#include - -#include "win32_window.h" - -// A window that does nothing but host a Flutter view. -class FlutterWindow : public Win32Window { - public: - // Creates a new FlutterWindow hosting a Flutter view running |project|. - explicit FlutterWindow(const flutter::DartProject& project); - virtual ~FlutterWindow(); - - protected: - // Win32Window: - bool OnCreate() override; - void OnDestroy() override; - LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, - LPARAM const lparam) noexcept override; - - private: - // The project to run. - flutter::DartProject project_; - - // The Flutter instance hosted by this window. - std::unique_ptr flutter_controller_; -}; - -#endif // RUNNER_FLUTTER_WINDOW_H_ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp index cf19c7d..81c236b 100644 --- a/windows/runner/main.cpp +++ b/windows/runner/main.cpp @@ -1,43 +1,43 @@ -#include -#include -#include - -#include "flutter_window.h" -#include "utils.h" - -int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { - // Attach to console when present (e.g., 'flutter run') or create a - // new console when running with a debugger. - if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { - CreateAndAttachConsole(); - } - - // Initialize COM, so that it is available for use in the library and/or - // plugins. - ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - - flutter::DartProject project(L"data"); - - std::vector command_line_arguments = - GetCommandLineArguments(); - - project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); - - FlutterWindow window(project); - Win32Window::Point origin(10, 10); - Win32Window::Size size(1280, 720); - if (!window.Create(L"retrieve_me", origin, size)) { - return EXIT_FAILURE; - } - window.SetQuitOnClose(true); - - ::MSG msg; - while (::GetMessage(&msg, nullptr, 0, 0)) { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } - - ::CoUninitialize(); - return EXIT_SUCCESS; -} +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"retrieve_me", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/windows/runner/resource.h b/windows/runner/resource.h index 66a65d1..ddc7f3e 100644 --- a/windows/runner/resource.h +++ b/windows/runner/resource.h @@ -1,16 +1,16 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Runner.rc -// -#define IDI_APP_ICON 101 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/windows/runner/runner.exe.manifest b/windows/runner/runner.exe.manifest index a42ea76..157e871 100644 --- a/windows/runner/runner.exe.manifest +++ b/windows/runner/runner.exe.manifest @@ -1,20 +1,20 @@ - - - - - PerMonitorV2 - - - - - - - - - - - - - - - + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/windows/runner/utils.cpp b/windows/runner/utils.cpp index b2b0873..fc55c57 100644 --- a/windows/runner/utils.cpp +++ b/windows/runner/utils.cpp @@ -1,65 +1,65 @@ -#include "utils.h" - -#include -#include -#include -#include - -#include - -void CreateAndAttachConsole() { - if (::AllocConsole()) { - FILE *unused; - if (freopen_s(&unused, "CONOUT$", "w", stdout)) { - _dup2(_fileno(stdout), 1); - } - if (freopen_s(&unused, "CONOUT$", "w", stderr)) { - _dup2(_fileno(stdout), 2); - } - std::ios::sync_with_stdio(); - FlutterDesktopResyncOutputStreams(); - } -} - -std::vector GetCommandLineArguments() { - // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. - int argc; - wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - if (argv == nullptr) { - return std::vector(); - } - - std::vector command_line_arguments; - - // Skip the first argument as it's the binary name. - for (int i = 1; i < argc; i++) { - command_line_arguments.push_back(Utf8FromUtf16(argv[i])); - } - - ::LocalFree(argv); - - return command_line_arguments; -} - -std::string Utf8FromUtf16(const wchar_t* utf16_string) { - if (utf16_string == nullptr) { - return std::string(); - } - int target_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - -1, nullptr, 0, nullptr, nullptr) - -1; // remove the trailing null character - int input_length = (int)wcslen(utf16_string); - std::string utf8_string; - if (target_length <= 0 || target_length > utf8_string.max_size()) { - return utf8_string; - } - utf8_string.resize(target_length); - int converted_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - input_length, utf8_string.data(), target_length, nullptr, nullptr); - if (converted_length == 0) { - return std::string(); - } - return utf8_string; -} +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length <= 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/windows/runner/utils.h b/windows/runner/utils.h index 3879d54..3f0e05c 100644 --- a/windows/runner/utils.h +++ b/windows/runner/utils.h @@ -1,19 +1,19 @@ -#ifndef RUNNER_UTILS_H_ -#define RUNNER_UTILS_H_ - -#include -#include - -// Creates a console for the process, and redirects stdout and stderr to -// it for both the runner and the Flutter library. -void CreateAndAttachConsole(); - -// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string -// encoded in UTF-8. Returns an empty std::string on failure. -std::string Utf8FromUtf16(const wchar_t* utf16_string); - -// Gets the command line arguments passed in as a std::vector, -// encoded in UTF-8. Returns an empty std::vector on failure. -std::vector GetCommandLineArguments(); - -#endif // RUNNER_UTILS_H_ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp index 60608d0..b5ba2a0 100644 --- a/windows/runner/win32_window.cpp +++ b/windows/runner/win32_window.cpp @@ -1,288 +1,288 @@ -#include "win32_window.h" - -#include -#include - -#include "resource.h" - -namespace { - -/// Window attribute that enables dark mode window decorations. -/// -/// Redefined in case the developer's machine has a Windows SDK older than -/// version 10.0.22000.0. -/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute -#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE -#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 -#endif - -constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; - -/// Registry key for app theme preference. -/// -/// A value of 0 indicates apps should use dark mode. A non-zero or missing -/// value indicates apps should use light mode. -constexpr const wchar_t kGetPreferredBrightnessRegKey[] = - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; -constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; - -// The number of Win32Window objects that currently exist. -static int g_active_window_count = 0; - -using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); - -// Scale helper to convert logical scaler values to physical using passed in -// scale factor -int Scale(int source, double scale_factor) { - return static_cast(source * scale_factor); -} - -// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. -// This API is only needed for PerMonitor V1 awareness mode. -void EnableFullDpiSupportIfAvailable(HWND hwnd) { - HMODULE user32_module = LoadLibraryA("User32.dll"); - if (!user32_module) { - return; - } - auto enable_non_client_dpi_scaling = - reinterpret_cast( - GetProcAddress(user32_module, "EnableNonClientDpiScaling")); - if (enable_non_client_dpi_scaling != nullptr) { - enable_non_client_dpi_scaling(hwnd); - } - FreeLibrary(user32_module); -} - -} // namespace - -// Manages the Win32Window's window class registration. -class WindowClassRegistrar { - public: - ~WindowClassRegistrar() = default; - - // Returns the singleton registrar instance. - static WindowClassRegistrar* GetInstance() { - if (!instance_) { - instance_ = new WindowClassRegistrar(); - } - return instance_; - } - - // Returns the name of the window class, registering the class if it hasn't - // previously been registered. - const wchar_t* GetWindowClass(); - - // Unregisters the window class. Should only be called if there are no - // instances of the window. - void UnregisterWindowClass(); - - private: - WindowClassRegistrar() = default; - - static WindowClassRegistrar* instance_; - - bool class_registered_ = false; -}; - -WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; - -const wchar_t* WindowClassRegistrar::GetWindowClass() { - if (!class_registered_) { - WNDCLASS window_class{}; - window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); - window_class.lpszClassName = kWindowClassName; - window_class.style = CS_HREDRAW | CS_VREDRAW; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = GetModuleHandle(nullptr); - window_class.hIcon = - LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); - window_class.hbrBackground = 0; - window_class.lpszMenuName = nullptr; - window_class.lpfnWndProc = Win32Window::WndProc; - RegisterClass(&window_class); - class_registered_ = true; - } - return kWindowClassName; -} - -void WindowClassRegistrar::UnregisterWindowClass() { - UnregisterClass(kWindowClassName, nullptr); - class_registered_ = false; -} - -Win32Window::Win32Window() { - ++g_active_window_count; -} - -Win32Window::~Win32Window() { - --g_active_window_count; - Destroy(); -} - -bool Win32Window::Create(const std::wstring& title, - const Point& origin, - const Size& size) { - Destroy(); - - const wchar_t* window_class = - WindowClassRegistrar::GetInstance()->GetWindowClass(); - - const POINT target_point = {static_cast(origin.x), - static_cast(origin.y)}; - HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); - UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); - double scale_factor = dpi / 96.0; - - HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW, - Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), - Scale(size.width, scale_factor), Scale(size.height, scale_factor), - nullptr, nullptr, GetModuleHandle(nullptr), this); - - if (!window) { - return false; - } - - UpdateTheme(window); - - return OnCreate(); -} - -bool Win32Window::Show() { - return ShowWindow(window_handle_, SW_SHOWNORMAL); -} - -// static -LRESULT CALLBACK Win32Window::WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - if (message == WM_NCCREATE) { - auto window_struct = reinterpret_cast(lparam); - SetWindowLongPtr(window, GWLP_USERDATA, - reinterpret_cast(window_struct->lpCreateParams)); - - auto that = static_cast(window_struct->lpCreateParams); - EnableFullDpiSupportIfAvailable(window); - that->window_handle_ = window; - } else if (Win32Window* that = GetThisFromHandle(window)) { - return that->MessageHandler(window, message, wparam, lparam); - } - - return DefWindowProc(window, message, wparam, lparam); -} - -LRESULT -Win32Window::MessageHandler(HWND hwnd, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - switch (message) { - case WM_DESTROY: - window_handle_ = nullptr; - Destroy(); - if (quit_on_close_) { - PostQuitMessage(0); - } - return 0; - - case WM_DPICHANGED: { - auto newRectSize = reinterpret_cast(lparam); - LONG newWidth = newRectSize->right - newRectSize->left; - LONG newHeight = newRectSize->bottom - newRectSize->top; - - SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, - newHeight, SWP_NOZORDER | SWP_NOACTIVATE); - - return 0; - } - case WM_SIZE: { - RECT rect = GetClientArea(); - if (child_content_ != nullptr) { - // Size and position the child window. - MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, TRUE); - } - return 0; - } - - case WM_ACTIVATE: - if (child_content_ != nullptr) { - SetFocus(child_content_); - } - return 0; - - case WM_DWMCOLORIZATIONCOLORCHANGED: - UpdateTheme(hwnd); - return 0; - } - - return DefWindowProc(window_handle_, message, wparam, lparam); -} - -void Win32Window::Destroy() { - OnDestroy(); - - if (window_handle_) { - DestroyWindow(window_handle_); - window_handle_ = nullptr; - } - if (g_active_window_count == 0) { - WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); - } -} - -Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { - return reinterpret_cast( - GetWindowLongPtr(window, GWLP_USERDATA)); -} - -void Win32Window::SetChildContent(HWND content) { - child_content_ = content; - SetParent(content, window_handle_); - RECT frame = GetClientArea(); - - MoveWindow(content, frame.left, frame.top, frame.right - frame.left, - frame.bottom - frame.top, true); - - SetFocus(child_content_); -} - -RECT Win32Window::GetClientArea() { - RECT frame; - GetClientRect(window_handle_, &frame); - return frame; -} - -HWND Win32Window::GetHandle() { - return window_handle_; -} - -void Win32Window::SetQuitOnClose(bool quit_on_close) { - quit_on_close_ = quit_on_close; -} - -bool Win32Window::OnCreate() { - // No-op; provided for subclasses. - return true; -} - -void Win32Window::OnDestroy() { - // No-op; provided for subclasses. -} - -void Win32Window::UpdateTheme(HWND const window) { - DWORD light_mode; - DWORD light_mode_size = sizeof(light_mode); - LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, - kGetPreferredBrightnessRegValue, - RRF_RT_REG_DWORD, nullptr, &light_mode, - &light_mode_size); - - if (result == ERROR_SUCCESS) { - BOOL enable_dark_mode = light_mode == 0; - DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, - &enable_dark_mode, sizeof(enable_dark_mode)); - } -} +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/windows/runner/win32_window.h b/windows/runner/win32_window.h index e901dde..49b847f 100644 --- a/windows/runner/win32_window.h +++ b/windows/runner/win32_window.h @@ -1,102 +1,102 @@ -#ifndef RUNNER_WIN32_WINDOW_H_ -#define RUNNER_WIN32_WINDOW_H_ - -#include - -#include -#include -#include - -// A class abstraction for a high DPI-aware Win32 Window. Intended to be -// inherited from by classes that wish to specialize with custom -// rendering and input handling -class Win32Window { - public: - struct Point { - unsigned int x; - unsigned int y; - Point(unsigned int x, unsigned int y) : x(x), y(y) {} - }; - - struct Size { - unsigned int width; - unsigned int height; - Size(unsigned int width, unsigned int height) - : width(width), height(height) {} - }; - - Win32Window(); - virtual ~Win32Window(); - - // Creates a win32 window with |title| that is positioned and sized using - // |origin| and |size|. New windows are created on the default monitor. Window - // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size this function will scale the inputted width and height as - // as appropriate for the default monitor. The window is invisible until - // |Show| is called. Returns true if the window was created successfully. - bool Create(const std::wstring& title, const Point& origin, const Size& size); - - // Show the current window. Returns true if the window was successfully shown. - bool Show(); - - // Release OS resources associated with window. - void Destroy(); - - // Inserts |content| into the window tree. - void SetChildContent(HWND content); - - // Returns the backing Window handle to enable clients to set icon and other - // window properties. Returns nullptr if the window has been destroyed. - HWND GetHandle(); - - // If true, closing this window will quit the application. - void SetQuitOnClose(bool quit_on_close); - - // Return a RECT representing the bounds of the current client area. - RECT GetClientArea(); - - protected: - // Processes and route salient window messages for mouse handling, - // size change and DPI. Delegates handling of these to member overloads that - // inheriting classes can handle. - virtual LRESULT MessageHandler(HWND window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Called when CreateAndShow is called, allowing subclass window-related - // setup. Subclasses should return false if setup fails. - virtual bool OnCreate(); - - // Called when Destroy is called. - virtual void OnDestroy(); - - private: - friend class WindowClassRegistrar; - - // OS callback called by message pump. Handles the WM_NCCREATE message which - // is passed when the non-client area is being created and enables automatic - // non-client DPI scaling so that the non-client area automatically - // responds to changes in DPI. All other messages are handled by - // MessageHandler. - static LRESULT CALLBACK WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Retrieves a class instance pointer for |window| - static Win32Window* GetThisFromHandle(HWND const window) noexcept; - - // Update the window frame's theme to match the system theme. - static void UpdateTheme(HWND const window); - - bool quit_on_close_ = false; - - // window handle for top level window. - HWND window_handle_ = nullptr; - - // window handle for hosted content. - HWND child_content_ = nullptr; -}; - -#endif // RUNNER_WIN32_WINDOW_H_ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ From d0da2cc20ede448044f9b535c601a2634b4d4e6e Mon Sep 17 00:00:00 2001 From: ImranIF Date: Wed, 17 Jan 2024 19:49:18 +0600 Subject: [PATCH 02/19] Added more specifiers --- lib/Components/drawer_items.dart | 1 + lib/Components/navigation_drawer_widget.dart | 4 + lib/pages/lostItemList.dart | 109 +++++++++++++++++++ lib/pages/postLostItem.dart | 21 ++-- 4 files changed, 126 insertions(+), 9 deletions(-) create mode 100644 lib/pages/lostItemList.dart diff --git a/lib/Components/drawer_items.dart b/lib/Components/drawer_items.dart index 62cbf3e..913c211 100644 --- a/lib/Components/drawer_items.dart +++ b/lib/Components/drawer_items.dart @@ -4,6 +4,7 @@ import 'drawer_item.dart'; final itemsFirst = [ const DrawerItem(title: 'Post Lost Item', icon: Icons.phone_android_outlined), const DrawerItem(title: 'Post Found Item', icon: Icons.people), + const DrawerItem(title: 'Lost Item List', icon: Icons.list), const DrawerItem(title: 'Item Case History', icon: Icons.history) ]; diff --git a/lib/Components/navigation_drawer_widget.dart b/lib/Components/navigation_drawer_widget.dart index 6bd93a6..b39d9d0 100644 --- a/lib/Components/navigation_drawer_widget.dart +++ b/lib/Components/navigation_drawer_widget.dart @@ -3,6 +3,7 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; import 'package:retrieve_me/Components/drawer_item.dart'; import 'package:retrieve_me/Components/drawer_items.dart'; +import 'package:retrieve_me/pages/lostItemList.dart'; import 'package:retrieve_me/pages/postFoundItem.dart'; import 'package:retrieve_me/pages/postLostItem.dart'; @@ -162,6 +163,9 @@ class NavigationDrawerWidget extends StatelessWidget { case 'Post Found Item': navigateTo(const PostFoundItemPage()); break; + case 'Lost Item List': + navigateTo(const LostItemListPage()); + break; case 'Logout': navigateTo(LoginPage()); break; diff --git a/lib/pages/lostItemList.dart b/lib/pages/lostItemList.dart new file mode 100644 index 0000000..5c0bb74 --- /dev/null +++ b/lib/pages/lostItemList.dart @@ -0,0 +1,109 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:retrieve_me/Components/navigation_drawer_widget.dart'; +import 'package:retrieve_me/provider/navigation_provider.dart'; + +import '../firebase_options.dart'; + +GlobalKey _sKey = GlobalKey(); + +class LostItemListPage extends StatefulWidget { + const LostItemListPage({super.key}); + + @override + State createState() => _LostItemListPageState(); +} + +class _LostItemListPageState extends State { + int index = 0; + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (BuildContext context) => NavigationProvider(), + child: Scaffold( + drawer: const NavigationDrawerWidget(), + key: _sKey, + body: FutureBuilder( + future: Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ), + builder: (context, snapshot) { + return Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111) + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: StreamBuilder( + stream: FirebaseFirestore.instance + .collection('LostProduct') + .snapshots(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return ListView.builder( + itemCount: snapshot.data!.docs.length, + itemBuilder: (context, index) { + DocumentSnapshot ds = snapshot.data!.docs[index]; + return Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.white, + ), + child: ListTile( + title: Text( + ds['LostItem'], + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + subtitle: Column( + children: [ + Row( + children: [ + const Text('Category: '), + Text(ds['Category']), + ], + ), + Row( + children: [ + const Text('Time of Request: '), + Text(ds['DateTime'].toString()), + ], + ), + Row( + children: [ + const Text('Description: '), + Text(ds['Description']), + ], + ), + ], + ), + ), + ), + ); + }, + ); + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + }, + ), + ); + }, + ), + ), + ); + } +} diff --git a/lib/pages/postLostItem.dart b/lib/pages/postLostItem.dart index e9dd26c..c697cb4 100644 --- a/lib/pages/postLostItem.dart +++ b/lib/pages/postLostItem.dart @@ -32,6 +32,7 @@ class PostLostItemPage extends StatefulWidget { } class _PostLostItemPageState extends State { + List documentKey = []; XFile? selectedImage; TextEditingController whatWasLost = TextEditingController(); TextEditingController itemCategory = TextEditingController(); @@ -86,13 +87,20 @@ class _PostLostItemPageState extends State { 'UnionVillageLocation': unionVillageController.text, 'StreetHouseLocation': streetHouseController.text, }; - await collectionReference.add(lostItemData); + DocumentReference docId = await collectionReference.add(lostItemData); + documentKey.add(docId); + final lostItem = await collectionReference.doc(docId.id).get().then( + (value) => value.data() as Map, + ); + // print(lostItem['LostItem']); + // print(lostItem['Category']); showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Lost Item Posted!', textAlign: TextAlign.center), - content: const Text('You have successfully created your Lost Item post!'), + content: const Text( + 'You have successfully created your Lost Item post!'), actions: [ TextButton( onPressed: () => Navigator.pop(context), @@ -126,8 +134,8 @@ class _PostLostItemPageState extends State { context: context, builder: (context) => AlertDialog( title: const Text('Error'), - content: - const Text('Please fill all the required fields before submitting!'), + content: const Text( + 'Please fill all the required fields before submitting!'), actions: [ TextButton( onPressed: () => Navigator.pop(context), @@ -149,11 +157,6 @@ class _PostLostItemPageState extends State { child: Scaffold( drawer: const NavigationDrawerWidget(), key: _sKey, - // appBar: AppBar( - // title: const Text('Post Lost Item'), - // centerTitle: true, - // backgroundColor: Colors.indigo, - // ), body: FutureBuilder( future: Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, From 230c1698d6dc9f41bc5ef5c75e17c08c8af9c2dc Mon Sep 17 00:00:00 2001 From: ImranIF Date: Thu, 18 Jan 2024 00:25:14 +0600 Subject: [PATCH 03/19] Added lost item list and found item list --- lib/Components/drawer_items.dart | 3 +- lib/Components/navigation_drawer_widget.dart | 6 +- lib/main.dart | 1 + lib/pages/foundItemList.dart | 223 +++++++++++++++++ lib/pages/lostItemList.dart | 243 ++++++++++++++----- lib/pages/postLostItem.dart | 5 +- 6 files changed, 413 insertions(+), 68 deletions(-) create mode 100644 lib/pages/foundItemList.dart diff --git a/lib/Components/drawer_items.dart b/lib/Components/drawer_items.dart index 913c211..58139f5 100644 --- a/lib/Components/drawer_items.dart +++ b/lib/Components/drawer_items.dart @@ -5,12 +5,13 @@ final itemsFirst = [ const DrawerItem(title: 'Post Lost Item', icon: Icons.phone_android_outlined), const DrawerItem(title: 'Post Found Item', icon: Icons.people), const DrawerItem(title: 'Lost Item List', icon: Icons.list), + const DrawerItem(title: 'Found Item List', icon: Icons.list), const DrawerItem(title: 'Item Case History', icon: Icons.history) ]; final itemsSecond = [ const DrawerItem(title: 'Chat', icon: Icons.chat), - const DrawerItem(title: 'Settings', icon: Icons.settings), + const DrawerItem(title: 'User Dashboard', icon: Icons.settings), ]; final itemsThird = [ diff --git a/lib/Components/navigation_drawer_widget.dart b/lib/Components/navigation_drawer_widget.dart index b39d9d0..7f5b684 100644 --- a/lib/Components/navigation_drawer_widget.dart +++ b/lib/Components/navigation_drawer_widget.dart @@ -3,6 +3,7 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; import 'package:retrieve_me/Components/drawer_item.dart'; import 'package:retrieve_me/Components/drawer_items.dart'; +import 'package:retrieve_me/pages/foundItemList.dart'; import 'package:retrieve_me/pages/lostItemList.dart'; import 'package:retrieve_me/pages/postFoundItem.dart'; import 'package:retrieve_me/pages/postLostItem.dart'; @@ -116,7 +117,7 @@ class NavigationDrawerWidget extends StatelessWidget { shrinkWrap: true, primary: false, itemCount: items.length, - separatorBuilder: (context, index) => const SizedBox(height: 16), + separatorBuilder: (context, index) => const SizedBox(height: 10), itemBuilder: (context, index) { final item = items[index]; @@ -166,6 +167,9 @@ class NavigationDrawerWidget extends StatelessWidget { case 'Lost Item List': navigateTo(const LostItemListPage()); break; + case 'Found Item List': + navigateTo(const FoundItemListPage()); + break; case 'Logout': navigateTo(LoginPage()); break; diff --git a/lib/main.dart b/lib/main.dart index 835f56d..4f27eee 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,5 +11,6 @@ void main() { ), // home: const RegistrationPage(), home: LoginPage(), + debugShowCheckedModeBanner: false, )); } diff --git a/lib/pages/foundItemList.dart b/lib/pages/foundItemList.dart new file mode 100644 index 0000000..a391712 --- /dev/null +++ b/lib/pages/foundItemList.dart @@ -0,0 +1,223 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:retrieve_me/Components/navigation_drawer_widget.dart'; +import 'package:retrieve_me/provider/navigation_provider.dart'; +import 'package:intl/intl.dart'; + +import '../firebase_options.dart'; + +GlobalKey _sKey = GlobalKey(); + +class FoundItemListPage extends StatefulWidget { + const FoundItemListPage({super.key}); + + @override + State createState() => _FoundItemListPageState(); +} + +class _FoundItemListPageState extends State { + int index = 0; + Stream query = + FirebaseFirestore.instance.collection('FoundProduct').snapshots(); + TextEditingController _searchController = TextEditingController(); + String _searchText = ""; + + @override + void initState() { + super.initState(); + _searchController.addListener(() { + setState(() { + _searchText = _searchController.text; + if (_searchText == "") { + query = + FirebaseFirestore.instance.collection('FoundProduct').snapshots(); + } else { + query = FirebaseFirestore.instance + .collection('FoundProduct') + .where('FoundItem', isEqualTo: _searchText) + .snapshots(); + print('Query result is: $query'); + } + }); + }); + } + + @override + void dispose() { + _searchController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (BuildContext context) => NavigationProvider(), + child: Scaffold( + drawer: const NavigationDrawerWidget(), + key: _sKey, + body: FutureBuilder( + future: Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ), + builder: (context, snapshot) { + return Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111) + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: Column( + children: [ + viewSearchBar(), + queryFoundItems(), + ], + ), + ); + }, + ), + ), + ); + } + + Widget queryFoundItems() { + return Expanded( + child: StreamBuilder( + stream: query, + builder: (context, snapshot) { + if (snapshot.hasData) { + return ListView.builder( + itemCount: snapshot.data!.docs.length, + itemBuilder: (context, index) { + DocumentSnapshot ds = snapshot.data!.docs[index]; + return Padding( + padding: const EdgeInsets.all(12.0), + child: Container( + margin: const EdgeInsets.all(15.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: const Color.fromARGB(255, 137, 181, 201), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Column( + children: [ + Image.network( + 'https://placehold.co/600x400/000000/FFFFFF/png', + width: MediaQuery.of(context).size.width * 0.4, + height: + MediaQuery.of(context).size.height * 0.4, + ), + ], + ), + const SizedBox(width: 10), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Item Name', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18.0, + color: Color.fromARGB(255, 114, 53, 3), + ), + ), + Text( + ds['FoundItem'], + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12.0, + ), + ), + const Text( + 'Category', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18.0, + color: Color.fromARGB(255, 114, 53, 3), + ), + ), + Text( + ds['Category'], + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12.0, + ), + ), + const Text( + 'Date When Found', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18.0, + color: Color.fromARGB(255, 114, 53, 3), + ), + ), + Text( + DateFormat('dd MMM yyyy') + .format(ds['DateTime'].toDate()), + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12.0, + ), + ), + const Text( + 'Time When Found', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18.0, + color: Color.fromARGB(255, 114, 53, 3), + ), + ), + Text( + DateFormat('hh:mm a') + .format(ds['DateTime'].toDate()), + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12.0, + ), + ), + ]), + ], + )), + ); + }, + ); + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + }, + ), + ); + } + + Widget viewSearchBar() { + return Container( + margin: const EdgeInsets.only(top: 30, left: 15.0, right: 15.0), + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + backgroundBlendMode: BlendMode.darken, + border: Border.all(color: Colors.blueAccent), + borderRadius: BorderRadius.circular(10), + color: Colors.white, + ), + child: TextField( + controller: _searchController, + decoration: const InputDecoration( + labelText: 'Search Found Item', + prefixIcon: Icon(Icons.search), + ), + ), + ); + } +} diff --git a/lib/pages/lostItemList.dart b/lib/pages/lostItemList.dart index 5c0bb74..7956480 100644 --- a/lib/pages/lostItemList.dart +++ b/lib/pages/lostItemList.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:retrieve_me/Components/navigation_drawer_widget.dart'; import 'package:retrieve_me/provider/navigation_provider.dart'; +import 'package:intl/intl.dart'; import '../firebase_options.dart'; @@ -17,7 +18,37 @@ class LostItemListPage extends StatefulWidget { } class _LostItemListPageState extends State { + Stream query = + FirebaseFirestore.instance.collection('LostProduct').snapshots(); int index = 0; + TextEditingController _searchController = TextEditingController(); + String _searchText = ""; + + @override + void initState() { + super.initState(); + _searchController.addListener(() { + setState(() { + _searchText = _searchController.text; + if (_searchText == "") { + query = + FirebaseFirestore.instance.collection('LostProduct').snapshots(); + } else { + query = FirebaseFirestore.instance + .collection('LostProduct') + .where('LostItem', isEqualTo: _searchText) + .snapshots(); + print('Query result is: $query'); + } + }); + }); + } + + @override + void dispose() { + _searchController.dispose(); + super.dispose(); + } @override Widget build(BuildContext context) { @@ -32,76 +63,160 @@ class _LostItemListPageState extends State { ), builder: (context, snapshot) { return Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color.fromARGB(255, 45, 44, 46), - Color.fromARGB(255, 5, 63, 111) - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111) + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), ), - ), - child: StreamBuilder( - stream: FirebaseFirestore.instance - .collection('LostProduct') - .snapshots(), - builder: (context, snapshot) { - if (snapshot.hasData) { - return ListView.builder( - itemCount: snapshot.data!.docs.length, - itemBuilder: (context, index) { - DocumentSnapshot ds = snapshot.data!.docs[index]; - return Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.white, - ), - child: ListTile( - title: Text( - ds['LostItem'], - style: const TextStyle( - fontWeight: FontWeight.bold, - ), + child: Column( + children: [ + viewSearchBar(), + queryLostItems(), + ], + )); + }, + ), + ), + ); + } + + Widget queryLostItems() { + return Expanded( + child: StreamBuilder( + stream: query, + // FirebaseFirestore.instance.collection('LostProduct').snapshots(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return ListView.builder( + shrinkWrap: true, // Add shrinkWrap: true to ListView.builder + itemCount: snapshot.data!.docs.length, + itemBuilder: (context, index) { + DocumentSnapshot ds = snapshot.data!.docs[index]; + return Padding( + padding: const EdgeInsets.all(12.0), + child: Container( + margin: const EdgeInsets.all(15.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Color.fromARGB(255, 137, 181, 201), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Column( + children: [ + Image.network( + 'https://placehold.co/600x400/000000/FFFFFF/png', + width: MediaQuery.of(context).size.width * 0.4, + height: + MediaQuery.of(context).size.height * 0.4, ), - subtitle: Column( - children: [ - Row( - children: [ - const Text('Category: '), - Text(ds['Category']), - ], + ], + ), + const SizedBox(width: 10), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Item Name', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18.0, + color: Color.fromARGB(255, 114, 53, 3), ), - Row( - children: [ - const Text('Time of Request: '), - Text(ds['DateTime'].toString()), - ], + ), + Text( + ds['LostItem'], + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12.0, ), - Row( - children: [ - const Text('Description: '), - Text(ds['Description']), - ], + ), + const Text( + 'Category', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18.0, + color: Color.fromARGB(255, 114, 53, 3), ), - ], - ), - ), - ), - ); - }, - ); - } else { - return const Center( - child: CircularProgressIndicator(), - ); - } - }, - ), + ), + Text( + ds['Category'], + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12.0, + ), + ), + const Text( + 'Date of Request', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18.0, + color: Color.fromARGB(255, 114, 53, 3), + ), + ), + Text( + DateFormat('dd MMM yyyy') + .format(ds['DateTime'].toDate()), + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12.0, + ), + ), + const Text( + 'Time of Request', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18.0, + color: Color.fromARGB(255, 114, 53, 3), + ), + ), + Text( + DateFormat('hh:mm a') + .format(ds['DateTime'].toDate()), + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12.0, + ), + ), + ]), + ], + )), + ); + }, ); - }, + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + }, + ), + ); + } + + Widget viewSearchBar() { + return Container( + margin: const EdgeInsets.only(top: 30, left: 15.0, right: 15.0), + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + backgroundBlendMode: BlendMode.darken, + border: Border.all(color: Colors.blueAccent), + borderRadius: BorderRadius.circular(10), + color: Colors.white, + ), + child: TextField( + controller: _searchController, + decoration: const InputDecoration( + labelText: 'Search Lost Item', + prefixIcon: Icon(Icons.search), ), ), ); diff --git a/lib/pages/postLostItem.dart b/lib/pages/postLostItem.dart index c697cb4..eab0e98 100644 --- a/lib/pages/postLostItem.dart +++ b/lib/pages/postLostItem.dart @@ -86,14 +86,15 @@ class _PostLostItemPageState extends State { 'DivisionLocation': divisionController.text, 'UnionVillageLocation': unionVillageController.text, 'StreetHouseLocation': streetHouseController.text, + // 'isRetrieved': }; DocumentReference docId = await collectionReference.add(lostItemData); documentKey.add(docId); final lostItem = await collectionReference.doc(docId.id).get().then( (value) => value.data() as Map, ); - // print(lostItem['LostItem']); - // print(lostItem['Category']); + print(lostItem['LostItem']); + print(lostItem['Category']); showDialog( context: context, From c681c1310ae17b5dce569600fe52917b6ffb9530 Mon Sep 17 00:00:00 2001 From: ImranIF Date: Thu, 18 Jan 2024 00:48:41 +0600 Subject: [PATCH 04/19] added indicators for waiting state --- lib/pages/foundItemList.dart | 9 +- lib/pages/lostItemList.dart | 9 +- lib/pages/postFoundItem.dart | 486 +++++++++++++++++---------------- lib/pages/postLostItem.dart | 511 ++++++++++++++++++----------------- 4 files changed, 521 insertions(+), 494 deletions(-) diff --git a/lib/pages/foundItemList.dart b/lib/pages/foundItemList.dart index a391712..3eb2525 100644 --- a/lib/pages/foundItemList.dart +++ b/lib/pages/foundItemList.dart @@ -36,7 +36,7 @@ class _FoundItemListPageState extends State { } else { query = FirebaseFirestore.instance .collection('FoundProduct') - .where('FoundItem', isEqualTo: _searchText) + .where('FoundItem', isEqualTo: _searchText.trim()) .snapshots(); print('Query result is: $query'); } @@ -91,7 +91,11 @@ class _FoundItemListPageState extends State { child: StreamBuilder( stream: query, builder: (context, snapshot) { - if (snapshot.hasData) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center( + child: CircularProgressIndicator(), + ); + } else if (snapshot.hasData) { return ListView.builder( itemCount: snapshot.data!.docs.length, itemBuilder: (context, index) { @@ -212,6 +216,7 @@ class _FoundItemListPageState extends State { color: Colors.white, ), child: TextField( + style: TextStyle(color: Colors.amber[50]), controller: _searchController, decoration: const InputDecoration( labelText: 'Search Found Item', diff --git a/lib/pages/lostItemList.dart b/lib/pages/lostItemList.dart index 7956480..6ae17a3 100644 --- a/lib/pages/lostItemList.dart +++ b/lib/pages/lostItemList.dart @@ -36,7 +36,7 @@ class _LostItemListPageState extends State { } else { query = FirebaseFirestore.instance .collection('LostProduct') - .where('LostItem', isEqualTo: _searchText) + .where('LostItem', isEqualTo: _searchText.trim()) .snapshots(); print('Query result is: $query'); } @@ -91,7 +91,11 @@ class _LostItemListPageState extends State { stream: query, // FirebaseFirestore.instance.collection('LostProduct').snapshots(), builder: (context, snapshot) { - if (snapshot.hasData) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center( + child: CircularProgressIndicator(), + ); + } else if (snapshot.hasData) { return ListView.builder( shrinkWrap: true, // Add shrinkWrap: true to ListView.builder itemCount: snapshot.data!.docs.length, @@ -213,6 +217,7 @@ class _LostItemListPageState extends State { color: Colors.white, ), child: TextField( + style: TextStyle(color: Colors.amber[50]), controller: _searchController, decoration: const InputDecoration( labelText: 'Search Lost Item', diff --git a/lib/pages/postFoundItem.dart b/lib/pages/postFoundItem.dart index 52c40cc..4d1081d 100644 --- a/lib/pages/postFoundItem.dart +++ b/lib/pages/postFoundItem.dart @@ -79,9 +79,10 @@ class _PostFoundItemPageState extends State { showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Found Item Posted!', textAlign: TextAlign.center), - content: - const Text('You have successfully created your Found Item post!'), + title: + const Text('Found Item Posted!', textAlign: TextAlign.center), + content: const Text( + 'You have successfully created your Found Item post!'), actions: [ TextButton( onPressed: () => Navigator.pop(context), @@ -115,8 +116,8 @@ class _PostFoundItemPageState extends State { context: context, builder: (context) => AlertDialog( title: const Text('Error'), - content: - const Text('Please fill all the required fields before submitting!'), + content: const Text( + 'Please fill all the required fields before submitting!'), actions: [ TextButton( onPressed: () => Navigator.pop(context), @@ -140,259 +141,268 @@ class _PostFoundItemPageState extends State { options: DefaultFirebaseOptions.currentPlatform, ), builder: (context, snapshot) { - return Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color.fromARGB(255, 45, 44, 46), - Color.fromARGB(255, 5, 63, 111) - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center( + child: CircularProgressIndicator(), + ); + } else { + return Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111) + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), ), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.all(15.0), - child: SingleChildScrollView( - child: Column(children: [ - // Lost/Found radio button group - Container( - child: IconButton( - onPressed: () { - _sKey.currentState!.openDrawer(); - }, - icon: const Icon( - Icons.menu, - color: Colors.white, - size: 30, - )), - ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.8, - child: DrawerHeader( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () { - // Navigator.pop(context); - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: (context) => PostLostItemPage(), - // ), - // ); - }, - child: const Text( - ' Lost ', - style: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 1.2, + child: Center( + child: Padding( + padding: const EdgeInsets.all(15.0), + child: SingleChildScrollView( + child: Column(children: [ + // Lost/Found radio button group + Container( + child: IconButton( + onPressed: () { + _sKey.currentState!.openDrawer(); + }, + icon: const Icon( + Icons.menu, + color: Colors.white, + size: 30, + )), + ), + SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + child: DrawerHeader( + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: [ + GestureDetector( + onTap: () { + // Navigator.pop(context); + // Navigator.of(context).push( + // MaterialPageRoute( + // builder: (context) => PostLostItemPage(), + // ), + // ); + }, + child: const Text( + ' Lost ', + style: TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 1.2, + ), ), ), - ), - GestureDetector( - child: const Text( - ' Found ', - style: TextStyle( - color: Colors.grey, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 2, + GestureDetector( + child: const Text( + ' Found ', + style: TextStyle( + color: Colors.grey, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 2, + ), ), - ), - ) - ], + ) + ], + ), ), ), - ), - const SizedBox(height: 16), - SizedBox( - width: MediaQuery.of(context).size.width * 0.75, - height: MediaQuery.of(context).size.height * 0.075, - child: TextButton( - onPressed: _insertImage, - style: TextButton.styleFrom( - backgroundColor: Colors.cyan, - shadowColor: Colors.green, + const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + height: MediaQuery.of(context).size.height * 0.075, + child: TextButton( + onPressed: _insertImage, + style: TextButton.styleFrom( + backgroundColor: Colors.cyan, + shadowColor: Colors.green, + ), + child: const Text('Insert Found Product Image', + style: TextStyle( + color: Colors.brown, + fontWeight: FontWeight.bold, + )), ), - child: const Text('Insert Found Product Image', - style: TextStyle( - color: Colors.brown, - fontWeight: FontWeight.bold, - )), ), - ), - const SizedBox(height: 16), - SizedBox( - width: MediaQuery.of(context).size.width * 0.75, - child: Align( - alignment: Alignment.center, - child: DateTimePicker( - // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, - type: DateTimePickerType.dateTimeSeparate, - dateMask: 'd MMM, yyyy', - initialValue: DateTime.now().toString(), - firstDate: DateTime(2000), - lastDate: DateTime(2099), - icon: const Icon(Icons.date_range_sharp), - dateLabelText: 'Date', - style: const TextStyle( - color: Colors.deepOrangeAccent, - fontWeight: FontWeight.bold, - ), - timeLabelText: "Hour", - selectableDayPredicate: (date) { - return true; - }, - onChanged: (value) => { - dateTimeController = DateTime.parse(value), - // dateTimeController = value as DateTimePicker, - }, - decoration: const InputDecoration( - border: OutlineInputBorder( - borderSide: BorderSide( - color: Color.fromARGB( - 255, 156, 178, 197), // Border color - ), - borderRadius: BorderRadius.all( - Radius.circular(15.0), // Border radius + const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + child: Align( + alignment: Alignment.center, + child: DateTimePicker( + // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, + type: DateTimePickerType.dateTimeSeparate, + dateMask: 'd MMM, yyyy', + initialValue: DateTime.now().toString(), + firstDate: DateTime(2000), + lastDate: DateTime(2099), + icon: const Icon(Icons.date_range_sharp), + dateLabelText: 'Date', + style: const TextStyle( + color: Colors.deepOrangeAccent, + fontWeight: FontWeight.bold, + ), + timeLabelText: "Hour", + selectableDayPredicate: (date) { + return true; + }, + onChanged: (value) => { + dateTimeController = DateTime.parse(value), + // dateTimeController = value as DateTimePicker, + }, + decoration: const InputDecoration( + border: OutlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB( + 255, 156, 178, 197), // Border color + ), + borderRadius: BorderRadius.all( + Radius.circular(15.0), // Border radius + ), ), ), ), - ), - )), + )), - const SizedBox(height: 16), - MyTextField( - controller: whatWasFound, - hintText: '', - obscureText: false, - prefixIcon: Icons.cases, - labelText: 'What was Found', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - MyTextField( - controller: itemCategory, - hintText: 'Mobile', - obscureText: false, - prefixIcon: Icons.miscellaneous_services, - labelText: 'Item Category', - keyboardType: TextInputType.emailAddress, - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: divisionController, - hintText: 'Chittagong', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Division', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[a-zA-Z. ]')) - ], - ), - ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: cityController, - hintText: 'Hathazari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'City', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[a-zA-Z. ]')) - ], - ), - ) - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: streetHouseController, - hintText: 'Road no: 3, House no: 7', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Street/House No.', - keyboardType: TextInputType.streetAddress, + const SizedBox(height: 16), + MyTextField( + controller: whatWasFound, + hintText: '', + obscureText: false, + prefixIcon: Icons.cases, + labelText: 'What was Found', + keyboardType: TextInputType.text, + ), + const SizedBox(height: 16), + MyTextField( + controller: itemCategory, + hintText: 'Mobile', + obscureText: false, + prefixIcon: Icons.miscellaneous_services, + labelText: 'Item Category', + keyboardType: TextInputType.emailAddress, + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + // City + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: divisionController, + hintText: 'Chittagong', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Division', + keyboardType: TextInputType.streetAddress, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[a-zA-Z. ]')) + ], + ), ), - ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: unionVillageController, - hintText: 'Fatikchhari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Union/Village', - keyboardType: TextInputType.streetAddress, + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: cityController, + hintText: 'Hathazari', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'City', + keyboardType: TextInputType.streetAddress, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[a-zA-Z. ]')) + ], + ), + ) + ], + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + // City + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: streetHouseController, + hintText: 'Road no: 3, House no: 7', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Street/House No.', + keyboardType: TextInputType.streetAddress, + ), ), - ) - ], - ), - const SizedBox(height: 16), - MyTextField( - controller: additionalInfo, - hintText: 'Context and description of item', - obscureText: false, - prefixIcon: Icons.info_outlined, - labelText: 'Additional Info', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - BackButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.greenAccent, - )), - const SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(width: 16), - SizedBox( - height: MediaQuery.of(context).size.height * 0.05, - width: MediaQuery.of(context).size.width * 0.250, - child: ElevatedButton( - onPressed: submitFoundItem, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - // splashFactory: InkRipple.splashFactory, + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: unionVillageController, + hintText: 'Fatikchhari', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Union/Village', + keyboardType: TextInputType.streetAddress, ), - child: const Text( - 'Submit', - style: TextStyle( - color: Colors.deepPurple, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 0.90, + ) + ], + ), + const SizedBox(height: 16), + MyTextField( + controller: additionalInfo, + hintText: 'Context and description of item', + obscureText: false, + prefixIcon: Icons.info_outlined, + labelText: 'Additional Info', + keyboardType: TextInputType.text, + ), + const SizedBox(height: 16), + BackButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.greenAccent, + )), + const SizedBox(height: 32), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(width: 16), + SizedBox( + height: + MediaQuery.of(context).size.height * 0.05, + width: + MediaQuery.of(context).size.width * 0.250, + child: ElevatedButton( + onPressed: submitFoundItem, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Submit', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.90, + ), ), ), ), - ), - ], - ), - ]), + ], + ), + ]), + ), ), ), - ), - // }, - ); + // }, + ); + } }), ), ); diff --git a/lib/pages/postLostItem.dart b/lib/pages/postLostItem.dart index eab0e98..2a7ab6c 100644 --- a/lib/pages/postLostItem.dart +++ b/lib/pages/postLostItem.dart @@ -89,12 +89,12 @@ class _PostLostItemPageState extends State { // 'isRetrieved': }; DocumentReference docId = await collectionReference.add(lostItemData); - documentKey.add(docId); - final lostItem = await collectionReference.doc(docId.id).get().then( - (value) => value.data() as Map, - ); - print(lostItem['LostItem']); - print(lostItem['Category']); + // documentKey.add(docId); + // final lostItem = await collectionReference.doc(docId.id).get().then( + // (value) => value.data() as Map, + // ); + // print(lostItem['LostItem']); + // print(lostItem['Category']); showDialog( context: context, @@ -163,274 +163,281 @@ class _PostLostItemPageState extends State { options: DefaultFirebaseOptions.currentPlatform, ), builder: (context, snapshot) { - // Your widget tree here - return Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color.fromARGB(255, 45, 44, 46), - Color.fromARGB(255, 5, 63, 111) - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center( + child: CircularProgressIndicator(), + ); + } else { + // Your widget tree here + return Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111) + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), ), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.all(15.0), - child: SingleChildScrollView( - child: Column(children: [ - Container( - child: IconButton( - onPressed: () { - _sKey.currentState!.openDrawer(); - }, - icon: const Icon( - Icons.menu, - color: Colors.white, - size: 30, - )), - ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.8, - child: DrawerHeader( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - child: Text( - ' Lost ', - textScaleFactor: - ScaleSize.textScaleFactor(context), - style: const TextStyle( - color: Colors.grey, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 2, + child: Center( + child: Padding( + padding: const EdgeInsets.all(15.0), + child: SingleChildScrollView( + child: Column(children: [ + Container( + child: IconButton( + onPressed: () { + _sKey.currentState!.openDrawer(); + }, + icon: const Icon( + Icons.menu, + color: Colors.white, + size: 30, + )), + ), + SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + child: DrawerHeader( + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: [ + GestureDetector( + child: Text( + ' Lost ', + textScaleFactor: + ScaleSize.textScaleFactor(context), + style: const TextStyle( + color: Colors.grey, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 2, + ), ), ), - ), - GestureDetector( - onTap: () { - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: (context) => - // PostFoundItemPage(), - // ), - // ); - // Navigator.pop(context); - }, - child: Text( - ' Found ', - textScaleFactor: - ScaleSize.textScaleFactor(context), - style: const TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 1, + GestureDetector( + onTap: () { + // Navigator.of(context).push( + // MaterialPageRoute( + // builder: (context) => + // PostFoundItemPage(), + // ), + // ); + // Navigator.pop(context); + }, + child: Text( + ' Found ', + textScaleFactor: + ScaleSize.textScaleFactor(context), + style: const TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 1, + ), ), - ), - ) - ], - ), - )), - // Lost/Found radio button group + ) + ], + ), + )), + // Lost/Found radio button group - const SizedBox(height: 16), - SizedBox( - width: MediaQuery.of(context).size.width * 0.75, - height: MediaQuery.of(context).size.height * 0.075, - child: TextButton( - onPressed: _insertImage, - style: TextButton.styleFrom( - backgroundColor: Colors.cyan, - shadowColor: Colors.green, + const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + height: MediaQuery.of(context).size.height * 0.075, + child: TextButton( + onPressed: _insertImage, + style: TextButton.styleFrom( + backgroundColor: Colors.cyan, + shadowColor: Colors.green, + ), + child: const Text('Insert Lost Product Image', + style: TextStyle( + color: Colors.brown, + fontWeight: FontWeight.bold, + )), ), - child: const Text('Insert Lost Product Image', - style: TextStyle( - color: Colors.brown, - fontWeight: FontWeight.bold, - )), ), - ), - const SizedBox(height: 16), - SizedBox( - width: MediaQuery.of(context).size.width * 0.75, - child: Align( - alignment: Alignment.center, - child: DateTimePicker( - // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, - type: DateTimePickerType - .dateTimeSeparate, // Adjust the type based on your requirements - dateMask: 'd MMM, yyyy', - initialValue: DateTime.now().toString(), - firstDate: DateTime( - 2000), // Adjust the firstDate based on your requirements - lastDate: DateTime(2099), - icon: const Icon(Icons.date_range_sharp), - dateLabelText: 'Date', - style: const TextStyle( - color: Colors.deepOrangeAccent, - fontWeight: FontWeight.bold, - ), - timeLabelText: "Hour", - selectableDayPredicate: (date) { - return true; - }, - onChanged: (value) => { - dateTimeController = DateTime.parse(value), - // dateTimeController = value as DateTimePicker, - }, - decoration: const InputDecoration( - border: OutlineInputBorder( - borderSide: BorderSide( - color: Color.fromARGB( - 255, 156, 178, 197), // Border color - ), - borderRadius: BorderRadius.all( - Radius.circular(15.0), // Border radius + const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + child: Align( + alignment: Alignment.center, + child: DateTimePicker( + // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, + type: DateTimePickerType + .dateTimeSeparate, // Adjust the type based on your requirements + dateMask: 'd MMM, yyyy', + initialValue: DateTime.now().toString(), + firstDate: DateTime( + 2000), // Adjust the firstDate based on your requirements + lastDate: DateTime(2099), + icon: const Icon(Icons.date_range_sharp), + dateLabelText: 'Date', + style: const TextStyle( + color: Colors.deepOrangeAccent, + fontWeight: FontWeight.bold, + ), + timeLabelText: "Hour", + selectableDayPredicate: (date) { + return true; + }, + onChanged: (value) => { + dateTimeController = DateTime.parse(value), + // dateTimeController = value as DateTimePicker, + }, + decoration: const InputDecoration( + border: OutlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB( + 255, 156, 178, 197), // Border color + ), + borderRadius: BorderRadius.all( + Radius.circular(15.0), // Border radius + ), ), ), ), ), ), - ), - const SizedBox(height: 16), - MyTextField( - controller: whatWasLost, - hintText: 'Walton Primo RX7', - obscureText: false, - prefixIcon: Icons.cases, - labelText: 'What was Lost', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - MyTextField( - controller: itemCategory, - hintText: 'Mobile', - obscureText: false, - prefixIcon: Icons.miscellaneous_services, - labelText: 'Item Category', - keyboardType: TextInputType.emailAddress, - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: divisionController, - hintText: 'Chittagong', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Division', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[a-zA-Z. ]')) - ], - ), - ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: cityController, - hintText: 'Hathazari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'City', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[a-zA-Z. ]')) - ], - ), - ) - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: streetHouseController, - hintText: 'Road no: 3, House no: 7', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Street/House No.', - keyboardType: TextInputType.streetAddress, + const SizedBox(height: 16), + MyTextField( + controller: whatWasLost, + hintText: 'Walton Primo RX7', + obscureText: false, + prefixIcon: Icons.cases, + labelText: 'What was Lost', + keyboardType: TextInputType.text, + ), + const SizedBox(height: 16), + MyTextField( + controller: itemCategory, + hintText: 'Mobile', + obscureText: false, + prefixIcon: Icons.miscellaneous_services, + labelText: 'Item Category', + keyboardType: TextInputType.emailAddress, + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + // City + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: divisionController, + hintText: 'Chittagong', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Division', + keyboardType: TextInputType.streetAddress, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[a-zA-Z. ]')) + ], + ), ), - ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: unionVillageController, - hintText: 'Fatikchhari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Union/Village', - keyboardType: TextInputType.streetAddress, + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: cityController, + hintText: 'Hathazari', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'City', + keyboardType: TextInputType.streetAddress, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[a-zA-Z. ]')) + ], + ), + ) + ], + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + // City + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: streetHouseController, + hintText: 'Road no: 3, House no: 7', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Street/House No.', + keyboardType: TextInputType.streetAddress, + ), ), - ) - ], - ), - const SizedBox(height: 16), - MyTextField( - controller: additionalInfo, - hintText: 'Context and description of item', - obscureText: false, - prefixIcon: Icons.info_outlined, - labelText: 'Additional Info', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: unionVillageController, + hintText: 'Fatikchhari', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Union/Village', + keyboardType: TextInputType.streetAddress, + ), + ) + ], + ), + const SizedBox(height: 16), + MyTextField( + controller: additionalInfo, + hintText: 'Context and description of item', + obscureText: false, + prefixIcon: Icons.info_outlined, + labelText: 'Additional Info', + keyboardType: TextInputType.text, + ), + const SizedBox(height: 16), - BackButton( - onPressed: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => LoginPage(), + BackButton( + onPressed: () => Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => LoginPage(), + ), ), - ), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.greenAccent, - )), - const SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(width: 16), - SizedBox( - height: MediaQuery.of(context).size.height * 0.05, - width: MediaQuery.of(context).size.width * 0.250, - child: ElevatedButton( - onPressed: submitLostItem, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - // splashFactory: InkRipple.splashFactory, - ), - child: const Text( - 'Submit', - style: TextStyle( - color: Colors.deepPurple, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 0.90, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.greenAccent, + )), + const SizedBox(height: 32), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(width: 16), + SizedBox( + height: MediaQuery.of(context).size.height * 0.05, + width: MediaQuery.of(context).size.width * 0.250, + child: ElevatedButton( + onPressed: submitLostItem, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Submit', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.90, + ), ), ), ), - ), - ], - ), - ]), + ], + ), + ]), + ), ), ), - ), - // }, - ); + // }, + ); + } }, ), ), From a02a2b67b8da74781c33d646b7428f7a93b89323 Mon Sep 17 00:00:00 2001 From: Md-Kais Date: Fri, 19 Jan 2024 15:58:20 +0600 Subject: [PATCH 05/19] registration successful. --- lib/Components/my_button.dart | 12 +- lib/auth/auth_services.dart | 25 ++ lib/db/db_helper.dart | 34 ++ lib/main.dart | 41 +- lib/model/UserModel.dart | 59 +++ lib/pages/login.dart | 381 ++++++++++-------- lib/pages/registration.dart | 168 +++++--- lib/provider/user_provider.dart | 41 ++ macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 176 +++++--- pubspec.yaml | 2 + .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 13 files changed, 649 insertions(+), 296 deletions(-) create mode 100644 lib/auth/auth_services.dart create mode 100644 lib/db/db_helper.dart create mode 100644 lib/model/UserModel.dart create mode 100644 lib/provider/user_provider.dart diff --git a/lib/Components/my_button.dart b/lib/Components/my_button.dart index aa46672..e45ce9f 100644 --- a/lib/Components/my_button.dart +++ b/lib/Components/my_button.dart @@ -2,8 +2,14 @@ import 'package:flutter/material.dart'; class MyButton extends StatelessWidget { final Function()? onTap; + final String childText; + final Key? key; - const MyButton({super.key, required this.onTap}); + const MyButton({ + this.key, + required this.onTap, + required this.childText, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -16,9 +22,9 @@ class MyButton extends StatelessWidget { color: Colors.blueAccent, borderRadius: BorderRadius.circular(8), ), - child: const Center( + child: Center( child: Text( - "Sign In", + childText, style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, diff --git a/lib/auth/auth_services.dart b/lib/auth/auth_services.dart new file mode 100644 index 0000000..c5f92fc --- /dev/null +++ b/lib/auth/auth_services.dart @@ -0,0 +1,25 @@ + +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:retrieve_me/db/db_helper.dart'; + +class AuthService{ + static final FirebaseAuth _auth = FirebaseAuth.instance; + static User ? get currentUser => _auth.currentUser; + static Future loginAdmin(String email,String password) async{ + final credintial = await _auth.signInWithEmailAndPassword(email: email, password: password); + + return credintial.user!; + } + + + + + static Future registerUser(String email, String password, String contactNumber) async { + final credential = await _auth.createUserWithEmailAndPassword(email: email, password: password); + return credential.user!; + } + + static Future logout(){ + return _auth.signOut(); + } +} \ No newline at end of file diff --git a/lib/db/db_helper.dart b/lib/db/db_helper.dart new file mode 100644 index 0000000..a68e732 --- /dev/null +++ b/lib/db/db_helper.dart @@ -0,0 +1,34 @@ +import 'dart:core'; + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_storage/firebase_storage.dart'; + +import '../model/UserModel.dart'; + +class db_helper { + static final FirebaseFirestore _db = FirebaseFirestore.instance; + static final String adminCollection = 'Admins'; + + // static fiinal String collectionUser = 'Users'; + static Future isAdmin(String uid) async { + final snapshot = await _db.collection(adminCollection).doc(uid).get(); + return snapshot.exists; + } + + static Future addUser(UserModel userModel) { + print(userModel.email); + return _db + .collection(collectionUser).add(userModel.toMap()); + } + + static Future doesUserExist(String uid) async { + final snapshot = await _db.collection(collectionUser).doc(uid).get(); + return snapshot.exists; + } + + static Stream>> getUserInfo( + String uid) { + return _db.collection(collectionUser).doc(uid).snapshots(); + } +} diff --git a/lib/main.dart b/lib/main.dart index 835f56d..009be91 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,15 +1,36 @@ +import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:provider/provider.dart'; import 'package:retrieve_me/pages/login.dart'; +import 'package:retrieve_me/provider/user_provider.dart'; -void main() { +Future main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(MaterialApp( - title: 'Retrieve-Me', - theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo), - useMaterial3: true, - ), - // home: const RegistrationPage(), - home: LoginPage(), - )); + await Firebase.initializeApp(); + runApp(MultiProvider( + providers: [ + + ChangeNotifierProvider(create: (context) => UserProvider(),), + ], + child: const MyApp())); +} +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + builder: EasyLoading.init(), + debugShowCheckedModeBanner: false, + title: 'Retrieve-Me', + theme: ThemeData( + colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo), + useMaterial3: true, + ), + // home: const RegistrationPage(), + home: LoginPage(), + ); + + } } diff --git a/lib/model/UserModel.dart b/lib/model/UserModel.dart new file mode 100644 index 0000000..bad3f66 --- /dev/null +++ b/lib/model/UserModel.dart @@ -0,0 +1,59 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; + +// import 'address_model.dart'; +const String collectionUser='Users'; + +const String userFieldId='userId'; +const String userFieldFirstName='firstName'; +const String userFieldAddress = 'address'; +const String userFieldCreationTime='CreationTime'; +const String userFieldRating='rating'; +const String userFieldProfession='profession'; +const String userFieldContact ='contactNo'; +const String userFieldEmail='email'; + +class UserModel{ + String userId; + String firstName; + String address; + Timestamp? userCreationTime; + String? rating; + String profession; + String contactNo; + String email; + + UserModel({ + required this.userId, + required this.firstName, + required this.address, + this.userCreationTime, + this.rating, + required this.profession, + required this.contactNo, + required this.email + }); + + + MaptoMap(){ + return { + userFieldId:userId, + userFieldFirstName:firstName, + userFieldAddress:address, + userFieldCreationTime:userCreationTime, + userFieldRating: rating, + userFieldProfession: profession, + userFieldContact: contactNo, + userFieldEmail:email, + }; + } + factory UserModel.fromMap(Mapmap)=>UserModel( + userId: map[userFieldId], + firstName: map[userFieldFirstName], + address: map[userFieldAddress] , + userCreationTime: map[userFieldCreationTime], + rating: map[userFieldRating], + profession: map[userFieldProfession], + contactNo: map[userFieldContact], + email: map[userFieldEmail], + ); +} \ No newline at end of file diff --git a/lib/pages/login.dart b/lib/pages/login.dart index d09ffd8..fa68f53 100644 --- a/lib/pages/login.dart +++ b/lib/pages/login.dart @@ -1,7 +1,9 @@ // import 'dart:js'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; import 'package:retrieve_me/Components/my_button.dart'; @@ -12,10 +14,23 @@ import 'package:retrieve_me/pages/postLostItem.dart'; import 'package:retrieve_me/pages/registration.dart'; import 'package:retrieve_me/provider/navigation_provider.dart'; -class LoginPage extends StatelessWidget { +import '../auth/auth_services.dart'; + +class LoginPage extends StatefulWidget { + static const String routeName = '/login'; + const LoginPage({Key? key}) : super(key: key); + @override + State createState() => _LoginPageState(); +} + +class _LoginPageState extends State { // text editing controllers - TextEditingController emailController = TextEditingController(); - TextEditingController passwordController = TextEditingController(); + final GlobalKey _formKey = GlobalKey(); + final TextEditingController emailController = TextEditingController(); + final TextEditingController passwordController = TextEditingController(); + + String _errMsg = ''; + // sign user in method Future signUserIn(BuildContext context) async { Navigator.of(context).push( @@ -28,191 +43,231 @@ class LoginPage extends StatelessWidget { @override Widget build(BuildContext context) { return ChangeNotifierProvider( - create: (context) => NavigationProvider(), - child: Scaffold( - body: FutureBuilder( - future: Firebase.initializeApp( - options: DefaultFirebaseOptions.currentPlatform, - ), - builder: (context, snapshot) { - return Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color.fromARGB(255, 45, 44, 46), - Color.fromARGB(255, 5, 63, 111) - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - ), + create: (context) => NavigationProvider(), + child: Scaffold( + body: Form( + key: _formKey, // Use key property for Form widget + child: FutureBuilder( + future: Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, ), - child: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: SingleChildScrollView( - child: Column( - children: [ - SizedBox( - width: MediaQuery.of(context).size.width * 0.8, - child: DrawerHeader( - child: Align( - alignment: Alignment.centerLeft, - child: Text( - 'LOG IN', - style: GoogleFonts.oswald( - textStyle: const TextStyle( - fontSize: 35, - color: Colors.white, - fontWeight: FontWeight.bold, + builder: (context, snapshot) { + return Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111) + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: SingleChildScrollView( + child: Column( + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + child: DrawerHeader( + child: Align( + alignment: Alignment.centerLeft, + child: Text( + 'LOG IN', + style: GoogleFonts.oswald( + textStyle: const TextStyle( + fontSize: 35, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), ), ), ), ), - ), - ), - const SizedBox(height: 50), // Removed 'const' - - // welcome back, you've been missed! - Text( - 'Welcome back you\'ve been missed!', - style: TextStyle( - color: Colors.grey[700], - fontSize: 16, - ), - ), + const SizedBox(height: 50), // Removed 'const' + + // welcome back, you've been missed! + Text( + 'Welcome back you\'ve been missed!', + style: TextStyle( + color: Colors.grey[700], + fontSize: 16, + ), + ), - const SizedBox(height: 25), // Removed 'const' + const SizedBox(height: 25), // Removed 'const' - // username textfield + // username textfield - const SizedBox(height: 16), - MyTextField( - controller: emailController, - hintText: 'johnKais@email.com', - obscureText: false, - prefixIcon: Icons.email, - labelText: 'Email', - keyboardType: TextInputType.emailAddress, - ), - const SizedBox(height: 16), - MyTextField( - controller: passwordController, - hintText: '', - obscureText: true, - prefixIcon: Icons.lock, - labelText: 'Password', - keyboardType: TextInputType.text, - ), + const SizedBox(height: 16), + MyTextField( + controller: emailController, + hintText: 'johnKais@email.com', + obscureText: false, + prefixIcon: Icons.email, + labelText: 'Email', + keyboardType: TextInputType.emailAddress, + ), + const SizedBox(height: 16), + MyTextField( + controller: passwordController, + hintText: '', + obscureText: true, + prefixIcon: Icons.lock, + labelText: 'Password', + keyboardType: TextInputType.text, + ), + + const SizedBox(height: 10), // Removed 'const' - const SizedBox(height: 10), // Removed 'const' - - // forgot password? - Padding( - padding: const EdgeInsets.symmetric(horizontal: 25.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - 'Forgot Password?', - style: TextStyle(color: Colors.grey[600]), + // forgot password? + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 25.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + 'Forgot Password?', + style: TextStyle(color: Colors.grey[600]), + ), + ], ), - ], - ), - ), + ), - const SizedBox(height: 25), + const SizedBox(height: 25), - // sign in button - MyButton(onTap: () { - signUserIn(context); - }), + // sign in button + ElevatedButton( + // Use UniqueKey to force the creation of a new instance + onPressed: () { + // Your onTap logic + print("done"); + _authenticate(); + }, + child: Text("Log In"), + ), - const SizedBox(height: 50), // Removed 'const' - // or continue with - Padding( - padding: const EdgeInsets.symmetric(horizontal: 25.0), - child: Row( - children: [ - Expanded( - child: Divider( - thickness: 0.5, - color: Colors.grey[400], - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 10.0), - child: Text( - 'Or continue with', - style: TextStyle(color: Colors.grey[700]), - ), - ), - Expanded( - child: Divider( - thickness: 0.5, - color: Colors.grey[400], - ), + const SizedBox(height: 50), // Removed 'const' + + // or continue with + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 25.0), + child: Row( + children: [ + Expanded( + child: Divider( + thickness: 0.5, + color: Colors.grey[400], + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10.0), + child: Text( + 'Or continue with', + style: TextStyle(color: Colors.grey[700]), + ), + ), + Expanded( + child: Divider( + thickness: 0.5, + color: Colors.grey[400], + ), + ), + ], ), - ], - ), - ), + ), - const SizedBox(height: 50), // Removed 'const' + const SizedBox(height: 50), // Removed 'const' - // google + apple sign in buttons - const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - // google button - SquareTile(imagePath: 'lib/images/google.png'), + // google + apple sign in buttons + const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // google button + SquareTile(imagePath: 'lib/images/google.png'), - SizedBox(width: 25), + SizedBox(width: 25), - // apple button - SquareTile(imagePath: 'lib/images/github.png') - ], - ), + // apple button + SquareTile(imagePath: 'lib/images/github.png') + ], + ), - const SizedBox(height: 50), // Removed 'const' + const SizedBox(height: 50), // Removed 'const' - // not a member? register now - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Not a member?', - style: TextStyle(color: Colors.grey[700]), - ), - const SizedBox(width: 4), - GestureDetector( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => - const RegistrationPage(), + // not a member? register now + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Not a member?', + style: TextStyle(color: Colors.grey[700]), + ), + const SizedBox(width: 4), + GestureDetector( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => + const RegistrationPage(), + ), + ); + }, + child: const Text( + 'Register now', + style: TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + ), ), - ); - }, - child: const Text( - 'Register now', - style: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, ), - ), - ), + ], + ) ], - ) - ], + ), + ), ), ), - ), - ), - ); - }, - ), - ), - ); + ); + }, + ), + ), + )); + } + + @override + void dispose() { + emailController.dispose(); + passwordController.dispose(); + super.dispose(); + } + + void _authenticate() async { + if (_formKey.currentState!.validate()) { + EasyLoading.show(status: 'Please wait', dismissOnTap: false); + final email = emailController.text; + final password = passwordController.text; + try { + final User user = await AuthService.loginAdmin(email, password); + EasyLoading.dismiss(); + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const PostLostItemPage(), + ), + ); + } on FirebaseAuthException catch (error) { + EasyLoading.dismiss(); + setState(() { + _errMsg = error.message!; + }); + } + } } } diff --git a/lib/pages/registration.dart b/lib/pages/registration.dart index 50df821..a10a4b6 100644 --- a/lib/pages/registration.dart +++ b/lib/pages/registration.dart @@ -1,17 +1,26 @@ // import 'dart:js_util'; +import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:provider/provider.dart'; import 'package:retrieve_me/Components/my_textfield.dart'; +import 'package:retrieve_me/auth/auth_services.dart'; +import 'package:retrieve_me/db/db_helper.dart'; import 'package:retrieve_me/pages/login.dart'; +import 'package:retrieve_me/pages/postLostItem.dart'; +import 'package:retrieve_me/provider/user_provider.dart'; import '../firebase_options.dart'; import 'package:image_picker/image_picker.dart'; import 'package:google_fonts/google_fonts.dart'; +import '../model/UserModel.dart'; + class RegistrationPage extends StatefulWidget { - const RegistrationPage({super.key}); + const RegistrationPage({Key? key}) : super(key: key); @override RegistrationPageState createState() => RegistrationPageState(); @@ -19,62 +28,15 @@ class RegistrationPage extends StatefulWidget { class RegistrationPageState extends State { // TextEditingController registrationController = TextEditingController(); - TextEditingController firstNameController = TextEditingController(); - TextEditingController lastNameController = TextEditingController(); - TextEditingController contactNumberController = TextEditingController(); - TextEditingController addressController = TextEditingController(); - TextEditingController emailController = TextEditingController(); - TextEditingController passwordController = TextEditingController(); + final TextEditingController firstNameController = TextEditingController(); + final TextEditingController lastNameController = TextEditingController(); + final TextEditingController contactNumberController = TextEditingController(); + final TextEditingController addressController = TextEditingController(); + final TextEditingController emailController = TextEditingController(); + final TextEditingController passwordController = TextEditingController(); XFile? selectedImage; - Future _submitRegistration() async { - if (_areAllFieldsFilled()) { - final firstName = firstNameController.text; - final lastName = lastNameController.text; - final contactNumber = contactNumberController.text; - final email = emailController.text; - final password = passwordController.text; - await FirebaseAuth.instance.createUserWithEmailAndPassword( - email: email, - password: password, - ); - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Registered Sucessfully!'), - content: const Text('You have created a new account now!'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Okay'), - ), - ], - ), - ); - //route to new page - // confirm registration and insert to database - // Navigator.push( - // context, - // MaterialPageRoute(builder: (context) => ConfirmedRegistration()), - // ); - } else { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Error'), - content: - const Text('Please fill all the required fields before submitting!'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Okay'), - ), - ], - ), - ); - } - } void _insertImage() async { final selector = ImagePicker(); @@ -93,8 +55,8 @@ class RegistrationPageState extends State { contactNumberController.text.isNotEmpty && addressController.text.isNotEmpty && emailController.text.isNotEmpty && - passwordController.text.isNotEmpty && - selectedImage != null; + passwordController.text.isNotEmpty; + // && selectedImage != null; } void _resetFields() { @@ -308,4 +270,98 @@ class RegistrationPageState extends State { }, )); } + void _submitRegistration() async { + if (_areAllFieldsFilled()) { + EasyLoading.show(status: 'File is uploading', dismissOnTap: false); + final firstName = firstNameController.text; + final lastName = lastNameController.text; + final contactNumber = contactNumberController.text; + final address = addressController.text; + final email = emailController.text; + final password = passwordController.text; + try { + User user; + + user = await AuthService.registerUser(email, password,contactNumber); + // String uid = user.uid; + // UserModel? userModel; + Future addUser(User user) async{ + try { + final userModel = UserModel( + userId: user.uid, + email: user.email!, + firstName : firstName, + userCreationTime: Timestamp.fromDate(DateTime.now()), + address: address, + profession: 'Student', + contactNo: contactNumber, + + ); + await db_helper.addUser(userModel); + + } + catch(error){ + print('Error adding user to Firestore: $error'); + // Handle error accordingly + } + } + addUser(user); + // + // await Provider.of( + // + // + // context, listen: false).addUser(user); + + EasyLoading.dismiss(); + Navigator.pushReplacement( + + + context, + MaterialPageRoute( + builder: (context) => const PostLostItemPage(), + )); + // await FirebaseAuth.instance.createUserWithEmailAndPassword( + } on FirebaseAuthException catch (error) {} + // email: email, + // password: password, + // ); + showDialog( + + + context: context, + builder: (context) => AlertDialog( + title: const Text('Registered Sucessfully!'), + content: const Text('You have created a new account now!'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Okay'), + ), + ], + ), + ); + //route to new page + // confirm registration and insert to database + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => ConfirmedRegistration()), + // ); + } else { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Error'), + content: const Text( + 'Please fill all the required fields before submitting!'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Okay'), + ), + ], + ), + ); + } + } + } diff --git a/lib/provider/user_provider.dart b/lib/provider/user_provider.dart new file mode 100644 index 0000000..59f0122 --- /dev/null +++ b/lib/provider/user_provider.dart @@ -0,0 +1,41 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:retrieve_me/db/db_helper.dart'; + +import '../auth/auth_services.dart'; +import '../model/UserModel.dart'; + +class UserProvider extends ChangeNotifier { + UserModel? userModel; + // Future addUser(User user) async{ + // try { + // final userModel = UserModel( + // userId: user.uid, + // email: user.email!, + // displayName: user.displayName!, + // userCreationTime: Timestamp.fromDate(DateTime.now()), + // address: user.!, + // profession: user.photoURL!, + // contactNo: '01912345667', + // + // ); + // await db_helper.addUser(userModel); + // } + // catch(error){ + // print('Error adding user to Firestore: $error'); + // // Handle error accordingly + // } + // } + + getUserInfo() { + db_helper.getUserInfo(AuthService.currentUser!.uid).listen((snapshot) { + if(snapshot.exists) { + userModel = UserModel.fromMap(snapshot.data()!); + notifyListeners(); + } + }); + } + + Future doesUserExist(String uid) => db_helper.doesUserExist(uid); +} \ No newline at end of file diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 466c67d..630d0f8 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -10,6 +10,7 @@ import file_selector_macos import firebase_analytics import firebase_auth import firebase_core +import firebase_storage import path_provider_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { @@ -18,5 +19,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAnalyticsPlugin")) FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 675ce6e..1f68857 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -45,26 +45,26 @@ packages: dependency: "direct main" description: name: cloud_firestore - sha256: "50e33a5cd62f7ed0e8290802a7e68e090d27738f65256977162c127303ad82ea" + sha256: "8bfbb5a2edbc6052452326d60de0113fea2bcbf081d34a3f8e45c8b38307b31c" url: "https://pub.dev" source: hosted - version: "4.13.5" + version: "4.14.0" cloud_firestore_platform_interface: dependency: transitive description: name: cloud_firestore_platform_interface - sha256: dedbd776c04429f85726e5cfb6f929d8405da241ceec32baa7d31b7d062dad53 + sha256: "73ff438fe46028f0e19f55da18b6ddc6906ab750562cd7d9ffab77ff8c0c4307" url: "https://pub.dev" source: hosted - version: "6.0.9" + version: "6.1.0" cloud_firestore_web: dependency: transitive description: name: cloud_firestore_web - sha256: fd60d31f4eb104295256edc2e0bee631dc2b3283c5087701c513bfa9f27b711a + sha256: "232e45e95970d3a6baab8f50f9c3a6e2838d145d9d91ec9a7392837c44296397" url: "https://pub.dev" source: hosted - version: "3.8.9" + version: "3.9.0" collapsible_sidebar: dependency: "direct main" description: @@ -77,18 +77,18 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.18.0" cross_file: dependency: transitive description: name: cross_file - sha256: "2f9d2cbccb76127ba28528cb3ae2c2326a122446a83de5a056aaa3880d3882c5" + sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e url: "https://pub.dev" source: hosted - version: "0.3.3+7" + version: "0.3.3+8" crypto: dependency: transitive description: @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: file_selector_platform_interface - sha256: "0aa47a725c346825a2bd396343ce63ac00bda6eff2fbc43eabe99737dede8262" + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b url: "https://pub.dev" source: hosted - version: "2.6.1" + version: "2.6.2" file_selector_windows: dependency: transitive description: @@ -165,50 +165,50 @@ packages: dependency: "direct main" description: name: firebase_analytics - sha256: "5e92d510eacd66c354718fd9cc8f66ffdfa025640b645c4742297fb973770508" + sha256: "0240076090d77045d757aecb090616066d23b343840d4c21074094d6fe40a184" url: "https://pub.dev" source: hosted - version: "10.7.4" + version: "10.8.0" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface - sha256: "72977325a72af5ebb8e53b5c5533cb2e33eec481cd46210cfe5427f5efba55d8" + sha256: "6d9baa077d16b47ef5f19d982c4fc475597991aa53b0c601216faa3e1cdab45f" url: "https://pub.dev" source: hosted - version: "3.8.4" + version: "3.9.0" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web - sha256: "8b9710be7e292e2a5ad34fff449d4b668c5808fb339649e69181727a4534f579" + sha256: "89a740249bce9d52a99db4e501be6087ca6749c73c47cff2b174802be10abd81" url: "https://pub.dev" source: hosted - version: "0.5.5+11" + version: "0.5.5+12" firebase_auth: dependency: "direct main" description: name: firebase_auth - sha256: a87cfdd16b2bd04ca4a61e8b8d95daafaae487aa4c6533c9497199d631eefe6f + sha256: "279b2773ff61afd9763202cb5582e2b995ee57419d826b9af6517302a59b672f" url: "https://pub.dev" source: hosted - version: "4.15.2" + version: "4.16.0" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface - sha256: "4ca90755469fd20bf32070a3ff4dcb6256cfafc47230cc021261acced672ed3c" + sha256: "3c9cfaccb7549492edf5b0c67c6dd1c6727c7830891aa6727f2fb225f0226626" url: "https://pub.dev" source: hosted - version: "7.0.8" + version: "7.0.9" firebase_auth_web: dependency: transitive description: name: firebase_auth_web - sha256: "8eb2b4d35ed46405783c135cdf7c4c2d2769abe09cee60fcd8080c0475a9e8b5" + sha256: c7b1379ccef7abf4b6816eede67a868c44142198e42350f51c01d8fc03f95a7d url: "https://pub.dev" source: hosted - version: "5.8.11" + version: "5.8.13" firebase_core: dependency: "direct main" description: @@ -233,11 +233,43 @@ packages: url: "https://pub.dev" source: hosted version: "2.10.0" + firebase_storage: + dependency: "direct main" + description: + name: firebase_storage + sha256: "75e6cb6bed65138b5bbd86bfd7cf9bc9a175fb0c31aacc400e9203df117ffbe6" + url: "https://pub.dev" + source: hosted + version: "11.6.0" + firebase_storage_platform_interface: + dependency: transitive + description: + name: firebase_storage_platform_interface + sha256: "545a3a8edf337850403bb0fa03c8074a53deb87c0107d19755c77a82ce07919e" + url: "https://pub.dev" + source: hosted + version: "5.1.3" + firebase_storage_web: + dependency: transitive + description: + name: firebase_storage_web + sha256: ee6870ff79aa304b8996ba18a4aefe1e8b3fc31fd385eab6574180267aa8d393 + url: "https://pub.dev" + source: hosted + version: "3.6.17" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_easyloading: + dependency: "direct main" + description: + name: flutter_easyloading + sha256: ba21a3c883544e582f9cc455a4a0907556714e1e9cf0eababfcb600da191d17c + url: "https://pub.dev" + source: hosted + version: "3.0.5" flutter_lints: dependency: "direct dev" description: @@ -254,6 +286,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.17" + flutter_spinkit: + dependency: transitive + description: + name: flutter_spinkit + sha256: b39c753e909d4796906c5696a14daf33639a76e017136c8d82bf3e620ce5bb8e + url: "https://pub.dev" + source: hosted + version: "5.2.0" flutter_test: dependency: "direct dev" description: flutter @@ -276,10 +316,10 @@ packages: dependency: transitive description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" http_parser: dependency: transitive description: @@ -300,10 +340,10 @@ packages: dependency: transitive description: name: image_picker_android - sha256: d6a6e78821086b0b737009b09363018309bbc6de3fd88cc5c26bc2bb44a4957f + sha256: "39f2bfe497e495450c81abcd44b62f56c2a36a37a175da7d137b4454977b51b1" url: "https://pub.dev" source: hosted - version: "0.8.8+2" + version: "0.8.9+3" image_picker_for_web: dependency: transitive description: @@ -316,10 +356,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: "76ec722aeea419d03aa915c2c96bf5b47214b053899088c9abb4086ceecf97a7" + sha256: fadafce49e8569257a0cad56d24438a6fa1f0cbd7ee0af9b631f7492818a4ca3 url: "https://pub.dev" source: hosted - version: "0.8.8+4" + version: "0.8.9+1" image_picker_linux: dependency: transitive description: @@ -340,10 +380,10 @@ packages: dependency: transitive description: name: image_picker_platform_interface - sha256: ed9b00e63977c93b0d2d2b343685bed9c324534ba5abafbb3dfbd6a780b1b514 + sha256: fa4e815e6fcada50e35718727d83ba1c92f1edf95c0b4436554cec301b56233b url: "https://pub.dev" source: hosted - version: "2.9.1" + version: "2.9.3" image_picker_windows: dependency: transitive description: @@ -380,26 +420,26 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" mime: dependency: transitive description: @@ -428,26 +468,26 @@ packages: dependency: transitive description: name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -460,10 +500,10 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: @@ -476,18 +516,18 @@ packages: dependency: transitive description: name: platform - sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.1.8" provider: dependency: "direct main" description: @@ -505,26 +545,26 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -545,10 +585,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.1" typed_data: dependency: transitive description: @@ -565,22 +605,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + url: "https://pub.dev" + source: hosted + version: "0.3.0" win32: dependency: transitive description: name: win32 - sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3" + sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" url: "https://pub.dev" source: hosted - version: "5.0.9" + version: "5.2.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" sdks: - dart: ">=3.0.5 <4.0.0" - flutter: ">=3.7.0" + dart: ">=3.2.0 <4.0.0" + flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 925c2c7..735ffdd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,6 +39,8 @@ dependencies: firebase_core: ^2.15.0 firebase_auth: ^4.7.2 cloud_firestore: ^4.8.4 + flutter_easyloading: + firebase_storage: firebase_analytics: ^10.4.4 image_picker: ^0.8.4 google_fonts: ^5.1.0 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 4a46c81..ec1e463 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -10,6 +10,7 @@ #include #include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { CloudFirestorePluginCApiRegisterWithRegistrar( @@ -20,4 +21,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi")); FirebaseCorePluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); + FirebaseStoragePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseStoragePluginCApi")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index e0beee3..767b528 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows firebase_auth firebase_core + firebase_storage ) list(APPEND FLUTTER_FFI_PLUGIN_LIST From 6259e77d22d91c30084c0f89e9240a6293c79590 Mon Sep 17 00:00:00 2001 From: ImranIF Date: Tue, 23 Jan 2024 17:16:23 +0600 Subject: [PATCH 06/19] Initialized firebase storage and added image functionality to items --- android/app/src/main/AndroidManifest.xml | 2 +- lib/pages/foundItemList.dart | 6 +- lib/pages/lostItemList.dart | 6 +- lib/pages/postFoundItem.dart | 466 +++++++++-------- lib/pages/postLostItem.dart | 483 +++++++++--------- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 200 +++++--- pubspec.yaml | 1 + .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 10 files changed, 649 insertions(+), 521 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index cbad2af..c0f7c85 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ { FirebaseFirestore.instance.collection('FoundProduct').snapshots(); TextEditingController _searchController = TextEditingController(); String _searchText = ""; + String placeholder = 'https://placehold.co/600x400/000000/FFFFFF/png'; @override void initState() { @@ -115,7 +116,10 @@ class _FoundItemListPageState extends State { Column( children: [ Image.network( - 'https://placehold.co/600x400/000000/FFFFFF/png', + (ds.data() as Map?)! + .containsKey('ImageURL') + ? ds['ImageURL'] + : placeholder, width: MediaQuery.of(context).size.width * 0.4, height: MediaQuery.of(context).size.height * 0.4, diff --git a/lib/pages/lostItemList.dart b/lib/pages/lostItemList.dart index 6ae17a3..e02fb95 100644 --- a/lib/pages/lostItemList.dart +++ b/lib/pages/lostItemList.dart @@ -23,6 +23,7 @@ class _LostItemListPageState extends State { int index = 0; TextEditingController _searchController = TextEditingController(); String _searchText = ""; + String placeholder = 'https://placehold.co/600x400/000000/FFFFFF/png'; @override void initState() { @@ -116,7 +117,10 @@ class _LostItemListPageState extends State { Column( children: [ Image.network( - 'https://placehold.co/600x400/000000/FFFFFF/png', + (ds.data() as Map?)! + .containsKey('ImageURL') + ? ds['ImageURL'] + : placeholder, width: MediaQuery.of(context).size.width * 0.4, height: MediaQuery.of(context).size.height * 0.4, diff --git a/lib/pages/postFoundItem.dart b/lib/pages/postFoundItem.dart index 4d1081d..36d595c 100644 --- a/lib/pages/postFoundItem.dart +++ b/lib/pages/postFoundItem.dart @@ -1,7 +1,11 @@ +import 'dart:io'; + import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/services.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; import 'package:image_picker/image_picker.dart'; import 'package:date_time_picker/date_time_picker.dart'; @@ -29,6 +33,7 @@ class _PostFoundItemPageState extends State { TextEditingController unionVillageController = TextEditingController(); TextEditingController streetHouseController = TextEditingController(); DateTime? dateTimeController = DateTime.now(); + late String imgURL; void _insertImage() async { final selector = ImagePicker(); @@ -37,6 +42,21 @@ class _PostFoundItemPageState extends State { if (selectedFile != null) { setState(() { selectedImage = selectedFile; + FirebaseStorage storage = FirebaseStorage.instance; + String fileName = selectedFile.path.split('/').last; + Reference ref = + storage.ref().child('images/$fileName${DateTime.now()}'); + print('--------------------------$ref'); + // Reference ref = + // storage.ref().child('images/' + DateTime.now().toString()); + UploadTask uploadTask = ref.putFile(File(selectedFile.path)); + print(uploadTask); + uploadTask.then((res) { + res.ref.getDownloadURL().then((val) { + imgURL = val; + print("Download URL: $imgURL"); + }); + }); }); } } @@ -161,242 +181,248 @@ class _PostFoundItemPageState extends State { child: Padding( padding: const EdgeInsets.all(15.0), child: SingleChildScrollView( - child: Column(children: [ - // Lost/Found radio button group - Container( - child: IconButton( - onPressed: () { - _sKey.currentState!.openDrawer(); - }, - icon: const Icon( - Icons.menu, - color: Colors.white, - size: 30, - )), - ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.8, - child: DrawerHeader( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () { - // Navigator.pop(context); - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: (context) => PostLostItemPage(), - // ), - // ); - }, - child: const Text( - ' Lost ', - style: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 1.2, + child: Stack( + children: [ + Positioned( + top: 0, + left: 0, + child: IconButton( + style: ElevatedButton.styleFrom( + shape: const CircleBorder(), + padding: const EdgeInsets.all(10), + backgroundColor: + const Color.fromARGB(255, 11, 55, 105), + ), + onPressed: () { + _sKey.currentState!.openDrawer(); + }, + icon: const Icon( + Icons.menu, + color: Colors.white, + size: 30, + )), + ), + Column(children: [ + // Lost/Found radio button group + SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + child: DrawerHeader( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + child: Text( + ' Found Item', + style: GoogleFonts.oswald( + textStyle: const TextStyle( + fontSize: 35, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), ), - ), + ], + ), + ), + ), + const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + height: + MediaQuery.of(context).size.height * 0.075, + child: TextButton( + onPressed: _insertImage, + style: TextButton.styleFrom( + backgroundColor: Colors.cyan, + shadowColor: Colors.green, ), - GestureDetector( - child: const Text( - ' Found ', - style: TextStyle( - color: Colors.grey, + child: + const Text('Insert Found Product Image', + style: TextStyle( + color: Colors.brown, + fontWeight: FontWeight.bold, + )), + ), + ), + const SizedBox(height: 16), + SizedBox( + width: + MediaQuery.of(context).size.width * 0.75, + child: Align( + alignment: Alignment.center, + child: DateTimePicker( + // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, + type: DateTimePickerType.dateTimeSeparate, + dateMask: 'd MMM, yyyy', + initialValue: DateTime.now().toString(), + firstDate: DateTime(2000), + lastDate: DateTime(2099), + icon: const Icon(Icons.date_range_sharp), + dateLabelText: 'Date', + style: const TextStyle( + color: Colors.deepOrangeAccent, fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 2, + ), + timeLabelText: "Hour", + selectableDayPredicate: (date) { + return true; + }, + onChanged: (value) => { + dateTimeController = + DateTime.parse(value), + // dateTimeController = value as DateTimePicker, + }, + decoration: const InputDecoration( + border: OutlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB(255, 156, 178, + 197), // Border color + ), + borderRadius: BorderRadius.all( + Radius.circular( + 15.0), // Border radius + ), + ), ), ), - ) - ], + )), + + const SizedBox(height: 16), + MyTextField( + controller: whatWasFound, + hintText: '', + obscureText: false, + prefixIcon: Icons.cases, + labelText: 'What was Found', + keyboardType: TextInputType.text, ), - ), - ), - const SizedBox(height: 16), - SizedBox( - width: MediaQuery.of(context).size.width * 0.75, - height: MediaQuery.of(context).size.height * 0.075, - child: TextButton( - onPressed: _insertImage, - style: TextButton.styleFrom( - backgroundColor: Colors.cyan, - shadowColor: Colors.green, + const SizedBox(height: 16), + MyTextField( + controller: itemCategory, + hintText: 'Mobile', + obscureText: false, + prefixIcon: Icons.miscellaneous_services, + labelText: 'Item Category', + keyboardType: TextInputType.emailAddress, ), - child: const Text('Insert Found Product Image', - style: TextStyle( - color: Colors.brown, - fontWeight: FontWeight.bold, - )), - ), - ), - const SizedBox(height: 16), - SizedBox( - width: MediaQuery.of(context).size.width * 0.75, - child: Align( - alignment: Alignment.center, - child: DateTimePicker( - // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, - type: DateTimePickerType.dateTimeSeparate, - dateMask: 'd MMM, yyyy', - initialValue: DateTime.now().toString(), - firstDate: DateTime(2000), - lastDate: DateTime(2099), - icon: const Icon(Icons.date_range_sharp), - dateLabelText: 'Date', - style: const TextStyle( - color: Colors.deepOrangeAccent, - fontWeight: FontWeight.bold, + const SizedBox(height: 16), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceAround, + children: [ + // City + SizedBox( + width: MediaQuery.of(context).size.width * + 0.25, + child: MyTextField( + controller: divisionController, + hintText: 'Chittagong', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Division', + keyboardType: TextInputType.streetAddress, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[a-zA-Z. ]')) + ], + ), ), - timeLabelText: "Hour", - selectableDayPredicate: (date) { - return true; - }, - onChanged: (value) => { - dateTimeController = DateTime.parse(value), - // dateTimeController = value as DateTimePicker, - }, - decoration: const InputDecoration( - border: OutlineInputBorder( - borderSide: BorderSide( - color: Color.fromARGB( - 255, 156, 178, 197), // Border color - ), - borderRadius: BorderRadius.all( - Radius.circular(15.0), // Border radius - ), + SizedBox( + width: MediaQuery.of(context).size.width * + 0.25, + child: MyTextField( + controller: cityController, + hintText: 'Hathazari', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'City', + keyboardType: TextInputType.streetAddress, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[a-zA-Z. ]')) + ], + ), + ) + ], + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceAround, + children: [ + // City + SizedBox( + width: MediaQuery.of(context).size.width * + 0.25, + child: MyTextField( + controller: streetHouseController, + hintText: 'Road no: 3, House no: 7', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Street/House No.', + keyboardType: TextInputType.streetAddress, ), ), - ), - )), - - const SizedBox(height: 16), - MyTextField( - controller: whatWasFound, - hintText: '', - obscureText: false, - prefixIcon: Icons.cases, - labelText: 'What was Found', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - MyTextField( - controller: itemCategory, - hintText: 'Mobile', - obscureText: false, - prefixIcon: Icons.miscellaneous_services, - labelText: 'Item Category', - keyboardType: TextInputType.emailAddress, - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: divisionController, - hintText: 'Chittagong', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Division', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[a-zA-Z. ]')) - ], - ), + SizedBox( + width: MediaQuery.of(context).size.width * + 0.25, + child: MyTextField( + controller: unionVillageController, + hintText: 'Fatikchhari', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Union/Village', + keyboardType: TextInputType.streetAddress, + ), + ) + ], ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: cityController, - hintText: 'Hathazari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'City', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[a-zA-Z. ]')) - ], - ), - ) - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: streetHouseController, - hintText: 'Road no: 3, House no: 7', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Street/House No.', - keyboardType: TextInputType.streetAddress, - ), + const SizedBox(height: 16), + MyTextField( + controller: additionalInfo, + hintText: 'Context and description of item', + obscureText: false, + prefixIcon: Icons.info_outlined, + labelText: 'Additional Info', + keyboardType: TextInputType.text, ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: unionVillageController, - hintText: 'Fatikchhari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Union/Village', - keyboardType: TextInputType.streetAddress, - ), - ) - ], - ), - const SizedBox(height: 16), - MyTextField( - controller: additionalInfo, - hintText: 'Context and description of item', - obscureText: false, - prefixIcon: Icons.info_outlined, - labelText: 'Additional Info', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - BackButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.greenAccent, - )), - const SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(width: 16), - SizedBox( - height: - MediaQuery.of(context).size.height * 0.05, - width: - MediaQuery.of(context).size.width * 0.250, - child: ElevatedButton( - onPressed: submitFoundItem, + const SizedBox(height: 16), + BackButton( style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - // splashFactory: InkRipple.splashFactory, - ), - child: const Text( - 'Submit', - style: TextStyle( - color: Colors.deepPurple, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 0.90, + backgroundColor: Colors.greenAccent, + )), + const SizedBox(height: 32), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(width: 16), + SizedBox( + height: MediaQuery.of(context).size.height * + 0.05, + width: MediaQuery.of(context).size.width * + 0.250, + child: ElevatedButton( + onPressed: submitFoundItem, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Submit', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.90, + ), + ), ), ), - ), + ], ), - ], - ), - ]), + ]), + ], + ), ), ), ), diff --git a/lib/pages/postLostItem.dart b/lib/pages/postLostItem.dart index 2a7ab6c..9e4b321 100644 --- a/lib/pages/postLostItem.dart +++ b/lib/pages/postLostItem.dart @@ -1,9 +1,11 @@ +import 'dart:io'; import 'dart:math'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/services.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; import 'package:retrieve_me/pages/login.dart'; import 'package:image_picker/image_picker.dart'; @@ -12,6 +14,7 @@ import '../Components/my_textfield.dart'; import '../Components/navigation_drawer_widget.dart'; import '../firebase_options.dart'; import '../provider/navigation_provider.dart'; +import 'package:firebase_storage/firebase_storage.dart'; GlobalKey _sKey = GlobalKey(); @@ -42,14 +45,33 @@ class _PostLostItemPageState extends State { TextEditingController unionVillageController = TextEditingController(); TextEditingController streetHouseController = TextEditingController(); DateTime? dateTimeController = DateTime.now(); + late String imgURL; void _insertImage() async { final selector = ImagePicker(); final selectedFile = await selector.pickImage(source: ImageSource.gallery); + print(selectedFile); + if (selectedFile != null) { setState(() { selectedImage = selectedFile; + + FirebaseStorage storage = FirebaseStorage.instance; + String fileName = selectedFile.path.split('/').last; + Reference ref = + storage.ref().child('images/$fileName${DateTime.now()}'); + print('--------------------------$ref'); + // Reference ref = + // storage.ref().child('images/' + DateTime.now().toString()); + UploadTask uploadTask = ref.putFile(File(selectedFile.path)); + print(uploadTask); + uploadTask.then((res) { + res.ref.getDownloadURL().then((val) { + imgURL = val; + print("Download URL: $imgURL"); + }); + }); }); } } @@ -86,6 +108,7 @@ class _PostLostItemPageState extends State { 'DivisionLocation': divisionController.text, 'UnionVillageLocation': unionVillageController.text, 'StreetHouseLocation': streetHouseController.text, + 'ImageURL': imgURL, // 'isRetrieved': }; DocumentReference docId = await collectionReference.add(lostItemData); @@ -184,254 +207,254 @@ class _PostLostItemPageState extends State { child: Padding( padding: const EdgeInsets.all(15.0), child: SingleChildScrollView( - child: Column(children: [ - Container( - child: IconButton( - onPressed: () { - _sKey.currentState!.openDrawer(); - }, - icon: const Icon( - Icons.menu, - color: Colors.white, - size: 30, - )), - ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.8, - child: DrawerHeader( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - child: Text( - ' Lost ', - textScaleFactor: - ScaleSize.textScaleFactor(context), - style: const TextStyle( - color: Colors.grey, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 2, + child: Stack( + children: [ + Positioned( + top: 0, + left: 0, + child: IconButton( + style: ElevatedButton.styleFrom( + shape: const CircleBorder(), + padding: const EdgeInsets.all(10), + backgroundColor: + const Color.fromARGB(255, 11, 55, 105), + ), + onPressed: () { + _sKey.currentState!.openDrawer(); + }, + icon: const Icon( + Icons.menu, + color: Colors.white, + size: 30, + )), + ), + Column(children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + child: DrawerHeader( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + child: Text( + ' Lost Item', + textScaleFactor: + ScaleSize.textScaleFactor( + context), + style: GoogleFonts.oswald( + textStyle: const TextStyle( + fontSize: 35, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), ), - ), + ], ), - GestureDetector( - onTap: () { - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: (context) => - // PostFoundItemPage(), - // ), - // ); - // Navigator.pop(context); - }, - child: Text( - ' Found ', - textScaleFactor: - ScaleSize.textScaleFactor(context), - style: const TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 1, - ), - ), - ) - ], - ), - )), - // Lost/Found radio button group - - const SizedBox(height: 16), - SizedBox( - width: MediaQuery.of(context).size.width * 0.75, - height: MediaQuery.of(context).size.height * 0.075, - child: TextButton( - onPressed: _insertImage, - style: TextButton.styleFrom( - backgroundColor: Colors.cyan, - shadowColor: Colors.green, - ), - child: const Text('Insert Lost Product Image', - style: TextStyle( - color: Colors.brown, - fontWeight: FontWeight.bold, )), - ), - ), - const SizedBox(height: 16), - SizedBox( - width: MediaQuery.of(context).size.width * 0.75, - child: Align( - alignment: Alignment.center, - child: DateTimePicker( - // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, - type: DateTimePickerType - .dateTimeSeparate, // Adjust the type based on your requirements - dateMask: 'd MMM, yyyy', - initialValue: DateTime.now().toString(), - firstDate: DateTime( - 2000), // Adjust the firstDate based on your requirements - lastDate: DateTime(2099), - icon: const Icon(Icons.date_range_sharp), - dateLabelText: 'Date', - style: const TextStyle( - color: Colors.deepOrangeAccent, - fontWeight: FontWeight.bold, + // Lost/Found radio button group + + const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + height: + MediaQuery.of(context).size.height * 0.075, + child: TextButton( + onPressed: _insertImage, + style: TextButton.styleFrom( + backgroundColor: Colors.cyan, + shadowColor: Colors.green, + ), + child: const Text('Insert Lost Product Image', + style: TextStyle( + color: Colors.brown, + fontWeight: FontWeight.bold, + )), ), - timeLabelText: "Hour", - selectableDayPredicate: (date) { - return true; - }, - onChanged: (value) => { - dateTimeController = DateTime.parse(value), - // dateTimeController = value as DateTimePicker, - }, - decoration: const InputDecoration( - border: OutlineInputBorder( - borderSide: BorderSide( - color: Color.fromARGB( - 255, 156, 178, 197), // Border color + ), + const SizedBox(height: 16), + SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + child: Align( + alignment: Alignment.center, + child: DateTimePicker( + // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, + type: DateTimePickerType + .dateTimeSeparate, // Adjust the type based on your requirements + dateMask: 'd MMM, yyyy', + initialValue: DateTime.now().toString(), + firstDate: DateTime( + 2000), // Adjust the firstDate based on your requirements + lastDate: DateTime(2099), + icon: const Icon(Icons.date_range_sharp), + dateLabelText: 'Date', + style: const TextStyle( + color: Colors.deepOrangeAccent, + fontWeight: FontWeight.bold, ), - borderRadius: BorderRadius.all( - Radius.circular(15.0), // Border radius + timeLabelText: "Hour", + selectableDayPredicate: (date) { + return true; + }, + onChanged: (value) => { + dateTimeController = DateTime.parse(value), + // dateTimeController = value as DateTimePicker, + }, + decoration: const InputDecoration( + border: OutlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB( + 255, 156, 178, 197), // Border color + ), + borderRadius: BorderRadius.all( + Radius.circular(15.0), // Border radius + ), + ), ), ), ), ), - ), - ), - const SizedBox(height: 16), - MyTextField( - controller: whatWasLost, - hintText: 'Walton Primo RX7', - obscureText: false, - prefixIcon: Icons.cases, - labelText: 'What was Lost', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - MyTextField( - controller: itemCategory, - hintText: 'Mobile', - obscureText: false, - prefixIcon: Icons.miscellaneous_services, - labelText: 'Item Category', - keyboardType: TextInputType.emailAddress, - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: divisionController, - hintText: 'Chittagong', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Division', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[a-zA-Z. ]')) - ], - ), + const SizedBox(height: 16), + MyTextField( + controller: whatWasLost, + hintText: 'Walton Primo RX7', + obscureText: false, + prefixIcon: Icons.cases, + labelText: 'What was Lost', + keyboardType: TextInputType.text, ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: cityController, - hintText: 'Hathazari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'City', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[a-zA-Z. ]')) - ], - ), - ) - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: streetHouseController, - hintText: 'Road no: 3, House no: 7', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Street/House No.', - keyboardType: TextInputType.streetAddress, - ), + const SizedBox(height: 16), + MyTextField( + controller: itemCategory, + hintText: 'Mobile', + obscureText: false, + prefixIcon: Icons.miscellaneous_services, + labelText: 'Item Category', + keyboardType: TextInputType.emailAddress, ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: unionVillageController, - hintText: 'Fatikchhari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Union/Village', - keyboardType: TextInputType.streetAddress, - ), - ) - ], - ), - const SizedBox(height: 16), - MyTextField( - controller: additionalInfo, - hintText: 'Context and description of item', - obscureText: false, - prefixIcon: Icons.info_outlined, - labelText: 'Additional Info', - keyboardType: TextInputType.text, - ), - const SizedBox(height: 16), - - BackButton( - onPressed: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => LoginPage(), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + // City + SizedBox( + width: + MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: divisionController, + hintText: 'Chittagong', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Division', + keyboardType: TextInputType.streetAddress, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[a-zA-Z. ]')) + ], ), ), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.greenAccent, - )), - const SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(width: 16), - SizedBox( - height: MediaQuery.of(context).size.height * 0.05, - width: MediaQuery.of(context).size.width * 0.250, - child: ElevatedButton( - onPressed: submitLostItem, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - // splashFactory: InkRipple.splashFactory, + SizedBox( + width: + MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: cityController, + hintText: 'Hathazari', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'City', + keyboardType: TextInputType.streetAddress, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[a-zA-Z. ]')) + ], + ), + ) + ], + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + // City + SizedBox( + width: + MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: streetHouseController, + hintText: 'Road no: 3, House no: 7', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Street/House No.', + keyboardType: TextInputType.streetAddress, + ), ), - child: const Text( - 'Submit', - style: TextStyle( - color: Colors.deepPurple, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 0.90, + SizedBox( + width: + MediaQuery.of(context).size.width * 0.25, + child: MyTextField( + controller: unionVillageController, + hintText: 'Fatikchhari', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Union/Village', + keyboardType: TextInputType.streetAddress, + ), + ) + ], + ), + const SizedBox(height: 16), + MyTextField( + controller: additionalInfo, + hintText: 'Context and description of item', + obscureText: false, + prefixIcon: Icons.info_outlined, + labelText: 'Additional Info', + keyboardType: TextInputType.text, + ), + const SizedBox(height: 16), + + BackButton( + onPressed: () => Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => LoginPage(), + ), + ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.greenAccent, + )), + const SizedBox(height: 32), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(width: 16), + SizedBox( + height: + MediaQuery.of(context).size.height * 0.05, + width: + MediaQuery.of(context).size.width * 0.250, + child: ElevatedButton( + onPressed: submitLostItem, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Submit', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.90, + ), + ), ), ), - ), + ], ), - ], - ), - ]), + ]), + ], + ), ), ), ), diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 466c67d..630d0f8 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -10,6 +10,7 @@ import file_selector_macos import firebase_analytics import firebase_auth import firebase_core +import firebase_storage import path_provider_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { @@ -18,5 +19,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAnalyticsPlugin")) FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 675ce6e..35aff47 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -45,26 +45,26 @@ packages: dependency: "direct main" description: name: cloud_firestore - sha256: "50e33a5cd62f7ed0e8290802a7e68e090d27738f65256977162c127303ad82ea" + sha256: "8bfbb5a2edbc6052452326d60de0113fea2bcbf081d34a3f8e45c8b38307b31c" url: "https://pub.dev" source: hosted - version: "4.13.5" + version: "4.14.0" cloud_firestore_platform_interface: dependency: transitive description: name: cloud_firestore_platform_interface - sha256: dedbd776c04429f85726e5cfb6f929d8405da241ceec32baa7d31b7d062dad53 + sha256: "73ff438fe46028f0e19f55da18b6ddc6906ab750562cd7d9ffab77ff8c0c4307" url: "https://pub.dev" source: hosted - version: "6.0.9" + version: "6.1.0" cloud_firestore_web: dependency: transitive description: name: cloud_firestore_web - sha256: fd60d31f4eb104295256edc2e0bee631dc2b3283c5087701c513bfa9f27b711a + sha256: "232e45e95970d3a6baab8f50f9c3a6e2838d145d9d91ec9a7392837c44296397" url: "https://pub.dev" source: hosted - version: "3.8.9" + version: "3.9.0" collapsible_sidebar: dependency: "direct main" description: @@ -77,18 +77,18 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.18.0" cross_file: dependency: transitive description: name: cross_file - sha256: "2f9d2cbccb76127ba28528cb3ae2c2326a122446a83de5a056aaa3880d3882c5" + sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e url: "https://pub.dev" source: hosted - version: "0.3.3+7" + version: "0.3.3+8" crypto: dependency: transitive description: @@ -125,10 +125,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" file_selector_linux: dependency: transitive description: @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: file_selector_platform_interface - sha256: "0aa47a725c346825a2bd396343ce63ac00bda6eff2fbc43eabe99737dede8262" + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b url: "https://pub.dev" source: hosted - version: "2.6.1" + version: "2.6.2" file_selector_windows: dependency: transitive description: @@ -165,50 +165,50 @@ packages: dependency: "direct main" description: name: firebase_analytics - sha256: "5e92d510eacd66c354718fd9cc8f66ffdfa025640b645c4742297fb973770508" + sha256: "0240076090d77045d757aecb090616066d23b343840d4c21074094d6fe40a184" url: "https://pub.dev" source: hosted - version: "10.7.4" + version: "10.8.0" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface - sha256: "72977325a72af5ebb8e53b5c5533cb2e33eec481cd46210cfe5427f5efba55d8" + sha256: "6d9baa077d16b47ef5f19d982c4fc475597991aa53b0c601216faa3e1cdab45f" url: "https://pub.dev" source: hosted - version: "3.8.4" + version: "3.9.0" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web - sha256: "8b9710be7e292e2a5ad34fff449d4b668c5808fb339649e69181727a4534f579" + sha256: "89a740249bce9d52a99db4e501be6087ca6749c73c47cff2b174802be10abd81" url: "https://pub.dev" source: hosted - version: "0.5.5+11" + version: "0.5.5+12" firebase_auth: dependency: "direct main" description: name: firebase_auth - sha256: a87cfdd16b2bd04ca4a61e8b8d95daafaae487aa4c6533c9497199d631eefe6f + sha256: "279b2773ff61afd9763202cb5582e2b995ee57419d826b9af6517302a59b672f" url: "https://pub.dev" source: hosted - version: "4.15.2" + version: "4.16.0" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface - sha256: "4ca90755469fd20bf32070a3ff4dcb6256cfafc47230cc021261acced672ed3c" + sha256: "3c9cfaccb7549492edf5b0c67c6dd1c6727c7830891aa6727f2fb225f0226626" url: "https://pub.dev" source: hosted - version: "7.0.8" + version: "7.0.9" firebase_auth_web: dependency: transitive description: name: firebase_auth_web - sha256: "8eb2b4d35ed46405783c135cdf7c4c2d2769abe09cee60fcd8080c0475a9e8b5" + sha256: c7b1379ccef7abf4b6816eede67a868c44142198e42350f51c01d8fc03f95a7d url: "https://pub.dev" source: hosted - version: "5.8.11" + version: "5.8.13" firebase_core: dependency: "direct main" description: @@ -233,6 +233,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.10.0" + firebase_storage: + dependency: "direct main" + description: + name: firebase_storage + sha256: "75e6cb6bed65138b5bbd86bfd7cf9bc9a175fb0c31aacc400e9203df117ffbe6" + url: "https://pub.dev" + source: hosted + version: "11.6.0" + firebase_storage_platform_interface: + dependency: transitive + description: + name: firebase_storage_platform_interface + sha256: "545a3a8edf337850403bb0fa03c8074a53deb87c0107d19755c77a82ce07919e" + url: "https://pub.dev" + source: hosted + version: "5.1.3" + firebase_storage_web: + dependency: transitive + description: + name: firebase_storage_web + sha256: ee6870ff79aa304b8996ba18a4aefe1e8b3fc31fd385eab6574180267aa8d393 + url: "https://pub.dev" + source: hosted + version: "3.6.17" flutter: dependency: "direct main" description: flutter @@ -276,10 +300,10 @@ packages: dependency: transitive description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" http_parser: dependency: transitive description: @@ -300,10 +324,10 @@ packages: dependency: transitive description: name: image_picker_android - sha256: d6a6e78821086b0b737009b09363018309bbc6de3fd88cc5c26bc2bb44a4957f + sha256: "39f2bfe497e495450c81abcd44b62f56c2a36a37a175da7d137b4454977b51b1" url: "https://pub.dev" source: hosted - version: "0.8.8+2" + version: "0.8.9+3" image_picker_for_web: dependency: transitive description: @@ -316,10 +340,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: "76ec722aeea419d03aa915c2c96bf5b47214b053899088c9abb4086ceecf97a7" + sha256: fadafce49e8569257a0cad56d24438a6fa1f0cbd7ee0af9b631f7492818a4ca3 url: "https://pub.dev" source: hosted - version: "0.8.8+4" + version: "0.8.9+1" image_picker_linux: dependency: transitive description: @@ -340,10 +364,10 @@ packages: dependency: transitive description: name: image_picker_platform_interface - sha256: ed9b00e63977c93b0d2d2b343685bed9c324534ba5abafbb3dfbd6a780b1b514 + sha256: fa4e815e6fcada50e35718727d83ba1c92f1edf95c0b4436554cec301b56233b url: "https://pub.dev" source: hosted - version: "2.9.1" + version: "2.9.3" image_picker_windows: dependency: transitive description: @@ -368,6 +392,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: f8cdf1383f5b4672a2693d875f1f239af6bd7e4a8925a17ef7219226db932624 + url: "https://pub.dev" + source: hosted + version: "10.0.1" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: a2055640bf5bc903475e4bbdb34e04f8bf698542bee41edec47d337a5939e1ae + url: "https://pub.dev" + source: hosted + version: "2.0.3" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: e62042d479c4c139dd774125ed4dfbde646b8f07ac228e3c1b57a3d91d6d9df4 + url: "https://pub.dev" + source: hosted + version: "2.0.2" lints: dependency: transitive description: @@ -380,26 +428,26 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.11.0" mime: dependency: transitive description: @@ -420,34 +468,34 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: transitive description: name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -460,10 +508,10 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: @@ -476,18 +524,18 @@ packages: dependency: transitive description: name: platform - sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.1.8" provider: dependency: "direct main" description: @@ -505,26 +553,26 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -545,10 +593,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.1" typed_data: dependency: transitive description: @@ -565,22 +613,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" + web: + dependency: transitive + description: + name: web + sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05" + url: "https://pub.dev" + source: hosted + version: "0.4.2" win32: dependency: transitive description: name: win32 - sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3" + sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" url: "https://pub.dev" source: hosted - version: "5.0.9" + version: "5.2.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" sdks: - dart: ">=3.0.5 <4.0.0" - flutter: ">=3.7.0" + dart: ">=3.3.0-279.1.beta <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/pubspec.yaml b/pubspec.yaml index 925c2c7..c6ca268 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,6 +45,7 @@ dependencies: js: ^0.6.2 collapsible_sidebar: ^2.0.7 provider: ^5.0.0 + firebase_storage: ^11.6.0 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 4a46c81..ec1e463 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -10,6 +10,7 @@ #include #include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { CloudFirestorePluginCApiRegisterWithRegistrar( @@ -20,4 +21,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi")); FirebaseCorePluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); + FirebaseStoragePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseStoragePluginCApi")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index e0beee3..767b528 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows firebase_auth firebase_core + firebase_storage ) list(APPEND FLUTTER_FFI_PLUGIN_LIST From 2a707ee2ef0c88055683a7a3abea4c1391538818 Mon Sep 17 00:00:00 2001 From: ImranIF Date: Tue, 23 Jan 2024 18:17:26 +0600 Subject: [PATCH 07/19] fixed image reference in Post Lost Item --- lib/pages/foundItemList.dart | 21 +++++++++++++-------- lib/pages/lostItemList.dart | 21 +++++++++++++-------- lib/pages/postFoundItem.dart | 1 + pubspec.lock | 8 ++++++++ pubspec.yaml | 1 + 5 files changed, 36 insertions(+), 16 deletions(-) diff --git a/lib/pages/foundItemList.dart b/lib/pages/foundItemList.dart index e9ec903..09752b3 100644 --- a/lib/pages/foundItemList.dart +++ b/lib/pages/foundItemList.dart @@ -5,6 +5,7 @@ import 'package:provider/provider.dart'; import 'package:retrieve_me/Components/navigation_drawer_widget.dart'; import 'package:retrieve_me/provider/navigation_provider.dart'; import 'package:intl/intl.dart'; +import 'package:widget_zoom/widget_zoom.dart'; import '../firebase_options.dart'; @@ -115,14 +116,18 @@ class _FoundItemListPageState extends State { children: [ Column( children: [ - Image.network( - (ds.data() as Map?)! - .containsKey('ImageURL') - ? ds['ImageURL'] - : placeholder, - width: MediaQuery.of(context).size.width * 0.4, - height: - MediaQuery.of(context).size.height * 0.4, + WidgetZoom( + heroAnimationTag: 'tag', + zoomWidget: Image.network( + (ds.data() as Map?)! + .containsKey('ImageURL') + ? ds['ImageURL'] + : placeholder, + width: + MediaQuery.of(context).size.width * 0.4, + height: + MediaQuery.of(context).size.height * 0.4, + ), ), ], ), diff --git a/lib/pages/lostItemList.dart b/lib/pages/lostItemList.dart index e02fb95..324a369 100644 --- a/lib/pages/lostItemList.dart +++ b/lib/pages/lostItemList.dart @@ -5,6 +5,7 @@ import 'package:provider/provider.dart'; import 'package:retrieve_me/Components/navigation_drawer_widget.dart'; import 'package:retrieve_me/provider/navigation_provider.dart'; import 'package:intl/intl.dart'; +import 'package:widget_zoom/widget_zoom.dart'; import '../firebase_options.dart'; @@ -116,14 +117,18 @@ class _LostItemListPageState extends State { children: [ Column( children: [ - Image.network( - (ds.data() as Map?)! - .containsKey('ImageURL') - ? ds['ImageURL'] - : placeholder, - width: MediaQuery.of(context).size.width * 0.4, - height: - MediaQuery.of(context).size.height * 0.4, + WidgetZoom( + heroAnimationTag: 'tag', + zoomWidget: Image.network( + (ds.data() as Map?)! + .containsKey('ImageURL') + ? ds['ImageURL'] + : placeholder, + width: + MediaQuery.of(context).size.width * 0.4, + height: + MediaQuery.of(context).size.height * 0.4, + ), ), ], ), diff --git a/lib/pages/postFoundItem.dart b/lib/pages/postFoundItem.dart index 36d595c..7c41157 100644 --- a/lib/pages/postFoundItem.dart +++ b/lib/pages/postFoundItem.dart @@ -93,6 +93,7 @@ class _PostFoundItemPageState extends State { 'DivisionLocation': divisionController.text, 'UnionVillageLocation': unionVillageController.text, 'StreetHouseLocation': streetHouseController.text, + 'ImageURL': imgURL, }; await collectionReference.add(foundItemData); diff --git a/pubspec.lock b/pubspec.lock index 35aff47..72a5187 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -629,6 +629,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.2" + widget_zoom: + dependency: "direct main" + description: + name: widget_zoom + sha256: "2bc683a465a5ba46db6e47c885b298e21b0588400e6507832bd04adc8848bf82" + url: "https://pub.dev" + source: hosted + version: "0.0.3" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c6ca268..7ef67ac 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,7 @@ dependencies: collapsible_sidebar: ^2.0.7 provider: ^5.0.0 firebase_storage: ^11.6.0 + widget_zoom: ^0.0.3 dev_dependencies: flutter_test: From 5aabc49f9a7412af914f54867ee5a923668fd5c2 Mon Sep 17 00:00:00 2001 From: ImranIF Date: Tue, 23 Jan 2024 19:30:20 +0600 Subject: [PATCH 08/19] refactored --- lib/pages/postFoundItem.dart | 127 ++++++++++++++++++----------------- lib/pages/postLostItem.dart | 62 ++++++++--------- pubspec.yaml | 2 +- 3 files changed, 95 insertions(+), 96 deletions(-) diff --git a/lib/pages/postFoundItem.dart b/lib/pages/postFoundItem.dart index 7c41157..55f845e 100644 --- a/lib/pages/postFoundItem.dart +++ b/lib/pages/postFoundItem.dart @@ -252,41 +252,7 @@ class _PostFoundItemPageState extends State { MediaQuery.of(context).size.width * 0.75, child: Align( alignment: Alignment.center, - child: DateTimePicker( - // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, - type: DateTimePickerType.dateTimeSeparate, - dateMask: 'd MMM, yyyy', - initialValue: DateTime.now().toString(), - firstDate: DateTime(2000), - lastDate: DateTime(2099), - icon: const Icon(Icons.date_range_sharp), - dateLabelText: 'Date', - style: const TextStyle( - color: Colors.deepOrangeAccent, - fontWeight: FontWeight.bold, - ), - timeLabelText: "Hour", - selectableDayPredicate: (date) { - return true; - }, - onChanged: (value) => { - dateTimeController = - DateTime.parse(value), - // dateTimeController = value as DateTimePicker, - }, - decoration: const InputDecoration( - border: OutlineInputBorder( - borderSide: BorderSide( - color: Color.fromARGB(255, 156, 178, - 197), // Border color - ), - borderRadius: BorderRadius.all( - Radius.circular( - 15.0), // Border radius - ), - ), - ), - ), + child: dateTimePicker(), )), const SizedBox(height: 16), @@ -394,33 +360,7 @@ class _PostFoundItemPageState extends State { backgroundColor: Colors.greenAccent, )), const SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(width: 16), - SizedBox( - height: MediaQuery.of(context).size.height * - 0.05, - width: MediaQuery.of(context).size.width * - 0.250, - child: ElevatedButton( - onPressed: submitFoundItem, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - // splashFactory: InkRipple.splashFactory, - ), - child: const Text( - 'Submit', - style: TextStyle( - color: Colors.deepPurple, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 0.90, - ), - ), - ), - ), - ], - ), + submitButton(context), ]), ], ), @@ -434,4 +374,67 @@ class _PostFoundItemPageState extends State { ), ); } + + Row submitButton(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(width: 16), + SizedBox( + height: MediaQuery.of(context).size.height * 0.05, + width: MediaQuery.of(context).size.width * 0.350, + child: ElevatedButton( + onPressed: submitFoundItem, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Submit', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.90, + ), + ), + ), + ), + ], + ); + } + + DateTimePicker dateTimePicker() { + return DateTimePicker( + // timeFieldWidth: MediaQuery.of(context).size.width * 0.35, + type: DateTimePickerType.dateTimeSeparate, + dateMask: 'd MMM, yyyy', + initialValue: DateTime.now().toString(), + firstDate: DateTime(2000), + lastDate: DateTime(2099), + icon: const Icon(Icons.date_range_sharp), + dateLabelText: 'Date', + style: const TextStyle( + color: Colors.deepOrangeAccent, + fontWeight: FontWeight.bold, + ), + timeLabelText: "Hour", + selectableDayPredicate: (date) { + return true; + }, + onChanged: (value) => { + dateTimeController = DateTime.parse(value), + // dateTimeController = value as DateTimePicker, + }, + decoration: const InputDecoration( + border: OutlineInputBorder( + borderSide: BorderSide( + color: Color.fromARGB(255, 156, 178, 197), // Border color + ), + borderRadius: BorderRadius.all( + Radius.circular(15.0), // Border radius + ), + ), + ), + ); + } } diff --git a/lib/pages/postLostItem.dart b/lib/pages/postLostItem.dart index 9e4b321..ee58465 100644 --- a/lib/pages/postLostItem.dart +++ b/lib/pages/postLostItem.dart @@ -133,12 +133,6 @@ class _PostLostItemPageState extends State { ], ), ); - - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: (context) => LoginPage(), - // ), - // ); } catch (e) { showDialog( context: context, @@ -425,33 +419,7 @@ class _PostLostItemPageState extends State { backgroundColor: Colors.greenAccent, )), const SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(width: 16), - SizedBox( - height: - MediaQuery.of(context).size.height * 0.05, - width: - MediaQuery.of(context).size.width * 0.250, - child: ElevatedButton( - onPressed: submitLostItem, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - // splashFactory: InkRipple.splashFactory, - ), - child: const Text( - 'Submit', - style: TextStyle( - color: Colors.deepPurple, - fontWeight: FontWeight.bold, - fontSize: Checkbox.width * 0.90, - ), - ), - ), - ), - ], - ), + submitButton(context), ]), ], ), @@ -466,4 +434,32 @@ class _PostLostItemPageState extends State { ), ); } + + Row submitButton(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(width: 16), + SizedBox( + height: MediaQuery.of(context).size.height * 0.05, + width: MediaQuery.of(context).size.width * 0.350, + child: ElevatedButton( + onPressed: submitLostItem, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Submit', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.90, + ), + ), + ), + ), + ], + ); + } } diff --git a/pubspec.yaml b/pubspec.yaml index 7ef67ac..51cba98 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. date_time_picker: ^2.1.0 cupertino_icons: ^1.0.2 - firebase_core: ^2.15.0 + firebase_core: ^2.24.2 firebase_auth: ^4.7.2 cloud_firestore: ^4.8.4 firebase_analytics: ^10.4.4 From 4b4ee92f72616e41a489bb938296fd4fc0dbf6ec Mon Sep 17 00:00:00 2001 From: Md-Kais Date: Wed, 24 Jan 2024 19:11:03 +0600 Subject: [PATCH 09/19] Profile Page + registration + user + leaderboard done. --- .gitignore | 2 +- lib/Components/navigation_drawer_widget.dart | 6 +- lib/auth/auth_services.dart | 3 + lib/db/db_helper.dart | 9 +- lib/main.dart | 11 +- lib/model/UserModel.dart | 19 +- lib/model/image_model.dart | 15 + lib/model/image_model.freezed.dart | 181 ++++++++ lib/model/image_model.g.dart | 21 + lib/pages/CustomListTile.dart | 37 ++ lib/pages/leaderBoardPage.dart | 107 +++++ lib/pages/login.dart | 3 +- lib/pages/profilePage.dart | 331 ++++++++++++++ lib/pages/registration.dart | 147 +++++-- lib/pages/userPage.dart | 234 ++++++++++ lib/provider/user_provider.dart | 47 +- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 410 +++++++++++++++++- pubspec.yaml | 7 + 19 files changed, 1529 insertions(+), 63 deletions(-) create mode 100644 lib/model/image_model.dart create mode 100644 lib/model/image_model.freezed.dart create mode 100644 lib/model/image_model.g.dart create mode 100644 lib/pages/CustomListTile.dart create mode 100644 lib/pages/leaderBoardPage.dart create mode 100644 lib/pages/profilePage.dart create mode 100644 lib/pages/userPage.dart diff --git a/.gitignore b/.gitignore index 70ccb97..eda748d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,7 @@ migrate_working_dir/ *.ipr *.iws .idea/ - +android/app/src/google-services.json # 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. diff --git a/lib/Components/navigation_drawer_widget.dart b/lib/Components/navigation_drawer_widget.dart index b39d9d0..96c046e 100644 --- a/lib/Components/navigation_drawer_widget.dart +++ b/lib/Components/navigation_drawer_widget.dart @@ -24,9 +24,12 @@ class NavigationDrawerWidget extends StatelessWidget { return SizedBox( width: isCollapsed ? MediaQuery.of(context).size.width * 0.15 : null, child: Drawer( + child: Container( color: const Color(0xFF1a2f45), - child: Column( + child: ListView( + physics: ClampingScrollPhysics(), + children: [ Container( padding: @@ -63,6 +66,7 @@ class NavigationDrawerWidget extends StatelessWidget { ], )), ), + ); } diff --git a/lib/auth/auth_services.dart b/lib/auth/auth_services.dart index c5f92fc..e45e7a2 100644 --- a/lib/auth/auth_services.dart +++ b/lib/auth/auth_services.dart @@ -1,4 +1,5 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:retrieve_me/db/db_helper.dart'; @@ -19,6 +20,8 @@ class AuthService{ return credential.user!; } + + static Future logout(){ return _auth.signOut(); } diff --git a/lib/db/db_helper.dart b/lib/db/db_helper.dart index a68e732..9eee7c4 100644 --- a/lib/db/db_helper.dart +++ b/lib/db/db_helper.dart @@ -15,11 +15,14 @@ class db_helper { final snapshot = await _db.collection(adminCollection).doc(uid).get(); return snapshot.exists; } - + static Stream>> getAllUsers() { + print("HELLO KAIS"); + return _db.collection(collectionUser).snapshots(); + } static Future addUser(UserModel userModel) { print(userModel.email); - return _db - .collection(collectionUser).add(userModel.toMap()); + return _db.collection(collectionUser).doc(userModel.userId).set(userModel + .toMap()); } static Future doesUserExist(String uid) async { diff --git a/lib/main.dart b/lib/main.dart index 009be91..4c7d93b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,7 +2,10 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:provider/provider.dart'; +import 'package:retrieve_me/pages/leaderBoardPage.dart'; import 'package:retrieve_me/pages/login.dart'; +import 'package:retrieve_me/pages/profilePage.dart'; +import 'package:retrieve_me/pages/userPage.dart'; import 'package:retrieve_me/provider/user_provider.dart'; Future main() async { @@ -29,7 +32,13 @@ class MyApp extends StatelessWidget { useMaterial3: true, ), // home: const RegistrationPage(), - home: LoginPage(), + // home: LoginPage(), + initialRoute: LoginPage.routeName, + routes:{ + LoginPage.routeName: (_) => const LoginPage(), + UserPage.routeName: (_) => const UserPage(), + LeaderBoardPage.routeName: (_) => const LeaderBoardPage(), + } ); } diff --git a/lib/model/UserModel.dart b/lib/model/UserModel.dart index bad3f66..519d68f 100644 --- a/lib/model/UserModel.dart +++ b/lib/model/UserModel.dart @@ -1,59 +1,72 @@ +import 'dart:ffi'; + import 'package:cloud_firestore/cloud_firestore.dart'; +import 'image_model.dart'; + // import 'address_model.dart'; const String collectionUser='Users'; const String userFieldId='userId'; const String userFieldFirstName='firstName'; +const String userFieldlastName='lastName'; const String userFieldAddress = 'address'; const String userFieldCreationTime='CreationTime'; const String userFieldRating='rating'; const String userFieldProfession='profession'; const String userFieldContact ='contactNo'; const String userFieldEmail='email'; +const String userFieldThumbnail = 'thumbnail'; class UserModel{ String userId; String firstName; + String lastName; String address; Timestamp? userCreationTime; - String? rating; + num? rating; String profession; String contactNo; String email; + ImageModel thumbnailImage; UserModel({ required this.userId, required this.firstName, + required this.lastName, required this.address, this.userCreationTime, this.rating, required this.profession, required this.contactNo, - required this.email + required this.email, + required this.thumbnailImage, }); - MaptoMap(){ return { userFieldId:userId, userFieldFirstName:firstName, + userFieldlastName:lastName, userFieldAddress:address, userFieldCreationTime:userCreationTime, userFieldRating: rating, userFieldProfession: profession, userFieldContact: contactNo, userFieldEmail:email, + userFieldThumbnail : thumbnailImage.toJson(),// }; } factory UserModel.fromMap(Mapmap)=>UserModel( userId: map[userFieldId], firstName: map[userFieldFirstName], + lastName: map[userFieldlastName], address: map[userFieldAddress] , userCreationTime: map[userFieldCreationTime], rating: map[userFieldRating], profession: map[userFieldProfession], contactNo: map[userFieldContact], email: map[userFieldEmail], + thumbnailImage: ImageModel.fromJson(map[userFieldThumbnail]), ); } \ No newline at end of file diff --git a/lib/model/image_model.dart b/lib/model/image_model.dart new file mode 100644 index 0000000..5fc0153 --- /dev/null +++ b/lib/model/image_model.dart @@ -0,0 +1,15 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'image_model.freezed.dart'; +part 'image_model.g.dart'; + +@unfreezed +class ImageModel with _$ImageModel{ + factory ImageModel({ + required String imageName, + required String directoryName, + required String downloadUrl, + }) = _ImageModel; + + factory ImageModel.fromJson(Map json) => + _$ImageModelFromJson(json); +} diff --git a/lib/model/image_model.freezed.dart b/lib/model/image_model.freezed.dart new file mode 100644 index 0000000..9b9db92 --- /dev/null +++ b/lib/model/image_model.freezed.dart @@ -0,0 +1,181 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'image_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +ImageModel _$ImageModelFromJson(Map json) { + return _ImageModel.fromJson(json); +} + +/// @nodoc +mixin _$ImageModel { + String get imageName => throw _privateConstructorUsedError; + set imageName(String value) => throw _privateConstructorUsedError; + String get directoryName => throw _privateConstructorUsedError; + set directoryName(String value) => throw _privateConstructorUsedError; + String get downloadUrl => throw _privateConstructorUsedError; + set downloadUrl(String value) => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ImageModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ImageModelCopyWith<$Res> { + factory $ImageModelCopyWith( + ImageModel value, $Res Function(ImageModel) then) = + _$ImageModelCopyWithImpl<$Res, ImageModel>; + @useResult + $Res call({String imageName, String directoryName, String downloadUrl}); +} + +/// @nodoc +class _$ImageModelCopyWithImpl<$Res, $Val extends ImageModel> + implements $ImageModelCopyWith<$Res> { + _$ImageModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? imageName = null, + Object? directoryName = null, + Object? downloadUrl = null, + }) { + return _then(_value.copyWith( + imageName: null == imageName + ? _value.imageName + : imageName // ignore: cast_nullable_to_non_nullable + as String, + directoryName: null == directoryName + ? _value.directoryName + : directoryName // ignore: cast_nullable_to_non_nullable + as String, + downloadUrl: null == downloadUrl + ? _value.downloadUrl + : downloadUrl // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ImageModelImplCopyWith<$Res> + implements $ImageModelCopyWith<$Res> { + factory _$$ImageModelImplCopyWith( + _$ImageModelImpl value, $Res Function(_$ImageModelImpl) then) = + __$$ImageModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String imageName, String directoryName, String downloadUrl}); +} + +/// @nodoc +class __$$ImageModelImplCopyWithImpl<$Res> + extends _$ImageModelCopyWithImpl<$Res, _$ImageModelImpl> + implements _$$ImageModelImplCopyWith<$Res> { + __$$ImageModelImplCopyWithImpl( + _$ImageModelImpl _value, $Res Function(_$ImageModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? imageName = null, + Object? directoryName = null, + Object? downloadUrl = null, + }) { + return _then(_$ImageModelImpl( + imageName: null == imageName + ? _value.imageName + : imageName // ignore: cast_nullable_to_non_nullable + as String, + directoryName: null == directoryName + ? _value.directoryName + : directoryName // ignore: cast_nullable_to_non_nullable + as String, + downloadUrl: null == downloadUrl + ? _value.downloadUrl + : downloadUrl // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ImageModelImpl implements _ImageModel { + _$ImageModelImpl( + {required this.imageName, + required this.directoryName, + required this.downloadUrl}); + + factory _$ImageModelImpl.fromJson(Map json) => + _$$ImageModelImplFromJson(json); + + @override + String imageName; + @override + String directoryName; + @override + String downloadUrl; + + @override + String toString() { + return 'ImageModel(imageName: $imageName, directoryName: $directoryName, downloadUrl: $downloadUrl)'; + } + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ImageModelImplCopyWith<_$ImageModelImpl> get copyWith => + __$$ImageModelImplCopyWithImpl<_$ImageModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ImageModelImplToJson( + this, + ); + } +} + +abstract class _ImageModel implements ImageModel { + factory _ImageModel( + {required String imageName, + required String directoryName, + required String downloadUrl}) = _$ImageModelImpl; + + factory _ImageModel.fromJson(Map json) = + _$ImageModelImpl.fromJson; + + @override + String get imageName; + set imageName(String value); + @override + String get directoryName; + set directoryName(String value); + @override + String get downloadUrl; + set downloadUrl(String value); + @override + @JsonKey(ignore: true) + _$$ImageModelImplCopyWith<_$ImageModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/model/image_model.g.dart b/lib/model/image_model.g.dart new file mode 100644 index 0000000..617a1b5 --- /dev/null +++ b/lib/model/image_model.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'image_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ImageModelImpl _$$ImageModelImplFromJson(Map json) => + _$ImageModelImpl( + imageName: json['imageName'] as String, + directoryName: json['directoryName'] as String, + downloadUrl: json['downloadUrl'] as String, + ); + +Map _$$ImageModelImplToJson(_$ImageModelImpl instance) => + { + 'imageName': instance.imageName, + 'directoryName': instance.directoryName, + 'downloadUrl': instance.downloadUrl, + }; diff --git a/lib/pages/CustomListTile.dart b/lib/pages/CustomListTile.dart new file mode 100644 index 0000000..cfde1f0 --- /dev/null +++ b/lib/pages/CustomListTile.dart @@ -0,0 +1,37 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import '../model/UserModel.dart'; + +class CustomListTile extends StatelessWidget { + final int serialNumber; + final UserModel user; + final VoidCallback? onTap; + + const CustomListTile({super.key, + required this.serialNumber, + required this.user, + this.onTap, + }); + + @override + Widget build(BuildContext context) { + return Card( + elevation: 5, + margin: const EdgeInsets.symmetric(vertical: 8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + side: const BorderSide(color: Colors.black), + ), + child: ListTile( + onTap: onTap, // Invoke the onTap callback when the ListTile is tapped + title: Text("${user.firstName} ${user.lastName}"), + subtitle: Text('Address: ${user.address}'), + leading: CircleAvatar( + child: Text(serialNumber.toString()), + ), + trailing: Text('✮ ${user.rating}'), + ), + ); + } +} diff --git a/lib/pages/leaderBoardPage.dart b/lib/pages/leaderBoardPage.dart new file mode 100644 index 0000000..50241f4 --- /dev/null +++ b/lib/pages/leaderBoardPage.dart @@ -0,0 +1,107 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:provider/provider.dart'; +import 'package:retrieve_me/pages/userPage.dart'; +import '../Components/navigation_drawer_widget.dart'; +import '../provider/navigation_provider.dart'; +import '../provider/user_provider.dart'; +import 'CustomListTile.dart'; + +class LeaderBoardPage extends StatefulWidget { + static const String routeName = '/leaderBoard'; + const LeaderBoardPage({Key? key}) : super(key: key); + + @override + _LeaderBoardPageState createState() => _LeaderBoardPageState(); +} + +class _LeaderBoardPageState extends State { + GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (context) => NavigationProvider(), + child: Scaffold( + key: _scaffoldKey, + appBar: AppBar( + iconTheme: const IconThemeData( + color: Colors.white, + ), + title: const SafeArea( + + child: Text( + 'Leader Board', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + + + + flexibleSpace: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111), + ], + begin: FractionalOffset(0.0, 0.0), + end: FractionalOffset(1.0, 0.0), + stops: [0.0, 1.0], + tileMode: TileMode.clamp), + ), + ), + ), + drawer: const NavigationDrawerWidget(), + body: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111), + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: SingleChildScrollView( + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: Column( + children: [ + + Expanded( + child: Consumer( + builder: (context, provider, child) => ListView.builder( + itemCount: provider.userList.length, + itemBuilder: (context, index) { + final userX = provider.userList[index]; + return CustomListTile( + serialNumber: index + 1, + user: userX, + onTap: () { + // Add your navigation logic here + Navigator.pushNamed(context, UserPage.routeName, + arguments: userX); + + }, + ); + }, + ), + ), + ) + + + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/pages/login.dart b/lib/pages/login.dart index fa68f53..4bbcfa6 100644 --- a/lib/pages/login.dart +++ b/lib/pages/login.dart @@ -11,6 +11,7 @@ import 'package:retrieve_me/Components/my_textfield.dart'; import 'package:retrieve_me/Components/square_tile.dart'; import 'package:retrieve_me/firebase_options.dart'; import 'package:retrieve_me/pages/postLostItem.dart'; +import 'package:retrieve_me/pages/profilePage.dart'; import 'package:retrieve_me/pages/registration.dart'; import 'package:retrieve_me/provider/navigation_provider.dart'; @@ -259,7 +260,7 @@ class _LoginPageState extends State { EasyLoading.dismiss(); Navigator.of(context).push( MaterialPageRoute( - builder: (context) => const PostLostItemPage(), + builder: (context) => ProfilePage(), ), ); } on FirebaseAuthException catch (error) { diff --git a/lib/pages/profilePage.dart b/lib/pages/profilePage.dart new file mode 100644 index 0000000..b3593b5 --- /dev/null +++ b/lib/pages/profilePage.dart @@ -0,0 +1,331 @@ +import 'package:firebase_core/firebase_core.dart'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:provider/provider.dart'; +import 'package:retrieve_me/db/db_helper.dart'; +import 'package:retrieve_me/model/UserModel.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:retrieve_me/pages/leaderBoardPage.dart'; +import '../Components/navigation_drawer_widget.dart'; +import '../auth/auth_services.dart'; +import '../firebase_options.dart'; +import '../model/image_model.dart'; +import '../provider/navigation_provider.dart'; +import 'package:flutter/foundation.dart'; + +import '../provider/user_provider.dart'; + +GlobalKey _sKey = GlobalKey(); +final FirebaseAuth _auth = FirebaseAuth.instance; + +User? get currentUser => _auth.currentUser; + +class ProfilePage extends StatefulWidget { + ProfilePage({Key? key}) : super(key: key); + + @override + _ProfilePageState createState() => _ProfilePageState(); +} + +class _ProfilePageState extends State { + late UserModel userModel; + List userListX = []; + + @override + + @override + void initState() { + super.initState(); + + getUserInfo(); + } + @override + void didChangeDependencies() async{ + + + + + super.didChangeDependencies(); + Provider.of(context, listen: false).getAllUsers(); + userListX = UserProvider().userList; + await Future.delayed(const Duration(seconds: 5)); + } + + // Fetch user information from Firestore + void getUserInfo() async{ + + + db_helper.getUserInfo(AuthService.currentUser!.uid).listen((snapshot) { + if (snapshot.exists) { + setState(() { + userModel = UserModel.fromMap(snapshot.data()!); + }); + } + }); + } + + + @override + Widget build(BuildContext context) { + + return ChangeNotifierProvider( + create: (context) => NavigationProvider(), + child: Scaffold( + drawer: const NavigationDrawerWidget(), + key: _sKey, + body: FutureBuilder( + future: Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + return SafeArea( + child: SingleChildScrollView( + child: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111), + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + IconButton( + onPressed: () { + _sKey.currentState!.openDrawer(); + }, + icon: const Icon( + Icons.menu, + color: Colors.white, + size: 30, + ), + ), + ], + ), + Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Column( + children: [ + CircleAvatar( + radius: 70, + backgroundColor: Colors.transparent, + child: CachedNetworkImage( + imageUrl: userModel.thumbnailImage.downloadUrl, + imageBuilder: (context, imageProvider) => + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: imageProvider, + fit: BoxFit.cover, + ), + ), + ), + placeholder: (context, url) => const Center( + child: CircularProgressIndicator()), + errorWidget: (context, url, error) => + const Icon(Icons.error), + ), + ), + const SizedBox(height: 10), + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment + .center, + children: [ + Text( + '${userModel.firstName} ${userModel.lastName}', + style: GoogleFonts.oswald( + textStyle: const TextStyle( + fontSize: 32, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 5), + Text( + userModel.profession, + style: GoogleFonts.lato( + textStyle: const TextStyle( + fontSize: 20, + color: Colors.cyanAccent, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 5), + Text( + 'Points: ${userModel.rating}', + style: GoogleFonts.lato( + textStyle: const TextStyle( + fontSize: 20, + color: Colors.amberAccent, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 5), + Text( + userModel.address, + style: GoogleFonts.lato( + textStyle: const TextStyle( + fontSize: 20, + color: Colors.grey, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + + ], + ), + ), + ), + const SizedBox(height: 25), + Card( + elevation: 5, // Adjust the elevation as needed + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + side: const BorderSide(color: Colors.grey), + ), + child: InkWell( + onTap: () { + // Add your onTap logic here + print('Statistics Card Tapped'); + }, + child: Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Colors.cyan, Colors.indigo], + ), + borderRadius: BorderRadius.circular(15), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _buildStatColumn('Lost Items', '10'), + const SizedBox(width: 20), + _buildStatColumn('Found Items', '20'), + ], + ), + ), + ), + ), + + const SizedBox(height: 20), + GestureDetector( + onTap: () { + // Navigate to the leaderboard page here + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const LeaderBoardPage(), // Replace with the actual page + ), + ); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + border: Border.all(color: Colors.grey), + ), + padding: const EdgeInsets.all(16), + child: Card( + elevation: 5, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + side: const BorderSide(color: Colors.grey), + ), + child: InkWell( + onTap: () { + // Navigate to the leaderboard page or add your onTap logic here + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const LeaderBoardPage(), // Replace with the actual page + ), + ); + }, + child: Container( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'LEADERBOARD 👉', + style: GoogleFonts.oswald( + textStyle: const TextStyle( + fontSize: 35, + color: Colors.purple, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 10), + ], + ), + ), + ), + ), + ), + ), + ], + ), + ), + ), + ), + ); + + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + }), + ), + ); + } + + Widget _buildStatColumn(String title, String number) { + return Column( + children: [ + Text( + title, + style: const TextStyle(fontSize: 36, color: Colors.white), + ), + const SizedBox(height: 5), + Text( + number, + style: const TextStyle( + fontSize: 36, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ], + ); + } + +} diff --git a/lib/pages/registration.dart b/lib/pages/registration.dart index a10a4b6..2e9806e 100644 --- a/lib/pages/registration.dart +++ b/lib/pages/registration.dart @@ -1,5 +1,5 @@ // import 'dart:js_util'; - +import 'dart:io'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -29,15 +29,15 @@ class RegistrationPage extends StatefulWidget { class RegistrationPageState extends State { // TextEditingController registrationController = TextEditingController(); final TextEditingController firstNameController = TextEditingController(); - final TextEditingController lastNameController = TextEditingController(); - final TextEditingController contactNumberController = TextEditingController(); - final TextEditingController addressController = TextEditingController(); - final TextEditingController emailController = TextEditingController(); - final TextEditingController passwordController = TextEditingController(); - + final TextEditingController lastNameController = TextEditingController(); + final TextEditingController contactNumberController = TextEditingController(); + final TextEditingController addressController = TextEditingController(); + final TextEditingController emailController = TextEditingController(); + final TextEditingController passwordController = TextEditingController(); + final TextEditingController professionController = TextEditingController(); + String? imageLocalPath; XFile? selectedImage; - void _insertImage() async { final selector = ImagePicker(); final selectedFile = await selector.pickImage(source: ImageSource.gallery); @@ -53,21 +53,35 @@ class RegistrationPageState extends State { return firstNameController.text.isNotEmpty && lastNameController.text.isNotEmpty && contactNumberController.text.isNotEmpty && + professionController.text.isNotEmpty && addressController.text.isNotEmpty && emailController.text.isNotEmpty && - passwordController.text.isNotEmpty; - // && selectedImage != null; + passwordController.text.isNotEmpty && + imageLocalPath != null; } void _resetFields() { firstNameController.clear(); lastNameController.clear(); contactNumberController.clear(); + professionController.clear(); addressController.clear(); emailController.clear(); passwordController.clear(); + imageLocalPath = null; } + @override + void dispose() { + firstNameController.dispose(); + lastNameController.dispose(); + contactNumberController.dispose(); + professionController.dispose(); + addressController.dispose(); + emailController.dispose(); + passwordController.dispose(); + super.dispose(); + } @override Widget build(BuildContext context) { return Scaffold( @@ -93,6 +107,7 @@ class RegistrationPageState extends State { child: SingleChildScrollView( child: Column( children: [ + SizedBox( width: MediaQuery.of(context).size.width * 0.8, child: DrawerHeader( @@ -112,6 +127,44 @@ class RegistrationPageState extends State { ), ), const SizedBox(height: 16), + Card( + + child: Column( + children: [ + imageLocalPath == null + ? const Icon( + Icons.photo, + size: 100, + ) + : Image.file( + File(imageLocalPath!), + width: 100, + height: 100, + fit: BoxFit.cover, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton.icon( + onPressed: () { + getImage(ImageSource.camera); + }, + icon: const Icon(Icons.camera), + label: const Text('Capture'), + ), + TextButton.icon( + onPressed: () { + getImage(ImageSource.gallery); + }, + icon: const Icon(Icons.photo_album), + label: const Text('Gallery'), + ), + ], + ), + ], + ), + ), + const SizedBox(height: 16), MyTextField( controller: firstNameController, hintText: 'John', @@ -158,6 +211,16 @@ class RegistrationPageState extends State { keyboardType: TextInputType.text, ), const SizedBox(height: 16), + MyTextField( + controller: professionController, + hintText: + 'Zero Point, Chittagong University Road, New Mooring Chittagong', + obscureText: false, + prefixIcon: Icons.work, + labelText: 'profession', + keyboardType: TextInputType.text, + ), + const SizedBox(height: 16), MyTextField( controller: emailController, hintText: 'johnKais@email.com', @@ -175,24 +238,9 @@ class RegistrationPageState extends State { labelText: 'Password', keyboardType: TextInputType.text, ), - const SizedBox(height: 16), - SizedBox( - width: MediaQuery.of(context).size.width * 0.75, - height: MediaQuery.of(context).size.height * 0.075, - child: TextButton( - onPressed: _insertImage, - style: TextButton.styleFrom( - backgroundColor: Colors.cyan, - shadowColor: Colors.green, - ), - child: const Text('Insert Profile Image', - style: TextStyle( - color: Colors.brown, - fontWeight: FontWeight.bold, - )), - ), - ), - const SizedBox(height: 36), + + + const SizedBox(height:26), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -270,52 +318,62 @@ class RegistrationPageState extends State { }, )); } + void getImage(ImageSource source) async { + final file = + await ImagePicker().pickImage(source: source, imageQuality: 50); + if (file != null) { + setState(() { + imageLocalPath = file.path; + }); + } + } + void _submitRegistration() async { if (_areAllFieldsFilled()) { EasyLoading.show(status: 'File is uploading', dismissOnTap: false); final firstName = firstNameController.text; final lastName = lastNameController.text; + final profession = professionController.text; final contactNumber = contactNumberController.text; final address = addressController.text; final email = emailController.text; + final password = passwordController.text; try { User user; - user = await AuthService.registerUser(email, password,contactNumber); + user = await AuthService.registerUser(email, password, contactNumber); // String uid = user.uid; // UserModel? userModel; - Future addUser(User user) async{ + Future addUser(User user) async { try { + final imageModel = + await Provider.of(context, listen: false) + .uploadImage(imageLocalPath!); final userModel = UserModel( userId: user.uid, email: user.email!, - firstName : firstName, + firstName: firstName, + lastName: lastName, userCreationTime: Timestamp.fromDate(DateTime.now()), address: address, - profession: 'Student', + profession: profession, + rating: 0, contactNo: contactNumber, - + thumbnailImage: imageModel, ); await db_helper.addUser(userModel); - - } - catch(error){ + } catch (error) { print('Error adding user to Firestore: $error'); // Handle error accordingly } } + addUser(user); - // - // await Provider.of( - // - // - // context, listen: false).addUser(user); + EasyLoading.dismiss(); Navigator.pushReplacement( - - context, MaterialPageRoute( builder: (context) => const PostLostItemPage(), @@ -326,8 +384,6 @@ class RegistrationPageState extends State { // password: password, // ); showDialog( - - context: context, builder: (context) => AlertDialog( title: const Text('Registered Sucessfully!'), @@ -363,5 +419,4 @@ class RegistrationPageState extends State { ); } } - } diff --git a/lib/pages/userPage.dart b/lib/pages/userPage.dart new file mode 100644 index 0000000..715c1b9 --- /dev/null +++ b/lib/pages/userPage.dart @@ -0,0 +1,234 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import '../Components/navigation_drawer_widget.dart'; +import '../model/UserModel.dart'; +import '../provider/navigation_provider.dart'; +import 'leaderBoardPage.dart'; + +class UserPage extends StatefulWidget { + static const String routeName = '/userPage'; + + const UserPage({Key? key}) : super(key: key); + + @override + _UserPageState createState() => _UserPageState(); +} + +class _UserPageState extends State { + GlobalKey _scaffoldKey = GlobalKey(); + late UserModel userModel; + + @override + void didChangeDependencies() { + userModel = ModalRoute.of(context)!.settings.arguments as UserModel; + super.didChangeDependencies(); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (context) => NavigationProvider(), + child: Scaffold( + key: _scaffoldKey, + appBar: AppBar( + iconTheme: const IconThemeData( + color: Colors.white, + ), + title: SafeArea( + child: Text( + "${userModel.firstName} ${userModel.lastName}", + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + flexibleSpace: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111), + ], + begin: FractionalOffset(0.0, 0.0), + end: FractionalOffset(1.0, 0.0), + stops: [0.0, 1.0], + tileMode: TileMode.clamp, + ), + ), + ), + ), + drawer: const NavigationDrawerWidget(), + body: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111), + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: SingleChildScrollView( + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 10), + SizedBox( + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: double.infinity, + child: Column( + children: [ + CircleAvatar( + radius: 70, + backgroundColor: Colors.transparent, + child: CachedNetworkImage( + imageUrl: userModel.thumbnailImage.downloadUrl, + imageBuilder: (context, imageProvider) => Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: imageProvider, + fit: BoxFit.cover, + ), + ), + ), + placeholder: (context, url) => + const Center(child: CircularProgressIndicator()), + errorWidget: (context, url, error) => const Icon(Icons.error), + ), + ), + const SizedBox(height: 10), + ], + ), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + _buildText( + 'Name: ${userModel.firstName} ${userModel.lastName}', isHeader: true), + _buildText('Email: ${userModel.email}'), + _buildText('Profession: ${userModel.profession}'), + _buildText('Points: ${userModel.rating}'), + _buildText('Address: ${userModel.address}'), + _buildText('Creation Time: ' + '${_formatTimestamp(userModel + .userCreationTime)}'), + ], + ), + ), + const SizedBox(height: 20), + GestureDetector( + onTap: () { + // Navigate to the leaderboard page here + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const LeaderBoardPage(), // Replace with the actual page + ), + ); + }, + child: Center( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + border: Border.all(color: Colors.grey), + ), + padding: const EdgeInsets.all(16), + child: Card( + elevation: 5, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + side: const BorderSide(color: Colors.grey), + ), + child: InkWell( + onTap: () { + // Navigate to the leaderboard page or add your onTap logic here + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const LeaderBoardPage(), // Replace with the actual page + ), + ); + }, + child: Container( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '⬅️ LEADERBOARD', + style: GoogleFonts.oswald( + textStyle: const TextStyle( + fontSize: 35, + color: Colors.purple, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 10), + ], + ), + ), + ), + ), + ), + ) + ), + ], + ), + ), + + ]), + ), + ), + ))); + } + Widget _buildText(String text, {bool isHeader = false}) { + return Column( + children: [Text( + text, + style: GoogleFonts.oswald( + textStyle: TextStyle( + fontSize: isHeader ? 32 : 26, + color: Colors.white, + fontWeight: isHeader ? FontWeight.bold : FontWeight.normal, + ), + ), + ), + const SizedBox(height: 5), + ] + ); + + } + String _formatTimestamp(Timestamp? timestamp) { + if (timestamp == null) { + return 'N/A'; // or any default value for null timestamp + } + // Convert Firebase Timestamp to DateTime + DateTime dateTime = timestamp.toDate(); + + // Format DateTime to a desired format using intl package + String formattedDate = DateFormat.yMMMd().add_jm().format(dateTime); + + return formattedDate; + } + +} diff --git a/lib/provider/user_provider.dart b/lib/provider/user_provider.dart index 59f0122..9564b37 100644 --- a/lib/provider/user_provider.dart +++ b/lib/provider/user_provider.dart @@ -1,32 +1,52 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_storage/firebase_storage.dart'; +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:retrieve_me/db/db_helper.dart'; import '../auth/auth_services.dart'; import '../model/UserModel.dart'; +import '../model/image_model.dart'; class UserProvider extends ChangeNotifier { UserModel? userModel; - // Future addUser(User user) async{ + + + // Future addUser(User user,firstName,lastName,address,contactNumber) + // async{ // try { // final userModel = UserModel( // userId: user.uid, // email: user.email!, - // displayName: user.displayName!, + // firstName : firstName, + // lastName: lastName, // userCreationTime: Timestamp.fromDate(DateTime.now()), - // address: user.!, - // profession: user.photoURL!, - // contactNo: '01912345667', + // address: address, + // profession: 'Student', + // contactNo: contactNumber, // // ); // await db_helper.addUser(userModel); + // // } // catch(error){ // print('Error adding user to Firestore: $error'); // // Handle error accordingly // } + // // } + List userList = []; + + getAllUsers() { + db_helper.getAllUsers().listen((event) { + userList = List.generate(event.docs.length, (index) => + UserModel.fromMap(event.docs[index].data())); + print(userList.length); + notifyListeners(); + }); + } getUserInfo() { db_helper.getUserInfo(AuthService.currentUser!.uid).listen((snapshot) { @@ -34,8 +54,23 @@ class UserProvider extends ChangeNotifier { userModel = UserModel.fromMap(snapshot.data()!); notifyListeners(); } + }); } - + Future uploadImage(String imageLocalPath) async { + final String imageName = 'image_${DateTime.now().millisecondsSinceEpoch}'; + const String imageDirectory = 'Users/'; + final photoRef = FirebaseStorage.instance + .ref() + .child('$imageDirectory$imageName'); + final uploadTask = photoRef.putFile(File(imageLocalPath)); + final snapshot = await uploadTask.whenComplete(() => null); + final url = await snapshot.ref.getDownloadURL(); + return ImageModel( + imageName: imageName, + downloadUrl: url, + directoryName: imageDirectory, + ); + } Future doesUserExist(String uid) => db_helper.doesUserExist(uid); } \ No newline at end of file diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 630d0f8..25abfc5 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -12,6 +12,7 @@ import firebase_auth import firebase_core import firebase_storage import path_provider_foundation +import sqflite func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) @@ -21,4 +22,5 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 1f68857..c5411da 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + url: "https://pub.dev" + source: hosted + version: "64.0.0" _flutterfire_internals: dependency: transitive description: @@ -9,6 +17,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.16" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + url: "https://pub.dev" + source: hosted + version: "6.2.0" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" async: dependency: transitive description: @@ -25,6 +49,94 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + url: "https://pub.dev" + source: hosted + version: "4.0.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + url: "https://pub.dev" + source: hosted + version: "2.4.8" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185 + url: "https://pub.dev" + source: hosted + version: "7.2.11" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: c9aabae0718ec394e5bc3c7272e6bb0dc0b32201a08fe185ec1d8401d3e39309 + url: "https://pub.dev" + source: hosted + version: "8.8.1" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" + url: "https://pub.dev" + source: hosted + version: "1.1.1" characters: dependency: transitive description: @@ -33,6 +145,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" clock: dependency: transitive description: @@ -65,6 +185,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.9.0" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + url: "https://pub.dev" + source: hosted + version: "4.10.0" collapsible_sidebar: dependency: "direct main" description: @@ -81,6 +209,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" cross_file: dependency: transitive description: @@ -105,6 +241,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.6" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" + url: "https://pub.dev" + source: hosted + version: "2.3.4" date_time_picker: dependency: "direct main" description: @@ -129,6 +273,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" file_selector_linux: dependency: transitive description: @@ -257,11 +409,27 @@ packages: url: "https://pub.dev" source: hosted version: "3.6.17" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + url: "https://pub.dev" + source: hosted + version: "3.3.1" flutter_easyloading: dependency: "direct main" description: @@ -304,6 +472,38 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: "6c5031daae12c7072b3a87eff98983076434b4889ef2a44384d0cae3f82372ba" + url: "https://pub.dev" + source: hosted + version: "2.4.6" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + url: "https://pub.dev" + source: hosted + version: "2.4.1" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" google_fonts: dependency: "direct main" description: @@ -312,6 +512,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.1.0" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" http: dependency: transitive description: @@ -320,6 +528,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" http_parser: dependency: transitive description: @@ -393,13 +609,21 @@ packages: source: hosted version: "0.2.1+1" intl: - dependency: transitive + dependency: "direct main" description: name: intl sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" url: "https://pub.dev" source: hosted version: "0.17.0" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" js: dependency: "direct main" description: @@ -408,6 +632,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969 + url: "https://pub.dev" + source: hosted + version: "6.7.1" lints: dependency: transitive description: @@ -416,6 +656,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" matcher: dependency: transitive description: @@ -456,6 +704,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" path: dependency: transitive description: @@ -528,6 +792,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" provider: dependency: "direct main" description: @@ -536,11 +808,67 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.0" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" + source: hosted + version: "0.27.7" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + url: "https://pub.dev" + source: hosted + version: "1.3.4" source_span: dependency: transitive description: @@ -549,6 +877,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: bb4738f15b23352822f4c42a531677e5c6f522e079461fd240ead29d8d8a54a6 + url: "https://pub.dev" + source: hosted + version: "2.5.0+2" stack_trace: dependency: transitive description: @@ -565,6 +917,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" string_scanner: dependency: transitive description: @@ -573,6 +933,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" term_glyph: dependency: transitive description: @@ -589,6 +957,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.1" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" typed_data: dependency: transitive description: @@ -597,6 +973,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + uuid: + dependency: transitive + description: + name: uuid + sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 + url: "https://pub.dev" + source: hosted + version: "4.3.3" vector_math: dependency: transitive description: @@ -605,6 +989,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" web: dependency: transitive description: @@ -613,6 +1005,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" win32: dependency: transitive description: @@ -629,6 +1029,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: dart: ">=3.2.0 <4.0.0" flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 735ffdd..77247ad 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -43,10 +43,14 @@ dependencies: firebase_storage: firebase_analytics: ^10.4.4 image_picker: ^0.8.4 + cached_network_image: google_fonts: ^5.1.0 js: ^0.6.2 collapsible_sidebar: ^2.0.7 provider: ^5.0.0 + freezed_annotation: + json_annotation: + intl: ^0.17.0 dev_dependencies: flutter_test: @@ -58,6 +62,9 @@ dev_dependencies: # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^2.0.0 + freezed: + json_serializable: + build_runner: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec From 523b12f8e485e2e5082132cc62fcb02658ca0547 Mon Sep 17 00:00:00 2001 From: ImranIF Date: Wed, 24 Jan 2024 19:21:38 +0600 Subject: [PATCH 10/19] ignored google-services.json --- .gitignore | 1 + lib/Components/my_textfield.dart | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 70ccb97..c16e9cd 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ migrate_working_dir/ .pub-cache/ .pub/ /build/ +android/app/google-services.json # Symbolication related app.*.symbols diff --git a/lib/Components/my_textfield.dart b/lib/Components/my_textfield.dart index 55e330c..7aee875 100644 --- a/lib/Components/my_textfield.dart +++ b/lib/Components/my_textfield.dart @@ -10,7 +10,8 @@ class MyTextField extends StatelessWidget { final List? inputFormatters; // Added inputFormatters final TextInputType? keyboardType; // Made keyboardType optional - const MyTextField({super.key, + const MyTextField({ + super.key, required this.controller, required this.hintText, required this.obscureText, @@ -33,7 +34,8 @@ class MyTextField extends StatelessWidget { style: const TextStyle(color: Color.fromRGBO(150, 255, 210, 75)), decoration: InputDecoration( labelText: labelText, - labelStyle: const TextStyle(color: Color.fromARGB(255, 223, 206, 206)), + labelStyle: + const TextStyle(color: Color.fromARGB(255, 223, 206, 206)), prefixIcon: Icon(prefixIcon), prefixIconColor: const Color.fromRGBO(255, 255, 255, 100), border: const OutlineInputBorder( From f4f00feb66e26ad4936f287578b284ea35fd51e2 Mon Sep 17 00:00:00 2001 From: ImranIF Date: Wed, 24 Jan 2024 19:43:16 +0600 Subject: [PATCH 11/19] refactored --- pubspec.lock | 60 ++++++++++++---------------------------------------- 1 file changed, 14 insertions(+), 46 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 72a5187..7f39801 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -125,10 +125,10 @@ packages: dependency: transitive description: name: ffi - sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.0" file_selector_linux: dependency: transitive description: @@ -392,30 +392,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: f8cdf1383f5b4672a2693d875f1f239af6bd7e4a8925a17ef7219226db932624 - url: "https://pub.dev" - source: hosted - version: "10.0.1" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: a2055640bf5bc903475e4bbdb34e04f8bf698542bee41edec47d337a5939e1ae - url: "https://pub.dev" - source: hosted - version: "2.0.3" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: e62042d479c4c139dd774125ed4dfbde646b8f07ac228e3c1b57a3d91d6d9df4 - url: "https://pub.dev" - source: hosted - version: "2.0.2" lints: dependency: transitive description: @@ -428,26 +404,26 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.10.0" mime: dependency: transitive description: @@ -468,10 +444,10 @@ packages: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.8.3" path_provider: dependency: transitive description: @@ -613,22 +589,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 - url: "https://pub.dev" - source: hosted - version: "13.0.0" web: dependency: transitive description: name: web - sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05" + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 url: "https://pub.dev" source: hosted - version: "0.4.2" + version: "0.3.0" widget_zoom: dependency: "direct main" description: @@ -654,5 +622,5 @@ packages: source: hosted version: "1.0.4" sdks: - dart: ">=3.3.0-279.1.beta <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.2.0 <4.0.0" + flutter: ">=3.10.0" From f6d6b14038a000fe3e9a1ac4655695a7e575d8fe Mon Sep 17 00:00:00 2001 From: ImranIF Date: Sat, 27 Jan 2024 19:46:03 +0600 Subject: [PATCH 12/19] Added nearby location of lost or found item --- android/app/src/main/AndroidManifest.xml | 1 + lib/Components/navigation_drawer_widget.dart | 7 +- lib/pages/foundItemList.dart | 63 +++++++ lib/pages/lostItemList.dart | 67 +++++++ lib/pages/mapscreen.dart | 95 ++++++++++ lib/pages/postFoundItem.dart | 176 ++++++++++-------- lib/pages/postLostItem.dart | 175 +++++++++-------- lib/pages/userPage.dart | 159 ++++++++-------- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 170 ++++++++++++++++- pubspec.yaml | 3 + .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 15 files changed, 685 insertions(+), 242 deletions(-) create mode 100644 lib/pages/mapscreen.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index c0f7c85..e4c5c5f 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -30,4 +30,5 @@ android:name="flutterEmbedding" android:value="2" /> + diff --git a/lib/Components/navigation_drawer_widget.dart b/lib/Components/navigation_drawer_widget.dart index 9d6669f..995e533 100644 --- a/lib/Components/navigation_drawer_widget.dart +++ b/lib/Components/navigation_drawer_widget.dart @@ -7,6 +7,7 @@ import 'package:retrieve_me/pages/foundItemList.dart'; import 'package:retrieve_me/pages/lostItemList.dart'; import 'package:retrieve_me/pages/postFoundItem.dart'; import 'package:retrieve_me/pages/postLostItem.dart'; +import 'package:retrieve_me/pages/profilePage.dart'; import '../pages/login.dart'; import '../provider/navigation_provider.dart'; @@ -25,12 +26,10 @@ class NavigationDrawerWidget extends StatelessWidget { return SizedBox( width: isCollapsed ? MediaQuery.of(context).size.width * 0.15 : null, child: Drawer( - child: Container( color: const Color(0xFF1a2f45), child: ListView( physics: ClampingScrollPhysics(), - children: [ Container( padding: @@ -67,7 +66,6 @@ class NavigationDrawerWidget extends StatelessWidget { ], )), ), - ); } @@ -174,6 +172,9 @@ class NavigationDrawerWidget extends StatelessWidget { case 'Found Item List': navigateTo(const FoundItemListPage()); break; + case 'User Dashboard': + navigateTo(ProfilePage()); + break; case 'Logout': navigateTo(LoginPage()); break; diff --git a/lib/pages/foundItemList.dart b/lib/pages/foundItemList.dart index 09752b3..05f29bc 100644 --- a/lib/pages/foundItemList.dart +++ b/lib/pages/foundItemList.dart @@ -3,6 +3,7 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:retrieve_me/Components/navigation_drawer_widget.dart'; +import 'package:retrieve_me/pages/mapscreen.dart'; import 'package:retrieve_me/provider/navigation_provider.dart'; import 'package:intl/intl.dart'; import 'package:widget_zoom/widget_zoom.dart'; @@ -198,6 +199,68 @@ class _FoundItemListPageState extends State { fontSize: 12.0, ), ), + const SizedBox( + height: 10, + ), + SizedBox( + height: + MediaQuery.of(context).size.height * 0.05, + width: + MediaQuery.of(context).size.width * 0.350, + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MapScreen( + address: ds['ItemLocation']), + )); + }, + style: ElevatedButton.styleFrom( + backgroundColor: + Color.fromARGB(255, 149, 202, 223), + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Location', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.70, + ), + ), + ), + ), + const SizedBox( + height: 10, + ), + SizedBox( + height: + MediaQuery.of(context).size.height * 0.05, + width: + MediaQuery.of(context).size.width * 0.350, + child: ElevatedButton( + onPressed: () { + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) => ChatPage()); + }, + style: ElevatedButton.styleFrom( + backgroundColor: + Color.fromARGB(255, 149, 202, 223), + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Assert a Claim', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.70, + ), + ), + ), + ) ]), ], )), diff --git a/lib/pages/lostItemList.dart b/lib/pages/lostItemList.dart index 324a369..405ef92 100644 --- a/lib/pages/lostItemList.dart +++ b/lib/pages/lostItemList.dart @@ -1,8 +1,11 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:provider/provider.dart'; +import 'package:retrieve_me/Components/my_button.dart'; import 'package:retrieve_me/Components/navigation_drawer_widget.dart'; +import 'package:retrieve_me/pages/mapscreen.dart'; import 'package:retrieve_me/provider/navigation_provider.dart'; import 'package:intl/intl.dart'; import 'package:widget_zoom/widget_zoom.dart'; @@ -199,6 +202,70 @@ class _LostItemListPageState extends State { fontSize: 12.0, ), ), + const SizedBox( + height: 10, + ), + SizedBox( + height: + MediaQuery.of(context).size.height * 0.05, + width: + MediaQuery.of(context).size.width * 0.350, + child: ElevatedButton( + onPressed: () async { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MapScreen( + address: ds['ItemLocation']), + )); + }, + style: ElevatedButton.styleFrom( + backgroundColor: + Color.fromARGB(255, 149, 202, 223), + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Location', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.70, + ), + ), + ), + ), + const SizedBox( + height: 10, + ), + SizedBox( + height: + MediaQuery.of(context).size.height * 0.05, + width: + MediaQuery.of(context).size.width * 0.350, + child: ElevatedButton( + onPressed: () { + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) => MapScreen( + // address: ds['CityLocation']), + // )); + }, + style: ElevatedButton.styleFrom( + backgroundColor: + Color.fromARGB(255, 149, 202, 223), + // splashFactory: InkRipple.splashFactory, + ), + child: const Text( + 'Assert a Claim', + style: TextStyle( + color: Colors.deepPurple, + fontWeight: FontWeight.bold, + fontSize: Checkbox.width * 0.70, + ), + ), + ), + ) ]), ], )), diff --git a/lib/pages/mapscreen.dart b/lib/pages/mapscreen.dart new file mode 100644 index 0000000..530dc79 --- /dev/null +++ b/lib/pages/mapscreen.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:geocoding/geocoding.dart'; +import 'package:flutter_map/flutter_map.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:latlong2/latlong.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class MapScreen extends StatefulWidget { + final String address; + const MapScreen({super.key, required this.address}); + @override + _MapScreenState createState() => _MapScreenState(); +} + +Future Wait() async { + EasyLoading.show(status: 'loading...'); + await Future.delayed(Duration(seconds: 1)); + EasyLoading.dismiss(); +} + +class _MapScreenState extends State { + double? latitude; + double? longitude; + + @override + void initState() { + super.initState(); + getLocationFromAddress(); + // Wait(); + } + + Future getLocationFromAddress() async { + try { + List locations = await locationFromAddress(widget.address); + setState(() { + latitude = locations.first.latitude; + longitude = locations.first.longitude; + }); + } catch (e) { + print("Error: $e"); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RichText( + text: const TextSpan( + text: 'Location of Item', + style: TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.bold))), + SizedBox(height: 16), + if (latitude != null && longitude != null) ...[ + Container( + height: 300, + width: double.infinity, + child: FlutterMap( + options: MapOptions( + center: LatLng(latitude!, longitude!), + zoom: 13.0, + ), + children: [ + TileLayer( + urlTemplate: + "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + subdomains: ['a', 'b', 'c'], + ), + RichAttributionWidget( + attributions: [ + TextSourceAttribution( + 'OpenStreetMap contributors', + onTap: () => launchUrl( + Uri.parse('https://openstreetmap.org/copyright')), + ), + ], + ) + ], + ), + ), + ] else if (latitude == null && longitude == null) ...[ + const CircularProgressIndicator(), + ] + ], + ), + ), + ); + } +} diff --git a/lib/pages/postFoundItem.dart b/lib/pages/postFoundItem.dart index 55f845e..6095575 100644 --- a/lib/pages/postFoundItem.dart +++ b/lib/pages/postFoundItem.dart @@ -28,10 +28,11 @@ class _PostFoundItemPageState extends State { TextEditingController whatWasFound = TextEditingController(); TextEditingController itemCategory = TextEditingController(); TextEditingController additionalInfo = TextEditingController(); - TextEditingController cityController = TextEditingController(); - TextEditingController divisionController = TextEditingController(); - TextEditingController unionVillageController = TextEditingController(); - TextEditingController streetHouseController = TextEditingController(); + TextEditingController itemLocationController = TextEditingController(); + // TextEditingController cityController = TextEditingController(); + // TextEditingController divisionController = TextEditingController(); + // TextEditingController unionVillageController = TextEditingController(); + // TextEditingController streetHouseController = TextEditingController(); DateTime? dateTimeController = DateTime.now(); late String imgURL; @@ -65,10 +66,11 @@ class _PostFoundItemPageState extends State { return whatWasFound.text.isNotEmpty && itemCategory.text.isNotEmpty && additionalInfo.text.isNotEmpty && - cityController.text.isNotEmpty && - divisionController.text.isNotEmpty && - unionVillageController.text.isNotEmpty && - streetHouseController.text.isNotEmpty && + itemLocationController.text.isNotEmpty && + // cityController.text.isNotEmpty && + // divisionController.text.isNotEmpty && + // unionVillageController.text.isNotEmpty && + // streetHouseController.text.isNotEmpty && selectedImage != null && dateTimeController != null; } @@ -89,10 +91,11 @@ class _PostFoundItemPageState extends State { 'Category': itemCategory.text, 'DateTime': dateTimeTimestamp, 'Description': additionalInfo.text, - 'CityLocation': cityController.text, - 'DivisionLocation': divisionController.text, - 'UnionVillageLocation': unionVillageController.text, - 'StreetHouseLocation': streetHouseController.text, + 'ItemLocation': itemLocationController.text, + // 'CityLocation': cityController.text, + // 'DivisionLocation': divisionController.text, + // 'UnionVillageLocation': unionVillageController.text, + // 'StreetHouseLocation': streetHouseController.text, 'ImageURL': imgURL, }; await collectionReference.add(foundItemData); @@ -274,77 +277,86 @@ class _PostFoundItemPageState extends State { keyboardType: TextInputType.emailAddress, ), const SizedBox(height: 16), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceAround, - children: [ - // City - SizedBox( - width: MediaQuery.of(context).size.width * - 0.25, - child: MyTextField( - controller: divisionController, - hintText: 'Chittagong', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Division', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[a-zA-Z. ]')) - ], - ), - ), - SizedBox( - width: MediaQuery.of(context).size.width * - 0.25, - child: MyTextField( - controller: cityController, - hintText: 'Hathazari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'City', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[a-zA-Z. ]')) - ], - ), - ) - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceAround, - children: [ - // City - SizedBox( - width: MediaQuery.of(context).size.width * - 0.25, - child: MyTextField( - controller: streetHouseController, - hintText: 'Road no: 3, House no: 7', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Street/House No.', - keyboardType: TextInputType.streetAddress, - ), - ), - SizedBox( - width: MediaQuery.of(context).size.width * - 0.25, - child: MyTextField( - controller: unionVillageController, - hintText: 'Fatikchhari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Union/Village', - keyboardType: TextInputType.streetAddress, - ), - ) - ], + + MyTextField( + controller: itemLocationController, + hintText: 'Chittagong University Museum', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Location of item found', + keyboardType: TextInputType.streetAddress, ), + // Row( + // mainAxisAlignment: + // MainAxisAlignment.spaceAround, + // children: [ + // // City + // SizedBox( + // width: MediaQuery.of(context).size.width * + // 0.25, + // child: MyTextField( + // controller: divisionController, + // hintText: 'Chittagong', + // obscureText: false, + // prefixIcon: Icons.location_city, + // labelText: 'Division', + // keyboardType: TextInputType.streetAddress, + // inputFormatters: [ + // FilteringTextInputFormatter.allow( + // RegExp(r'[a-zA-Z. ]')) + // ], + // ), + // ), + // SizedBox( + // width: MediaQuery.of(context).size.width * + // 0.25, + // child: MyTextField( + // controller: cityController, + // hintText: 'Hathazari', + // obscureText: false, + // prefixIcon: Icons.location_city, + // labelText: 'City', + // keyboardType: TextInputType.streetAddress, + // inputFormatters: [ + // FilteringTextInputFormatter.allow( + // RegExp(r'[a-zA-Z. ]')) + // ], + // ), + // ) + // ], + // ), + // const SizedBox(height: 16), + // Row( + // mainAxisAlignment: + // MainAxisAlignment.spaceAround, + // children: [ + // // City + // SizedBox( + // width: MediaQuery.of(context).size.width * + // 0.25, + // child: MyTextField( + // controller: streetHouseController, + // hintText: 'Road no: 3, House no: 7', + // obscureText: false, + // prefixIcon: Icons.location_city, + // labelText: 'Street/House No.', + // keyboardType: TextInputType.streetAddress, + // ), + // ), + // SizedBox( + // width: MediaQuery.of(context).size.width * + // 0.25, + // child: MyTextField( + // controller: unionVillageController, + // hintText: 'Fatikchhari', + // obscureText: false, + // prefixIcon: Icons.location_city, + // labelText: 'Union/Village', + // keyboardType: TextInputType.streetAddress, + // ), + // ) + // ], + // ), const SizedBox(height: 16), MyTextField( controller: additionalInfo, diff --git a/lib/pages/postLostItem.dart b/lib/pages/postLostItem.dart index e8183b1..350d040 100644 --- a/lib/pages/postLostItem.dart +++ b/lib/pages/postLostItem.dart @@ -40,10 +40,11 @@ class _PostLostItemPageState extends State { TextEditingController whatWasLost = TextEditingController(); TextEditingController itemCategory = TextEditingController(); TextEditingController additionalInfo = TextEditingController(); - TextEditingController cityController = TextEditingController(); - TextEditingController divisionController = TextEditingController(); - TextEditingController unionVillageController = TextEditingController(); - TextEditingController streetHouseController = TextEditingController(); + TextEditingController itemLocationController = TextEditingController(); + // TextEditingController cityController = TextEditingController(); + // TextEditingController divisionController = TextEditingController(); + // TextEditingController unionVillageController = TextEditingController(); + // TextEditingController streetHouseController = TextEditingController(); DateTime? dateTimeController = DateTime.now(); late String imgURL; @@ -80,10 +81,11 @@ class _PostLostItemPageState extends State { return whatWasLost.text.isNotEmpty && itemCategory.text.isNotEmpty && additionalInfo.text.isNotEmpty && - cityController.text.isNotEmpty && - divisionController.text.isNotEmpty && - unionVillageController.text.isNotEmpty && - streetHouseController.text.isNotEmpty && + itemLocationController.text.isNotEmpty && + // cityController.text.isNotEmpty && + // divisionController.text.isNotEmpty && + // unionVillageController.text.isNotEmpty && + // streetHouseController.text.isNotEmpty && selectedImage != null && dateTimeController != null; } @@ -104,10 +106,11 @@ class _PostLostItemPageState extends State { 'Category': itemCategory.text, 'DateTime': dateTimeTimestamp, 'Description': additionalInfo.text, - 'CityLocation': cityController.text, - 'DivisionLocation': divisionController.text, - 'UnionVillageLocation': unionVillageController.text, - 'StreetHouseLocation': streetHouseController.text, + 'ItemLocation': itemLocationController.text, + // 'CityLocation': cityController.text, + // 'DivisionLocation': divisionController.text, + // 'UnionVillageLocation': unionVillageController.text, + // 'StreetHouseLocation': streetHouseController.text, 'ImageURL': imgURL, }; DocumentReference docId = await collectionReference.add(lostItemData); @@ -323,75 +326,87 @@ class _PostLostItemPageState extends State { keyboardType: TextInputType.emailAddress, ), const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - SizedBox( - width: - MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: divisionController, - hintText: 'Chittagong', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Division', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[a-zA-Z. ]')) - ], - ), - ), - SizedBox( - width: - MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: cityController, - hintText: 'Hathazari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'City', - keyboardType: TextInputType.streetAddress, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[a-zA-Z. ]')) - ], - ), - ) - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - // City - SizedBox( - width: - MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: streetHouseController, - hintText: 'Road no: 3, House no: 7', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Street/House No.', - keyboardType: TextInputType.streetAddress, - ), - ), - SizedBox( - width: - MediaQuery.of(context).size.width * 0.25, - child: MyTextField( - controller: unionVillageController, - hintText: 'Fatikchhari', - obscureText: false, - prefixIcon: Icons.location_city, - labelText: 'Union/Village', - keyboardType: TextInputType.streetAddress, - ), - ) - ], + MyTextField( + controller: itemLocationController, + hintText: 'Chittagong University Museum', + obscureText: false, + prefixIcon: Icons.location_city, + labelText: 'Location of item lost', + keyboardType: TextInputType.streetAddress, + // inputFormatters: [ + // FilteringTextInputFormatter.allow( + // RegExp(r'[a-zA-Z. ]')) + // ], ), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceAround, + // children: [ + // // City + // SizedBox( + // width: + // MediaQuery.of(context).size.width * 0.25, + // child: MyTextField( + // controller: divisionController, + // hintText: 'Chittagong', + // obscureText: false, + // prefixIcon: Icons.location_city, + // labelText: 'Division', + // keyboardType: TextInputType.streetAddress, + // inputFormatters: [ + // FilteringTextInputFormatter.allow( + // RegExp(r'[a-zA-Z. ]')) + // ], + // ), + // ), + // SizedBox( + // width: + // MediaQuery.of(context).size.width * 0.25, + // child: MyTextField( + // controller: cityController, + // hintText: 'Hathazari', + // obscureText: false, + // prefixIcon: Icons.location_city, + // labelText: 'City', + // keyboardType: TextInputType.streetAddress, + // inputFormatters: [ + // FilteringTextInputFormatter.allow( + // RegExp(r'[a-zA-Z. ]')) + // ], + // ), + // ) + // ], + // ), + // const SizedBox(height: 16), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceAround, + // children: [ + // // City + // SizedBox( + // width: + // MediaQuery.of(context).size.width * 0.25, + // child: MyTextField( + // controller: streetHouseController, + // hintText: 'Road no: 3, House no: 7', + // obscureText: false, + // prefixIcon: Icons.location_city, + // labelText: 'Street/House No.', + // keyboardType: TextInputType.streetAddress, + // ), + // ), + // SizedBox( + // width: + // MediaQuery.of(context).size.width * 0.25, + // child: MyTextField( + // controller: unionVillageController, + // hintText: 'Fatikchhari', + // obscureText: false, + // prefixIcon: Icons.location_city, + // labelText: 'Union/Village', + // keyboardType: TextInputType.streetAddress, + // ), + // ) + // ], + // ), const SizedBox(height: 16), MyTextField( controller: additionalInfo, diff --git a/lib/pages/userPage.dart b/lib/pages/userPage.dart index 715c1b9..a51102a 100644 --- a/lib/pages/userPage.dart +++ b/lib/pages/userPage.dart @@ -94,8 +94,11 @@ class _UserPageState extends State { radius: 70, backgroundColor: Colors.transparent, child: CachedNetworkImage( - imageUrl: userModel.thumbnailImage.downloadUrl, - imageBuilder: (context, imageProvider) => Container( + imageUrl: userModel + .thumbnailImage.downloadUrl, + imageBuilder: + (context, imageProvider) => + Container( decoration: BoxDecoration( shape: BoxShape.circle, image: DecorationImage( @@ -105,8 +108,11 @@ class _UserPageState extends State { ), ), placeholder: (context, url) => - const Center(child: CircularProgressIndicator()), - errorWidget: (context, url, error) => const Icon(Icons.error), + const Center( + child: + CircularProgressIndicator()), + errorWidget: (context, url, error) => + const Icon(Icons.error), ), ), const SizedBox(height: 10), @@ -118,106 +124,108 @@ class _UserPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildText( - 'Name: ${userModel.firstName} ${userModel.lastName}', isHeader: true), + 'Name: ${userModel.firstName} ${userModel.lastName}', + isHeader: true), _buildText('Email: ${userModel.email}'), - _buildText('Profession: ${userModel.profession}'), + _buildText( + 'Profession: ${userModel.profession}'), _buildText('Points: ${userModel.rating}'), _buildText('Address: ${userModel.address}'), _buildText('Creation Time: ' - '${_formatTimestamp(userModel - .userCreationTime)}'), + '${_formatTimestamp(userModel.userCreationTime)}'), ], ), ), const SizedBox(height: 20), GestureDetector( - onTap: () { - // Navigate to the leaderboard page here - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - const LeaderBoardPage(), // Replace with the actual page - ), - ); - }, - child: Center( - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(15), - border: Border.all(color: Colors.grey), - ), - padding: const EdgeInsets.all(16), - child: Card( - elevation: 5, - shape: RoundedRectangleBorder( + onTap: () { + // Navigate to the leaderboard page here + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const LeaderBoardPage(), // Replace with the actual page + ), + ); + }, + child: Center( + child: Container( + decoration: BoxDecoration( + color: Colors.white, borderRadius: BorderRadius.circular(15), - side: const BorderSide(color: Colors.grey), + border: Border.all(color: Colors.grey), ), - child: InkWell( - onTap: () { - // Navigate to the leaderboard page or add your onTap logic here - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - const LeaderBoardPage(), // Replace with the actual page - ), - ); - }, - child: Container( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '⬅️ LEADERBOARD', - style: GoogleFonts.oswald( - textStyle: const TextStyle( - fontSize: 35, - color: Colors.purple, - fontWeight: FontWeight.bold, + padding: const EdgeInsets.all(16), + child: Card( + elevation: 5, + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(15), + side: const BorderSide( + color: Colors.grey), + ), + child: InkWell( + onTap: () { + // Navigate to the leaderboard page or add your onTap logic here + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const LeaderBoardPage(), // Replace with the actual page + ), + ); + }, + child: Container( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + '⬅️ LEADERBOARD', + style: GoogleFonts.oswald( + textStyle: const TextStyle( + fontSize: 35, + color: Colors.purple, + fontWeight: + FontWeight.bold, + ), ), ), - ), - const SizedBox(height: 10), - ], + const SizedBox(height: 10), + ], + ), ), ), ), ), - ), - ) - ), + )), ], ), ), - ]), ), ), ))); } + Widget _buildText(String text, {bool isHeader = false}) { - return Column( - children: [Text( - text, - style: GoogleFonts.oswald( - textStyle: TextStyle( - fontSize: isHeader ? 32 : 26, - color: Colors.white, - fontWeight: isHeader ? FontWeight.bold : FontWeight.normal, - ), + return Column(children: [ + Text( + text, + style: GoogleFonts.oswald( + textStyle: TextStyle( + fontSize: isHeader ? 32 : 26, + color: Colors.white, + fontWeight: isHeader ? FontWeight.bold : FontWeight.normal, ), - ), - const SizedBox(height: 5), - ] - ); - + ), + ), + const SizedBox(height: 5), + ]); } + String _formatTimestamp(Timestamp? timestamp) { if (timestamp == null) { return 'N/A'; // or any default value for null timestamp @@ -230,5 +238,4 @@ class _UserPageState extends State { return formattedDate; } - } diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 64a0ece..7299b5c 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -7,9 +7,13 @@ #include "generated_plugin_registrant.h" #include +#include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 2db3c22..786ff5c 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_linux + url_launcher_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 25abfc5..667e7a7 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -13,6 +13,7 @@ import firebase_core import firebase_storage import path_provider_foundation import sqflite +import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) @@ -23,4 +24,5 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index b144755..a60fe11 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -446,6 +446,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + flutter_map: + dependency: "direct main" + description: + name: flutter_map + sha256: cda8d72135b697f519287258b5294a57ce2f2a5ebf234f0e406aad4dc14c9399 + url: "https://pub.dev" + source: hosted + version: "6.1.0" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -496,6 +504,38 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.0" + geocoding: + dependency: "direct main" + description: + name: geocoding + sha256: e1dc0ac56666d9ed1d5a9ae5543ce9eb5986db6209cc7600103487d09192059c + url: "https://pub.dev" + source: hosted + version: "2.1.1" + geocoding_android: + dependency: transitive + description: + name: geocoding_android + sha256: "609db1d71bc364dd9d0616f72a41c01e0c74f3a3807efb85e0d5a67e57baf50f" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + geocoding_ios: + dependency: transitive + description: + name: geocoding_ios + sha256: "8f79e380abb640ef4d88baee8bb65390058c802601158d0813dc990b36b189d2" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + geocoding_platform_interface: + dependency: transitive + description: + name: geocoding_platform_interface + sha256: "8848605d307d844d89937cdb4b8ad7dfa880552078f310fa24d8a460f6dddab4" + url: "https://pub.dev" + source: hosted + version: "2.0.1" glob: dependency: transitive description: @@ -648,6 +688,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.7.1" + latlong2: + dependency: transitive + description: + name: latlong2 + sha256: "18712164760cee655bc790122b0fd8f3d5b3c36da2cb7bf94b68a197fbb0811b" + url: "https://pub.dev" + source: hosted + version: "0.9.0" lints: dependency: transitive description: @@ -656,6 +704,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + lists: + dependency: transitive + description: + name: lists + sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + logger: + dependency: transitive + description: + name: logger + sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac" + url: "https://pub.dev" + source: hosted + version: "2.0.2+1" logging: dependency: transitive description: @@ -688,6 +752,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" + mgrs_dart: + dependency: transitive + description: + name: mgrs_dart + sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 + url: "https://pub.dev" + source: hosted + version: "2.0.0" mime: dependency: transitive description: @@ -792,6 +864,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.7" + polylabel: + dependency: transitive + description: + name: polylabel + sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b" + url: "https://pub.dev" + source: hosted + version: "1.0.1" pool: dependency: transitive description: @@ -800,6 +880,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + proj4dart: + dependency: transitive + description: + name: proj4dart + sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e + url: "https://pub.dev" + source: hosted + version: "2.1.0" provider: dependency: "direct main" description: @@ -973,6 +1061,78 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + unicode: + dependency: transitive + description: + name: unicode + sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c + url: "https://pub.dev" + source: hosted + version: "6.2.4" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f" + url: "https://pub.dev" + source: hosted + version: "6.2.2" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" + url: "https://pub.dev" + source: hosted + version: "6.2.4" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 + url: "https://pub.dev" + source: hosted + version: "3.1.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234 + url: "https://pub.dev" + source: hosted + version: "3.1.0" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f + url: "https://pub.dev" + source: hosted + version: "2.3.1" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b + url: "https://pub.dev" + source: hosted + version: "2.2.3" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 + url: "https://pub.dev" + source: hosted + version: "3.1.1" uuid: dependency: transitive description: @@ -1029,6 +1189,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.2.0" + wkt_parser: + dependency: transitive + description: + name: wkt_parser + sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13" + url: "https://pub.dev" + source: hosted + version: "2.0.0" xdg_directories: dependency: transitive description: @@ -1047,4 +1215,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.2.0 <4.0.0" - flutter: ">=3.10.0" + flutter: ">=3.16.0" diff --git a/pubspec.yaml b/pubspec.yaml index 22833b9..7bb76cf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -52,6 +52,9 @@ dependencies: freezed_annotation: json_annotation: intl: ^0.17.0 + geocoding: ^2.0.0 + flutter_map: ^6.1.0 + url_launcher: ^6.2.4 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index ec1e463..3e6795e 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -11,6 +11,7 @@ #include #include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { CloudFirestorePluginCApiRegisterWithRegistrar( @@ -23,4 +24,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); FirebaseStoragePluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FirebaseStoragePluginCApi")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 767b528..9615bc9 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST firebase_auth firebase_core firebase_storage + url_launcher_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST From ee2f3d0ae3fcd2b5ab92a080353d76f0196e76fc Mon Sep 17 00:00:00 2001 From: ImranIF Date: Sat, 27 Jan 2024 21:44:57 +0600 Subject: [PATCH 13/19] added isRetrieved and userId --- lib/pages/login.dart | 4 ++-- lib/pages/postFoundItem.dart | 17 +++++------------ lib/pages/postLostItem.dart | 17 +++++------------ lib/pages/profilePage.dart | 16 ++++++++-------- 4 files changed, 20 insertions(+), 34 deletions(-) diff --git a/lib/pages/login.dart b/lib/pages/login.dart index 4bbcfa6..5cd52d2 100644 --- a/lib/pages/login.dart +++ b/lib/pages/login.dart @@ -152,7 +152,6 @@ class _LoginPageState extends State { child: Text("Log In"), ), - const SizedBox(height: 50), // Removed 'const' // or continue with @@ -258,12 +257,13 @@ class _LoginPageState extends State { try { final User user = await AuthService.loginAdmin(email, password); EasyLoading.dismiss(); + // ignore: use_build_context_synchronously Navigator.of(context).push( MaterialPageRoute( builder: (context) => ProfilePage(), ), ); - } on FirebaseAuthException catch (error) { + } on FirebaseAuthException catch (error) { EasyLoading.dismiss(); setState(() { _errMsg = error.message!; diff --git a/lib/pages/postFoundItem.dart b/lib/pages/postFoundItem.dart index 6095575..9fd4cc7 100644 --- a/lib/pages/postFoundItem.dart +++ b/lib/pages/postFoundItem.dart @@ -9,6 +9,7 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; import 'package:image_picker/image_picker.dart'; import 'package:date_time_picker/date_time_picker.dart'; +import 'package:retrieve_me/auth/auth_services.dart'; import '../Components/my_textfield.dart'; import '../Components/navigation_drawer_widget.dart'; import '../firebase_options.dart'; @@ -29,10 +30,8 @@ class _PostFoundItemPageState extends State { TextEditingController itemCategory = TextEditingController(); TextEditingController additionalInfo = TextEditingController(); TextEditingController itemLocationController = TextEditingController(); - // TextEditingController cityController = TextEditingController(); - // TextEditingController divisionController = TextEditingController(); - // TextEditingController unionVillageController = TextEditingController(); - // TextEditingController streetHouseController = TextEditingController(); + String userID = AuthService.currentUser!.uid; + bool isRetrieved = false; DateTime? dateTimeController = DateTime.now(); late String imgURL; @@ -67,10 +66,6 @@ class _PostFoundItemPageState extends State { itemCategory.text.isNotEmpty && additionalInfo.text.isNotEmpty && itemLocationController.text.isNotEmpty && - // cityController.text.isNotEmpty && - // divisionController.text.isNotEmpty && - // unionVillageController.text.isNotEmpty && - // streetHouseController.text.isNotEmpty && selectedImage != null && dateTimeController != null; } @@ -92,11 +87,9 @@ class _PostFoundItemPageState extends State { 'DateTime': dateTimeTimestamp, 'Description': additionalInfo.text, 'ItemLocation': itemLocationController.text, - // 'CityLocation': cityController.text, - // 'DivisionLocation': divisionController.text, - // 'UnionVillageLocation': unionVillageController.text, - // 'StreetHouseLocation': streetHouseController.text, 'ImageURL': imgURL, + 'userID': userID, + 'isRetrieved': isRetrieved, }; await collectionReference.add(foundItemData); diff --git a/lib/pages/postLostItem.dart b/lib/pages/postLostItem.dart index 350d040..95c0d9a 100644 --- a/lib/pages/postLostItem.dart +++ b/lib/pages/postLostItem.dart @@ -7,6 +7,7 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; +import 'package:retrieve_me/auth/auth_services.dart'; import 'package:retrieve_me/pages/login.dart'; import 'package:image_picker/image_picker.dart'; import 'package:date_time_picker/date_time_picker.dart'; @@ -41,11 +42,9 @@ class _PostLostItemPageState extends State { TextEditingController itemCategory = TextEditingController(); TextEditingController additionalInfo = TextEditingController(); TextEditingController itemLocationController = TextEditingController(); - // TextEditingController cityController = TextEditingController(); - // TextEditingController divisionController = TextEditingController(); - // TextEditingController unionVillageController = TextEditingController(); - // TextEditingController streetHouseController = TextEditingController(); DateTime? dateTimeController = DateTime.now(); + String userID = AuthService.currentUser!.uid; + bool isRetrieved = false; late String imgURL; void _insertImage() async { @@ -82,10 +81,6 @@ class _PostLostItemPageState extends State { itemCategory.text.isNotEmpty && additionalInfo.text.isNotEmpty && itemLocationController.text.isNotEmpty && - // cityController.text.isNotEmpty && - // divisionController.text.isNotEmpty && - // unionVillageController.text.isNotEmpty && - // streetHouseController.text.isNotEmpty && selectedImage != null && dateTimeController != null; } @@ -107,11 +102,9 @@ class _PostLostItemPageState extends State { 'DateTime': dateTimeTimestamp, 'Description': additionalInfo.text, 'ItemLocation': itemLocationController.text, - // 'CityLocation': cityController.text, - // 'DivisionLocation': divisionController.text, - // 'UnionVillageLocation': unionVillageController.text, - // 'StreetHouseLocation': streetHouseController.text, 'ImageURL': imgURL, + 'userID': userID, + 'isRetrieved': isRetrieved, }; DocumentReference docId = await collectionReference.add(lostItemData); diff --git a/lib/pages/profilePage.dart b/lib/pages/profilePage.dart index d1a872f..d6dc9dc 100644 --- a/lib/pages/profilePage.dart +++ b/lib/pages/profilePage.dart @@ -24,9 +24,10 @@ final FirebaseAuth _auth = FirebaseAuth.instance; User? get currentUser => _auth.currentUser; class ProfilePage extends StatefulWidget { - ProfilePage({Key? key}) : super(key: key); + const ProfilePage({Key? key}) : super(key: key); @override + // ignore: library_private_types_in_public_api _ProfilePageState createState() => _ProfilePageState(); } @@ -38,7 +39,6 @@ class _ProfilePageState extends State { @override void initState() { super.initState(); - getUserInfo(); } @@ -55,7 +55,7 @@ class _ProfilePageState extends State { db_helper.getUserInfo(AuthService.currentUser!.uid).listen((snapshot) { if (snapshot.exists) { setState(() { - userModel = UserModel.fromMap(snapshot.data()!); + userModel = UserModel?.fromMap(snapshot.data()!); }); } }); @@ -148,7 +148,7 @@ class _ProfilePageState extends State { CrossAxisAlignment.center, children: [ Text( - '${userModel.firstName} ${userModel.lastName}', + '${userModel?.firstName} ${userModel?.lastName}', style: GoogleFonts.oswald( textStyle: const TextStyle( fontSize: 32, @@ -209,7 +209,7 @@ class _ProfilePageState extends State { print('Statistics Card Tapped'); }, child: Container( - padding: const EdgeInsets.all(16), + padding: const EdgeInsets.all(8), decoration: BoxDecoration( gradient: const LinearGradient( colors: [Colors.cyan, Colors.indigo], @@ -220,7 +220,7 @@ class _ProfilePageState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ _buildStatColumn('Lost Items', '10'), - const SizedBox(width: 20), + const SizedBox(width: 18), _buildStatColumn('Found Items', '20'), ], ), @@ -308,13 +308,13 @@ class _ProfilePageState extends State { children: [ Text( title, - style: const TextStyle(fontSize: 36, color: Colors.white), + style: const TextStyle(fontSize: 24, color: Colors.white), ), const SizedBox(height: 5), Text( number, style: const TextStyle( - fontSize: 36, + fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white, ), From 355fa1f0d54818b46a6ff30e7ad5a59a5a08b93d Mon Sep 17 00:00:00 2001 From: ImranIF Date: Sat, 27 Jan 2024 21:59:34 +0600 Subject: [PATCH 14/19] added ? --- lib/pages/userPage.dart | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/pages/userPage.dart b/lib/pages/userPage.dart index a51102a..629610a 100644 --- a/lib/pages/userPage.dart +++ b/lib/pages/userPage.dart @@ -20,7 +20,7 @@ class UserPage extends StatefulWidget { class _UserPageState extends State { GlobalKey _scaffoldKey = GlobalKey(); - late UserModel userModel; + UserModel? userModel; @override void didChangeDependencies() { @@ -40,7 +40,7 @@ class _UserPageState extends State { ), title: SafeArea( child: Text( - "${userModel.firstName} ${userModel.lastName}", + "${userModel?.firstName} ${userModel?.lastName}", style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, @@ -94,7 +94,7 @@ class _UserPageState extends State { radius: 70, backgroundColor: Colors.transparent, child: CachedNetworkImage( - imageUrl: userModel + imageUrl: userModel! .thumbnailImage.downloadUrl, imageBuilder: (context, imageProvider) => @@ -125,15 +125,16 @@ class _UserPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildText( - 'Name: ${userModel.firstName} ${userModel.lastName}', + 'Name: ${userModel!.firstName} ${userModel!.lastName}', isHeader: true), - _buildText('Email: ${userModel.email}'), + _buildText('Email: ${userModel!.email}'), _buildText( - 'Profession: ${userModel.profession}'), - _buildText('Points: ${userModel.rating}'), - _buildText('Address: ${userModel.address}'), + 'Profession: ${userModel!.profession}'), + _buildText('Points: ${userModel!.rating}'), + _buildText( + 'Address: ${userModel!.address}'), _buildText('Creation Time: ' - '${_formatTimestamp(userModel.userCreationTime)}'), + '${_formatTimestamp(userModel!.userCreationTime)}'), ], ), ), From 032970ac36c6b05a2447e9fa5e651e100dfd3c96 Mon Sep 17 00:00:00 2001 From: ImranIF Date: Sat, 27 Jan 2024 22:23:50 +0600 Subject: [PATCH 15/19] added LoserID and FounderID in FoundProduct and LostProduct --- lib/pages/postFoundItem.dart | 6 ++++-- lib/pages/postLostItem.dart | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/pages/postFoundItem.dart b/lib/pages/postFoundItem.dart index 9fd4cc7..b8145b9 100644 --- a/lib/pages/postFoundItem.dart +++ b/lib/pages/postFoundItem.dart @@ -31,6 +31,7 @@ class _PostFoundItemPageState extends State { TextEditingController additionalInfo = TextEditingController(); TextEditingController itemLocationController = TextEditingController(); String userID = AuthService.currentUser!.uid; + String loserID = ''; bool isRetrieved = false; DateTime? dateTimeController = DateTime.now(); late String imgURL; @@ -88,8 +89,9 @@ class _PostFoundItemPageState extends State { 'Description': additionalInfo.text, 'ItemLocation': itemLocationController.text, 'ImageURL': imgURL, - 'userID': userID, - 'isRetrieved': isRetrieved, + 'UserID': userID, + 'LoserID': loserID, + 'IsRetrieved': isRetrieved, }; await collectionReference.add(foundItemData); diff --git a/lib/pages/postLostItem.dart b/lib/pages/postLostItem.dart index 95c0d9a..c017760 100644 --- a/lib/pages/postLostItem.dart +++ b/lib/pages/postLostItem.dart @@ -44,6 +44,7 @@ class _PostLostItemPageState extends State { TextEditingController itemLocationController = TextEditingController(); DateTime? dateTimeController = DateTime.now(); String userID = AuthService.currentUser!.uid; + String founderID = ''; bool isRetrieved = false; late String imgURL; @@ -103,8 +104,9 @@ class _PostLostItemPageState extends State { 'Description': additionalInfo.text, 'ItemLocation': itemLocationController.text, 'ImageURL': imgURL, - 'userID': userID, - 'isRetrieved': isRetrieved, + 'FounderID': founderID, + 'UserID': userID, + 'IsRetrieved': isRetrieved, }; DocumentReference docId = await collectionReference.add(lostItemData); From a11d2a4f2ec211e901905edf61f82d6d612ca5ba Mon Sep 17 00:00:00 2001 From: ImranIF Date: Sun, 28 Jan 2024 14:25:46 +0600 Subject: [PATCH 16/19] tweaked lost item and found item page --- README.md | 36 +++-- android/app/src/main/AndroidManifest.xml | 4 +- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 8815 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 5366 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 14354 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 27095 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 42628 bytes lib/db/db_helper.dart | 8 +- lib/pages/login.dart | 40 +++++- lib/pages/postFoundItem.dart | 50 +++++-- lib/pages/postLostItem.dart | 124 ++++++------------ lib/pages/profilePage.dart | 12 +- lib/pages/registration.dart | 18 +-- lib/pages/userPage.dart | 2 +- lib/provider/user_provider.dart | 17 ++- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 48 +++++++ pubspec.yaml | 1 + 18 files changed, 219 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index 62c8506..12dd70e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,22 @@ -# Setup Guide for "Retrieve Me" Project +#

RETRIEVE ME

+ +## Table of Contents +- [Overview](#overview) +- [Seteup Guide](#steup-guide) +- [Installation](#installation) +- [Features](#features) +- [Getting Started](#getting-started) +- [Acknowledgements](#acknowledgements) +- [Contributors](#contributors) + +## Overview + + +## Setup Guide Welcome to the setup guide for the "Retrieve Me" project, a Flutter and Firebase-based application developed using Agile methodologies. In this guide, we will walk you through the process of setting up the project on your local machine for development and testing purposes. -## Prerequisites +### Prerequisites Before you begin, make sure you have the following prerequisites installed on your system: @@ -12,11 +26,11 @@ Before you begin, make sure you have the following prerequisites installed on yo 4. **Android Studio** or **VS Code**: Integrated development environment (IDE) for Flutter development. 5. **Android/iOS Emulator** or a physical device for testing. -## Step-by-Step Setup Process +### Step-by-Step Setup Process Follow these steps to set up the "Retrieve Me" project on your local machine: -### 1. Clone the Repository +#### 1. Clone the Repository Open a terminal and execute the following command to clone the project repository: @@ -37,11 +51,11 @@ cd retrieve_me flutter pub get ``` -### 4. Run the Application +#### 4. Run the Application Use your preferred IDE (Android Studio or VS Code) to open the project directory. -#### Running on Android Emulator/Device +##### Running on Android Emulator/Device 1. Ensure your Android emulator or physical device is connected. 2. Run the app using the IDE's run button or execute the following command in the terminal: @@ -50,7 +64,7 @@ Use your preferred IDE (Android Studio or VS Code) to open the project directory flutter run ``` -#### Running on iOS Simulator/Device +##### Running on iOS Simulator/Device 1. Ensure you have Xcode installed on macOS. 2. Open the `ios/Runner.xcworkspace` file in Xcode. @@ -61,22 +75,22 @@ flutter run flutter run ``` -### 5. Testing +#### 5. Testing You can now interact with the "Retrieve Me" app on the emulator or device. Explore its features and functionalities to ensure everything is working as expected. -## Contributing and Agile Workflow +### Contributing and Agile Workflow If you're interested in contributing to the project, we follow an Agile development workflow using Git. Create a new branch for your feature or bug fix, make your changes, and submit a pull request to the `develop` branch. For Agile-related tasks, we use tools like Trello to manage user stories, tasks, and sprints. Feel free to join our Agile boards and participate in the development process. -## Conclusion +### Conclusion Congratulations! You've successfully set up the "Retrieve Me" project on your local machine using Agile development practices. You can now start developing, testing, and contributing to the project. If you encounter any issues, refer to the project documentation or reach out to the development team for assistance. Happy coding! 🚀 -## Team Members: +## Contributors: 1. Imran Farid 2. Ramisa Zahara Matin diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e4c5c5f..c92073c 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,9 @@ + android:icon="@mipmap/ic_launcher" + android:enableOnBackInvokedCallback="true" + > L!{>>k_Yd|mG*EiNub(ix z{r|$?|AiqQUjOhDo;cF3F24Wd`bYk$7}wU#=*82F`P69uZ@>Uh0~G&R|I_u8xEBF{ z_#Xg3N%@ZsoC5%D?*M?}+kbS-p8$X$3IJMX{-gWPo_N@J+59UU>eGm9X9oZm=ztqO?WTJVh%l)a@11^9qzyN>%Hvj_gJ|RJX9}oaUAJ+h-r{ny; z$v;8Jvfg8GwX}0w5uyprfE+pgr->P*Bk^kdQG60W2bt=ftGs0t)(MHmTUm!k#`%uOl*= z=e7!qOJHYD&NNSVH`-I~|3pWBiiU=Pf{FZOm3yiK83_di85tc7=PAciDaa_OXy}AQ z0P%AS5=H@1K?Qx!2uvoMR2Z|6q5;?|t#EGZjEuaoPuTnX@f(2qR5vmq3Lzi|ym?=g z)MO3X3~NZe@#*F*s1B78%7aro@6qSWatDswz-RKpM!p{Sz7oGbzxO=w>9q1hz;EGS z4}3nuuSfno0yCxa1S4TL2+8uH`aH=j-3WFuuUZ1{(^S25S6Zml3Zo;azWL)>Xg!>O8^^yhut}y>QAuy)HYx z2~!_fMGgV0FowLt*hNZR+?mc6cs8q|q@ncboPFM8W)kByuk?Oinbw-u)`wn(gFe=( zj&gDlVneMAaSp4*tn{_%mV{`-MAN2r4(mHc4o&q^y{NFuHj^+oGmXSu1VMq5L!D5b>qh8N_Owu*J>@k{`+1%{ zooAjsy-hOZaA?l3=N{!qa(Pu`b!{Z95@1MCP**?=U`Teq3K==s&$ed2LwJhrc?1a1 zg;h6qxn3o2_L~1(gG!ifWX2T|cqRMZ@4lR-TO571))o{fdA?D>@BKE)2}*Vg!{fBS z`hcEDXS3@w?b6&qo{%3qnverN^CAw-AHPEM47c|4UK8xxpRT4bxQ#%%1`A^3@K;|U zP0+E$4#Gie31P3o-6lM7(Gk&tqzHMb(=P=K1We%b6J3(EVUg1r-_Lt4a4I<6Ru)+( z_sQk*2!dew@?J)fs&iEeyJd`Rx1T=eyn$|W%9ZeK8>zXI8fIObrpxGjhFEd;S)RbckrTLCr(6Z{Ly<`;6oH3 z5v50m$-3j$idovz_j8Y4*{L{I3l2ZH>Zkl3*RGXj1i*3_O>N}wFa*d0%Q#>s$RLa2 zhiwN55vBv%w3R>>^YdLY7)78<7U5O*;0sMj)%4IxS6wT~LypB&^qYRd%>#C|!R!H4@R zB}1xw{Qj|pi<<`5S+r6UI}T&(R_fRa`sSFi9ClM6n=MQBrDnzu2y|0+f)hyXGURXd zO8BqF`9=htC`PE1>m2$Y`$evQJyj-U`J_f9e$$>+6O2i#!*A@VYU*P5#AkjbxaPrc z;PXPB#y0n)Jc#IfNqp_WfQ`TR45S;$kY}uP-8^?}{ddn7Z-_1VQ_IY{9kqmi1g{wM0bU zcSog^4|>)|xeXM>^hdieC-~pXwo9ssN#{ruYfIo!gnU z$lRQ)Mj$DqKlIHeVOnljyEfyOEJt(h*mkx&I397iFB)<1L_P|F&8;J{-s;?auNKkN zvMx5=z7^w29UJon;_pGu=b?DMC0qu{EOr|fp2#H7+89?goMSWVlp%K071u@#X>1OT z$>+4P&_%km+pLt)5R4Pv-7Ny?#Z#ju)rG~$sNl}Cm1ws7jx<&LIpn!92I3koox(9Z z@7I!*(*p<9w!b7^s56m8D?7$D63gal?lj_2*8E@}LXplIX4s^778%8i;=x@!GTNYL zei3<57(U8xQz1Mj0%z$wa$C%?&vo44PpKO8w;21We@@0?+AiIJaX#4kIT>A+;%M^E zp<%RmRevqFXW58DVIt+^YZ#4zu#VOm8usgTppRlVsnGowwj$Km63cy5z+p11LhbT2 znfnpgR{9gK^D)(@nJI+?zXleh-TYnbTPd^P_V1r5wLEDH`~rm&1#>W;4axl47b}QU zIJrs&_UobT!Ax?xX&N=!*6;<)gd!VUKPpgh%)507GpRCsl(FBuQ-6YsJOX~7#7cw* z0+z+{Nox%lGQnB?^q}9a^^D25aOW2l0e3A**(wj&E5-IAKeEU~Pe#;c@EV5do@E5y zo@kFUE*q+P^=|#x_s;!3Knv-oWfCPj>cM|!R+RLmjZ~_oEPB!)|1vF>DJwSu*Lg4+ zhu$TNy4NSrBZA>)dDGAltHcHAi5gGf)-MHfy2;pKo#Q5SuTrxPOnBzsOn{xaE$6dD z*h+n_Cpu2hdAAJ82W;P{aCgsopzc( z>ktT&!N4TcW~8Ds!c8--OD4|OHXvl7m8@B4yeF7H=Ob#G=f#!+Arxu+LeGoGrb32# zwzcBL0?e>Fy)$)1xZ0>GrOBM!^<6cWjzlh|R796M0|AE#e@V22_;3HqQ|@WB{;Wlo zio)4bo8umiyJ!9sn<`Y2H75u9F@K&G%)-;tfU?Cq-1a^lyXQOhZ@Q zR@N=ruUb3Mz0+aL_1-xQLpCw?%CE8*M>5jRr60%?^*Cf44*x8e1@Ui9YL=Q%f@xel zQGMEQ`6;<9ylm2i+Ir-%6mgCHBcRhiq7^4O}?&%iQo5rE-kpby-C06kZa%k zo1f2DCx^gDo(#OZji;yEH?h$=6WQl44962Q?FHF${Qs7)pP=Jbo-MM%uft)Rm5 zD9v`5MK$%ajKgsoJHw?sV_z!Ru<9r#yZTVzbDGa)sX0V5hIY-iKyB(`aaJt_nne@V zOIu<7ey`Op3CwfZL)xvuB_PEI#h>QUep)Qu0zut|gG;ftTD4iJv~_jzWBtet6KijL zGBAQ|)-#Ih3n+1aX7)R7aAeOev^?-FYKh#{eEWWqW1R)s+Nu`zv{}PWVeX(i8HG-o z-R4Ftz8T-YL+w-molse9*tu0ta|@#?@1D z)RAfrxW}5nMl_EZa;sYmgZEaZHpn4rR_$|R%qv|rJ^d3Quk|eRYm*o_O|{dvsd+M0 z()h7E)edRgtD9vk`oRn^62lfUMv0Os2r)bwLh)7`g2#Rr3Xfi2qH3S@M zpCSdnoeTOl7%=FrusC!3hJB{sPGAsL9nUUrh~{KFVcW+Um+)QP6j){a7C*83x`wIi z{_sw8GG+05k&w0L@9!^_Gh@=3Tf*TqjYK4pjVT7AVBByQ9K7hh8S^0--75BjvIyrD zTQui|Y4wQGx9w6CF}}Vz3y~yb%zq94+Hl8}+$Beucw0gJAT1oXV}O=lB%uG3=gMDuLZ&*cC)9sExdvD@A+FmSxO7&ddq zMOiZ$`#M0JX=ZCaRSA=Kv2kLUO9drV`>rA^T>NFaW@ZVztYSu{=IChT9GRx=e(;)6 zd1b;Lg+&9DXT(!DQe9z%KlxWgBK=0!p$&DFW5W#Km~@v)B_V1ZCpa<$H=SZb#@K5m zEODa+S%Q{&pIga8iJEcKZ}h15wOw(khqRM|RS79rBf}cr%*AyI`_1NsAez@WH7j|Z ztIEAoK)cT^`(lYezuIJCy)C5C*lyBEIvq3)NhmWq@$jW#aLisBexbf-Q@xp>7*B(Q z9`sTB!XBPBc{w9{O6juzP&;8p_lOTK zWpQ1d!eQq`kxF5F1BnpnBw7%!8Vz~?&3BJLddBC# zhtQ0CChz;`2aM8ZXv2>H69dNCx-TBNjgaM1=X=bqnobkS;&4vCk--&TBQ<%@y5dR&hQ&eh?`CdqKv07)RZosjw< z0ry{p9aw3F<~9Vv zL_0X0de0drSf=Z^_M`N3Y*K|^jluZ?c9M_;d3a~j*E>+-zK&sxPvn1|_Z?D;l2rFN z=N_rb`JB~J*+NiEC%44C7|E{w;)BlV)~<PP5mK0IzP4QkLXf zM3|2`2@D6^A{E*dF%D1T+s3{zW43ne>tlG9-XQh}_}7hvdjW|q!_SOZH-%^=8G_(6 zjw>^U-t89xHSEEt?~WLk>zD}N)8ECE$fsR@&I#=BgIabaCZOG8 z5ZK;7tvgsy8`rx_3K~Fx`P$C!XN6IMHSF)ljI=Hvxq6>gDRr=n`f`w6J#6Nu&lIj@ zx(3B|oOrdxv1ywD1^gT3@nU1V<6J18jg^Pg_@pL*j=Hk>hWp8uK#DuX)QBk}YRRb2 z_RI0=Ds7cl+q&?g9jk_Gk*oQ~kc&<}7R*ju3f4gm-_&vHPRrkIFPeOU0|wj-iURo5 zv?^|=Xb_`?t$>?ok`V(ynvHZ$yyU-c463kqv-Ui2y}WW)GhWae6HjHZ*kFl^Ha1Tg z{R%==RTHj7hrVE`nuCQtCz9Y*j?$4bEc-VGOz(eQXH8{Qd%;;}~WZYXM+EUwlp;L15tluk2DO z2CiA3D1aA124=P`G@kEbWtvdet4Aw|D_?Vq?%1lLX3@+B6hJ59%tf93_bJ%kp1Hi$ zsbfv*H%nx@)*r{INgbmewn+u)^eG#Vw-yeV$QhYcAwqpsY@~`iWhdg47`mlQLPZ>n zQ>Dl<1`n}nBX9_xr)YjiBZ_#wQ#{*Op>2z2wuO6Id4R*yl<2XBOzN4Q_fB@UsO4l# zy~Nv8Uf+$vXbvouk8JNy6esWhVoh$2@#nMxmxA!rDb$HeCNsD5c&oA`t)^ltGtG!F zmUK4Sj6^V#$zxG)!_ZQZa2Ede({XSv@{AqBm_|zTt-cfI0xV-zB^tXh#hfLlGmgOy zg*C}`zha+4d{0Mz;u<}sn*xf?Q4%)S1j>b#tO-Oz1(F1cM0j#V%nPXs<_brz%E(Tj zj=3T+0g8isX3n>@20d>p4>xDc>!iEvjgPDN7Opu+I>=)V(PsRYCf51xY9XdfP)+<7 zpXqPZbmqb@yW<(*Zqmg}3&~nbf4U>7;7-iD3%4~K&+x}vny{9PR=*C|h6UxSidkI|7#0dxyk{VI z`+EjDc6h_`ES?7V-JfB!-1uA^hl@HbukjYY=`0Xb%g?OTsSG4w$TpcAVj?z7RL$*n z$I3ND_8Oh5PPoR^9r(Bu&xcGCuii3yJ=f*yLJ?>9bePU(knx9mz8jUePx^%t7$Z6F z#X_2xS=3zW`8ByG-@p!D%5Pfa?>@e+@Rq+ZmUUX`O#Q*z1<7=8yU8YXR3CQ87Ci#KVd00}GfU@JsSo$&(A$zu>|X^`j9X}i zGkb7l=$!U%IDNinUB`LyvTS;i`nasEI(;@%xe{#sX0;6=E1yjNaC69x<5hO#^s+5@ z^bMU7eO(IqH~)bSn&LnQR<9LEs#oP{jZ5m;wL3K(OU%8kGg00^7C8E-I*li8Bx^RG zxL@*;# z)a^Z!qU4tKaC+02^~dsRaJMt0!E&~hPQ%A37m2%|DW*Ayr<5NSPM{#BbPns1minCX zR=TH~u7utBsmVtP>J`yZ8BGgkTh8G_4y&|*=DA66H65z7%}lVrzD%l~0vSS+vGvQZ zY`Nl}Q%m!Pt`M%(55z%JuXC@&=;NdFg_mRD5?s(jFc)Yf&ft@4ZM=Ho@sBj|wdDNN z;G;9c;=~}jN}pHj#!`-JQ=NtCJ1QK7!@}8(S(fi#t1}{vsePM(VlOdt63tPjy>sdF z18uE(Ry4n|IJ&y$vS||eH6LhG;cQ$$HN}x+1tPVtWnPQa%X(g%Qh8cF(zk++rc3S5 zVP5Gc`TG}mNGpniO4BlDCm%7`a1#MNfds#%gByD+3mTk@i8FKBy=!B5HW&+$6W>iv7wjZueuLj<%oc}l zf)cafyIq?R!~G}CsMuGREW&o%wpNg@51g6yN!Q8;%El6}x(zZ=O{6?bTHO=UP~z+1 z$*SbX)bCUSlMT^JhWBztx^S-NCV&PY5rq0CZv5#R^e(Z`sy9*+cKYAr?&Hdw>yI(T zIfOKuUpCM3Lnx^mOJ)b>&~J#6Nsf9M=(A?X+iv*}x|R_QuX!MjnT_Ch`joUq1&&ZX zHLrY)HPbX^?ZsF0{`6dQT+I3vr?|hTyN}5RnfElelRtW`canK%UDdYi!$e1S)3`ZI z68?~!nDKX{x2oncXzrPIDzqMBGJg1cnzD_%>eefH`xY9?MX{lBqQXJS%q7-Yi@Q+? zv5n0y;n$+2wg<)`8R*>MpJ?T$Zlx;jg}UPw9x|t(leUax?7Eh!g1fgMuj&zzmEwtS zx$%o1?B42Z_;l$t#_Z*Cl;Y%^+n-lynSXY0>vNQKXqf0(u+umJZL9u9>V6f= zWsvdvZKBiiuj#5R%&um;Jnm-R25AzMG=!20h&Dy0$Uh!`EUFuMJw*H_vpkyeuzh+E zySf!#RQ|LY+@aKBwAklN%$UbZg|(v{_%L0RiRZYxi+Jx;tT8thnA9>eO!%0?vhQO!?X02wW=>{ zmyt+op<^RY7;)x4v=>mM#4AqgHOJ{W*#E-hfc7xi%59O!nAGiS^$2)=wVM6D=y#%K zQsQa=JxV9WPx)>Wj$4n+x=+qkt%W90|hJi6-e zl1daq=VTop(jhz^E!ERS+rVWp6aOheUM|Fv~yV!jdNM{ux$3cw&8FtgyJ?}nPTMN zXs3t>WW;cmI@xtH(3UW|Fq8|bG&BajLy@GRH>CoQq7LNcQo!qy8 zM?mi3A?LE4?T^VF)4k-Ay5%A4*Vmi(`ETy#H*d;i<;wpdUH_iR?31hN-J(C3_m^u9 z3zQ4n`0LYSv$>3z->gSW)R#Z(%|8NKK^DZf)enRZALZoaUjE*FcqLoeIPJeI$-eb9 z*ERXQD~U(Xt$V_~P~zpyB>1#9$LPal#8M@MBly*wiiz4I3b0W&8B2L+mCn;zd4)@j3^epdP5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..860c899a89a7313ec2d720ed2d0b6a2c0e516462 100644 GIT binary patch literal 5366 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 aJ8BJ|HINj$vy5tLXBU@1pa0?I)V~1v`eOnB literal 442 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 literal 721 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD3?#3*wSy!iOI#yLg7ec#$`gxH85~pclTsBt za}(23gHjVyDhp4h+5i=O3-AeX1=1l$e`s#|#^}+&7(N@w0CIr{$Oe+Uk^K-ZP~83C zcc@hG6rikF&NPT(23>y!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..4edee25da46e2b0b96a9ec1f8ae3664bdbd76a3e 100644 GIT binary patch literal 27095 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 Sf)f#?(&vwbk@NHa7XJ^7Jj${F literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372eebdb28e45604e46eeda8dd24651419bc0..026b526346f7cf2b9c611226f801f03b998185ca 100644 GIT binary patch literal 42628 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 TJ+?&{b*ZoK9?&T3e{=r_d9O!^ literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/lib/db/db_helper.dart b/lib/db/db_helper.dart index 9eee7c4..83ad660 100644 --- a/lib/db/db_helper.dart +++ b/lib/db/db_helper.dart @@ -15,14 +15,18 @@ class db_helper { final snapshot = await _db.collection(adminCollection).doc(uid).get(); return snapshot.exists; } + static Stream>> getAllUsers() { print("HELLO KAIS"); return _db.collection(collectionUser).snapshots(); } + static Future addUser(UserModel userModel) { print(userModel.email); - return _db.collection(collectionUser).doc(userModel.userId).set(userModel - .toMap()); + return _db + .collection(collectionUser) + .doc(userModel.userId) + .set(userModel.toMap()); } static Future doesUserExist(String uid) async { diff --git a/lib/pages/login.dart b/lib/pages/login.dart index 5cd52d2..775195a 100644 --- a/lib/pages/login.dart +++ b/lib/pages/login.dart @@ -5,6 +5,7 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:google_sign_in/google_sign_in.dart'; import 'package:provider/provider.dart'; import 'package:retrieve_me/Components/my_button.dart'; import 'package:retrieve_me/Components/my_textfield.dart'; @@ -41,6 +42,35 @@ class _LoginPageState extends State { ); } + Future signInWithGoogle() async { + // Trigger the authentication flow + final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn(); + + // Obtain the auth details from the request + final GoogleSignInAuthentication? googleAuth = + await googleUser?.authentication; + + // Create a new credential + final credential = GoogleAuthProvider.credential( + accessToken: googleAuth?.accessToken, + idToken: googleAuth?.idToken, + ); + + // Once signed in, return the UserCredential + return await FirebaseAuth.instance.signInWithCredential(credential); + } + + Future handleGoogleSignIn() async { + EasyLoading.show(status: 'Loading. Please wait...'); + final UserCredential user = await signInWithGoogle(); + EasyLoading.dismiss(); + if (user != null) { + Navigator.of(context).push( + MaterialPageRoute(builder: (context) => const ProfilePage()), + ); + } + } + @override Widget build(BuildContext context) { return ChangeNotifierProvider( @@ -252,15 +282,15 @@ class _LoginPageState extends State { void _authenticate() async { if (_formKey.currentState!.validate()) { EasyLoading.show(status: 'Please wait', dismissOnTap: false); - final email = emailController.text; - final password = passwordController.text; + // final email = emailController.text; + // final password = passwordController.text; try { - final User user = await AuthService.loginAdmin(email, password); - EasyLoading.dismiss(); + // final User user = await AuthService.loginAdmin(email, password); + // ignore: use_build_context_synchronously Navigator.of(context).push( MaterialPageRoute( - builder: (context) => ProfilePage(), + builder: (context) => const ProfilePage(), ), ); } on FirebaseAuthException catch (error) { diff --git a/lib/pages/postFoundItem.dart b/lib/pages/postFoundItem.dart index b8145b9..7c51384 100644 --- a/lib/pages/postFoundItem.dart +++ b/lib/pages/postFoundItem.dart @@ -10,6 +10,7 @@ import 'package:provider/provider.dart'; import 'package:image_picker/image_picker.dart'; import 'package:date_time_picker/date_time_picker.dart'; import 'package:retrieve_me/auth/auth_services.dart'; +import 'package:widget_zoom/widget_zoom.dart'; import '../Components/my_textfield.dart'; import '../Components/navigation_drawer_widget.dart'; import '../firebase_options.dart'; @@ -230,19 +231,42 @@ class _PostFoundItemPageState extends State { width: MediaQuery.of(context).size.width * 0.75, height: MediaQuery.of(context).size.height * 0.075, - child: TextButton( - onPressed: _insertImage, - style: TextButton.styleFrom( - backgroundColor: Colors.cyan, - shadowColor: Colors.green, - ), - child: - const Text('Insert Found Product Image', - style: TextStyle( - color: Colors.brown, - fontWeight: FontWeight.bold, - )), - ), + child: selectedImage != null + ? Row( + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + WidgetZoom( + heroAnimationTag: 'tag', + zoomWidget: Image.file( + File(selectedImage!.path))), + // reset + const SizedBox(width: 16), + IconButton( + onPressed: () { + setState(() { + selectedImage = null; + }); + }, + icon: const Icon( + Icons.close_outlined, + size: 30)) + ]) + : TextButton( + onPressed: _insertImage, + style: TextButton.styleFrom( + backgroundColor: Colors.cyan, + shadowColor: Colors.green, + ), + child: const Text( + 'Insert Lost Product Image', + style: TextStyle( + color: Colors.brown, + fontWeight: FontWeight.bold, + )), + ), ), const SizedBox(height: 16), SizedBox( diff --git a/lib/pages/postLostItem.dart b/lib/pages/postLostItem.dart index c017760..8bc38ac 100644 --- a/lib/pages/postLostItem.dart +++ b/lib/pages/postLostItem.dart @@ -11,6 +11,7 @@ import 'package:retrieve_me/auth/auth_services.dart'; import 'package:retrieve_me/pages/login.dart'; import 'package:image_picker/image_picker.dart'; import 'package:date_time_picker/date_time_picker.dart'; +import 'package:widget_zoom/widget_zoom.dart'; import '../Components/my_textfield.dart'; import '../Components/navigation_drawer_widget.dart'; import '../firebase_options.dart'; @@ -63,8 +64,6 @@ class _PostLostItemPageState extends State { Reference ref = storage.ref().child('images/$fileName${DateTime.now()}'); print('--------------------------$ref'); - // Reference ref = - // storage.ref().child('images/' + DateTime.now().toString()); UploadTask uploadTask = ref.putFile(File(selectedFile.path)); print(uploadTask); uploadTask.then((res) { @@ -246,18 +245,42 @@ class _PostLostItemPageState extends State { width: MediaQuery.of(context).size.width * 0.75, height: MediaQuery.of(context).size.height * 0.075, - child: TextButton( - onPressed: _insertImage, - style: TextButton.styleFrom( - backgroundColor: Colors.cyan, - shadowColor: Colors.green, - ), - child: const Text('Insert Lost Product Image', - style: TextStyle( - color: Colors.brown, - fontWeight: FontWeight.bold, - )), - ), + child: selectedImage != null + ? Row( + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + WidgetZoom( + heroAnimationTag: 'tag', + zoomWidget: Image.file( + File(selectedImage!.path))), + // reset + const SizedBox(width: 16), + IconButton( + onPressed: () { + setState(() { + selectedImage = null; + }); + }, + icon: const Icon( + Icons.close_outlined, + size: 30)) + ]) + : TextButton( + onPressed: _insertImage, + style: TextButton.styleFrom( + backgroundColor: Colors.cyan, + shadowColor: Colors.green, + ), + child: const Text( + 'Insert Lost Product Image', + style: TextStyle( + color: Colors.brown, + fontWeight: FontWeight.bold, + )), + ), ), const SizedBox(height: 16), SizedBox( @@ -328,80 +351,7 @@ class _PostLostItemPageState extends State { prefixIcon: Icons.location_city, labelText: 'Location of item lost', keyboardType: TextInputType.streetAddress, - // inputFormatters: [ - // FilteringTextInputFormatter.allow( - // RegExp(r'[a-zA-Z. ]')) - // ], ), - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceAround, - // children: [ - // // City - // SizedBox( - // width: - // MediaQuery.of(context).size.width * 0.25, - // child: MyTextField( - // controller: divisionController, - // hintText: 'Chittagong', - // obscureText: false, - // prefixIcon: Icons.location_city, - // labelText: 'Division', - // keyboardType: TextInputType.streetAddress, - // inputFormatters: [ - // FilteringTextInputFormatter.allow( - // RegExp(r'[a-zA-Z. ]')) - // ], - // ), - // ), - // SizedBox( - // width: - // MediaQuery.of(context).size.width * 0.25, - // child: MyTextField( - // controller: cityController, - // hintText: 'Hathazari', - // obscureText: false, - // prefixIcon: Icons.location_city, - // labelText: 'City', - // keyboardType: TextInputType.streetAddress, - // inputFormatters: [ - // FilteringTextInputFormatter.allow( - // RegExp(r'[a-zA-Z. ]')) - // ], - // ), - // ) - // ], - // ), - // const SizedBox(height: 16), - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceAround, - // children: [ - // // City - // SizedBox( - // width: - // MediaQuery.of(context).size.width * 0.25, - // child: MyTextField( - // controller: streetHouseController, - // hintText: 'Road no: 3, House no: 7', - // obscureText: false, - // prefixIcon: Icons.location_city, - // labelText: 'Street/House No.', - // keyboardType: TextInputType.streetAddress, - // ), - // ), - // SizedBox( - // width: - // MediaQuery.of(context).size.width * 0.25, - // child: MyTextField( - // controller: unionVillageController, - // hintText: 'Fatikchhari', - // obscureText: false, - // prefixIcon: Icons.location_city, - // labelText: 'Union/Village', - // keyboardType: TextInputType.streetAddress, - // ), - // ) - // ], - // ), const SizedBox(height: 16), MyTextField( controller: additionalInfo, diff --git a/lib/pages/profilePage.dart b/lib/pages/profilePage.dart index d6dc9dc..c2e2a54 100644 --- a/lib/pages/profilePage.dart +++ b/lib/pages/profilePage.dart @@ -32,13 +32,15 @@ class ProfilePage extends StatefulWidget { } class _ProfilePageState extends State { - late UserModel userModel; + UserModel? userModel; List userListX = []; @override @override void initState() { + EasyLoading.dismiss(); super.initState(); + getUserInfo(); } @@ -118,7 +120,7 @@ class _ProfilePageState extends State { radius: 70, backgroundColor: Colors.transparent, child: CachedNetworkImage( - imageUrl: userModel + imageUrl: userModel! .thumbnailImage.downloadUrl, imageBuilder: (context, imageProvider) => @@ -159,7 +161,7 @@ class _ProfilePageState extends State { ), const SizedBox(height: 5), Text( - userModel.profession, + userModel!.profession, style: GoogleFonts.lato( textStyle: const TextStyle( fontSize: 20, @@ -170,7 +172,7 @@ class _ProfilePageState extends State { ), const SizedBox(height: 5), Text( - 'Points: ${userModel.rating}', + 'Points: ${userModel!.rating}', style: GoogleFonts.lato( textStyle: const TextStyle( fontSize: 20, @@ -181,7 +183,7 @@ class _ProfilePageState extends State { ), const SizedBox(height: 5), Text( - userModel.address, + userModel!.address, style: GoogleFonts.lato( textStyle: const TextStyle( fontSize: 20, diff --git a/lib/pages/registration.dart b/lib/pages/registration.dart index b292550..8de96d8 100644 --- a/lib/pages/registration.dart +++ b/lib/pages/registration.dart @@ -170,9 +170,9 @@ class RegistrationPageState extends State { obscureText: false, prefixIcon: Icons.person, labelText: 'First Name', - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z. ]')) - ], + // inputFormatters: [ + // FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z. ]')) + // ], ), const SizedBox(height: 16), @@ -182,9 +182,9 @@ class RegistrationPageState extends State { obscureText: false, prefixIcon: Icons.person, labelText: 'Last Name', - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z. ]')) - ], + // inputFormatters: [ + // FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z. ]')) + // ], ), const SizedBox(height: 16), MyTextField( @@ -195,9 +195,9 @@ class RegistrationPageState extends State { prefixIcon: Icons.phone, labelText: 'Contact Number', keyboardType: TextInputType.phone, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], // Allow digits only + // inputFormatters: [ + // FilteringTextInputFormatter.digitsOnly + // ], // Allow digits only ), const SizedBox(height: 16), MyTextField( diff --git a/lib/pages/userPage.dart b/lib/pages/userPage.dart index 629610a..95ae5e7 100644 --- a/lib/pages/userPage.dart +++ b/lib/pages/userPage.dart @@ -19,7 +19,7 @@ class UserPage extends StatefulWidget { } class _UserPageState extends State { - GlobalKey _scaffoldKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); UserModel? userModel; @override diff --git a/lib/provider/user_provider.dart b/lib/provider/user_provider.dart index 9564b37..944a8b6 100644 --- a/lib/provider/user_provider.dart +++ b/lib/provider/user_provider.dart @@ -13,7 +13,6 @@ import '../model/image_model.dart'; class UserProvider extends ChangeNotifier { UserModel? userModel; - // Future addUser(User user,firstName,lastName,address,contactNumber) // async{ // try { @@ -41,8 +40,8 @@ class UserProvider extends ChangeNotifier { getAllUsers() { db_helper.getAllUsers().listen((event) { - userList = List.generate(event.docs.length, (index) => - UserModel.fromMap(event.docs[index].data())); + userList = List.generate(event.docs.length, + (index) => UserModel.fromMap(event.docs[index].data())); print(userList.length); notifyListeners(); }); @@ -50,19 +49,18 @@ class UserProvider extends ChangeNotifier { getUserInfo() { db_helper.getUserInfo(AuthService.currentUser!.uid).listen((snapshot) { - if(snapshot.exists) { + if (snapshot.exists) { userModel = UserModel.fromMap(snapshot.data()!); notifyListeners(); } - }); } + Future uploadImage(String imageLocalPath) async { final String imageName = 'image_${DateTime.now().millisecondsSinceEpoch}'; const String imageDirectory = 'Users/'; - final photoRef = FirebaseStorage.instance - .ref() - .child('$imageDirectory$imageName'); + final photoRef = + FirebaseStorage.instance.ref().child('$imageDirectory$imageName'); final uploadTask = photoRef.putFile(File(imageLocalPath)); final snapshot = await uploadTask.whenComplete(() => null); final url = await snapshot.ref.getDownloadURL(); @@ -72,5 +70,6 @@ class UserProvider extends ChangeNotifier { directoryName: imageDirectory, ); } + Future doesUserExist(String uid) => db_helper.doesUserExist(uid); -} \ No newline at end of file +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 667e7a7..aa4a268 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,6 +11,7 @@ import firebase_analytics import firebase_auth import firebase_core import firebase_storage +import google_sign_in_ios import path_provider_foundation import sqflite import url_launcher_macos @@ -22,6 +23,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) + FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) diff --git a/pubspec.lock b/pubspec.lock index a60fe11..7b54a3f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -552,6 +552,54 @@ packages: url: "https://pub.dev" source: hosted version: "5.1.0" + google_identity_services_web: + dependency: transitive + description: + name: google_identity_services_web + sha256: "0c56c2c5d60d6dfaf9725f5ad4699f04749fb196ee5a70487a46ef184837ccf6" + url: "https://pub.dev" + source: hosted + version: "0.3.0+2" + google_sign_in: + dependency: "direct main" + description: + name: google_sign_in + sha256: "0b8787cb9c1a68ad398e8010e8c8766bfa33556d2ab97c439fb4137756d7308f" + url: "https://pub.dev" + source: hosted + version: "6.2.1" + google_sign_in_android: + dependency: transitive + description: + name: google_sign_in_android + sha256: bfd42c81c30c6faba16e0f62968d5505a87504aaa672b3155ee931461abb0a49 + url: "https://pub.dev" + source: hosted + version: "6.1.21" + google_sign_in_ios: + dependency: transitive + description: + name: google_sign_in_ios + sha256: f3336d9e44d4d28063ac90271f6db5caf99f0480cb07281330e7a432edb95226 + url: "https://pub.dev" + source: hosted + version: "5.7.3" + google_sign_in_platform_interface: + dependency: transitive + description: + name: google_sign_in_platform_interface + sha256: "1f6e5787d7a120cc0359ddf315c92309069171306242e181c09472d1b00a2971" + url: "https://pub.dev" + source: hosted + version: "2.4.5" + google_sign_in_web: + dependency: transitive + description: + name: google_sign_in_web + sha256: a278ea2d01013faf341cbb093da880d0f2a552bbd1cb6ee90b5bebac9ba69d77 + url: "https://pub.dev" + source: hosted + version: "0.12.3+2" graphs: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7bb76cf..38cc149 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,6 +55,7 @@ dependencies: geocoding: ^2.0.0 flutter_map: ^6.1.0 url_launcher: ^6.2.4 + google_sign_in: ^6.2.1 dev_dependencies: flutter_test: From 4e5fdb266778a9df355c771d576d9e7548ae8f46 Mon Sep 17 00:00:00 2001 From: "Md. Kais" Date: Sun, 28 Jan 2024 19:10:02 +0600 Subject: [PATCH 17/19] Item History + major issues fixed --- lib/Components/navigation_drawer_widget.dart | 4 + lib/main.dart | 7 +- lib/model/UserModel.dart | 43 +++-- lib/pages/foundItemList.dart | 27 +++ lib/pages/itemHistory.dart | 173 +++++++++++++++++++ lib/pages/leaderBoardPage.dart | 48 ++--- lib/pages/lostItemList.dart | 34 +++- lib/pages/postFoundItem.dart | 32 +++- lib/pages/postLostItem.dart | 33 +++- lib/pages/profilePage.dart | 1 + lib/pages/registration.dart | 7 + 11 files changed, 364 insertions(+), 45 deletions(-) create mode 100644 lib/pages/itemHistory.dart diff --git a/lib/Components/navigation_drawer_widget.dart b/lib/Components/navigation_drawer_widget.dart index 995e533..2079b8b 100644 --- a/lib/Components/navigation_drawer_widget.dart +++ b/lib/Components/navigation_drawer_widget.dart @@ -9,6 +9,7 @@ import 'package:retrieve_me/pages/postFoundItem.dart'; import 'package:retrieve_me/pages/postLostItem.dart'; import 'package:retrieve_me/pages/profilePage.dart'; +import '../pages/itemHistory.dart'; import '../pages/login.dart'; import '../provider/navigation_provider.dart'; @@ -175,6 +176,9 @@ class NavigationDrawerWidget extends StatelessWidget { case 'User Dashboard': navigateTo(ProfilePage()); break; + case 'Item Case History': + navigateTo(ItemHistory()); + break; case 'Logout': navigateTo(LoginPage()); break; diff --git a/lib/main.dart b/lib/main.dart index a40da97..8c0fa92 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,9 +2,11 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:provider/provider.dart'; +import 'package:retrieve_me/pages/itemHistory.dart'; import 'package:retrieve_me/pages/leaderBoardPage.dart'; import 'package:retrieve_me/pages/login.dart'; import 'package:retrieve_me/pages/profilePage.dart'; +import 'package:retrieve_me/pages/registration.dart'; import 'package:retrieve_me/pages/userPage.dart'; import 'package:retrieve_me/provider/user_provider.dart'; @@ -36,8 +38,11 @@ class MyApp extends StatelessWidget { initialRoute: LoginPage.routeName, routes: { LoginPage.routeName: (_) => const LoginPage(), - UserPage.routeName: (_) => const UserPage(), + ProfilePage.routeName: (_) => const ProfilePage(), LeaderBoardPage.routeName: (_) => const LeaderBoardPage(), + UserPage.routeName: (_) => const UserPage(), + RegistrationPage.routeName: (_) => const RegistrationPage(), + ItemHistory.routeName: (_) => const ItemHistory(), }); } } diff --git a/lib/model/UserModel.dart b/lib/model/UserModel.dart index e9c282a..588471c 100644 --- a/lib/model/UserModel.dart +++ b/lib/model/UserModel.dart @@ -1,10 +1,6 @@ -import 'dart:ffi'; - import 'package:cloud_firestore/cloud_firestore.dart'; - import 'image_model.dart'; -// import 'address_model.dart'; const String collectionUser = 'Users'; const String userFieldId = 'userId'; @@ -17,6 +13,9 @@ const String userFieldProfession = 'profession'; const String userFieldContact = 'contactNo'; const String userFieldEmail = 'email'; const String userFieldThumbnail = 'thumbnail'; +const String userFieldLostProductIds = 'lostProductIds'; +const String userFieldFoundProductIds = 'foundProductIds'; +const String userFieldMessageProductIds = 'messageProductIds'; class UserModel { String userId; @@ -29,6 +28,9 @@ class UserModel { String contactNo; String email; ImageModel thumbnailImage; + List? lostProductIds; + List? foundProductIds; + List? messageProductIds; UserModel({ required this.userId, @@ -41,6 +43,9 @@ class UserModel { required this.contactNo, required this.email, required this.thumbnailImage, + this.lostProductIds, + this.foundProductIds, + this.messageProductIds, }); Map toMap() { @@ -54,20 +59,26 @@ class UserModel { userFieldProfession: profession, userFieldContact: contactNo, userFieldEmail: email, - userFieldThumbnail: thumbnailImage.toJson(), // + userFieldThumbnail: thumbnailImage.toJson(), + userFieldLostProductIds: lostProductIds, + userFieldFoundProductIds: foundProductIds, + userFieldMessageProductIds: messageProductIds, }; } factory UserModel.fromMap(Map map) => UserModel( - userId: map[userFieldId], - firstName: map[userFieldFirstName], - lastName: map[userFieldlastName], - address: map[userFieldAddress], - userCreationTime: map[userFieldCreationTime], - rating: map[userFieldRating], - profession: map[userFieldProfession], - contactNo: map[userFieldContact], - email: map[userFieldEmail], - thumbnailImage: ImageModel.fromJson(map[userFieldThumbnail]), - ); + userId: map[userFieldId], + firstName: map[userFieldFirstName], + lastName: map[userFieldlastName], + address: map[userFieldAddress], + userCreationTime: map[userFieldCreationTime], + rating: map[userFieldRating], + profession: map[userFieldProfession], + contactNo: map[userFieldContact], + email: map[userFieldEmail], + thumbnailImage: ImageModel.fromJson(map[userFieldThumbnail]), + lostProductIds: List.from(map[userFieldLostProductIds]), + foundProductIds: List.from(map[userFieldFoundProductIds]), + messageProductIds: List.from(map[userFieldMessageProductIds]), + ); } diff --git a/lib/pages/foundItemList.dart b/lib/pages/foundItemList.dart index 05f29bc..7e83487 100644 --- a/lib/pages/foundItemList.dart +++ b/lib/pages/foundItemList.dart @@ -58,6 +58,33 @@ class _FoundItemListPageState extends State { return ChangeNotifierProvider( create: (BuildContext context) => NavigationProvider(), child: Scaffold( + appBar: AppBar( + iconTheme: const IconThemeData( + color: Colors.white, + ), + title: const SafeArea( + child: Text( + 'Found Items', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + flexibleSpace: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111), + ], + begin: FractionalOffset(0.0, 0.0), + end: FractionalOffset(1.0, 0.0), + stops: [0.0, 1.0], + tileMode: TileMode.clamp), + ), + ), + ), drawer: const NavigationDrawerWidget(), key: _sKey, body: FutureBuilder( diff --git a/lib/pages/itemHistory.dart b/lib/pages/itemHistory.dart new file mode 100644 index 0000000..8d20866 --- /dev/null +++ b/lib/pages/itemHistory.dart @@ -0,0 +1,173 @@ +import 'package:flutter/material.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; + +import '../Components/navigation_drawer_widget.dart'; +import '../auth/auth_services.dart'; +import '../provider/navigation_provider.dart'; + +class ItemHistory extends StatefulWidget { + static const String routeName = '/itemHistory'; + + const ItemHistory({Key? key}) : super(key: key); + + @override + _ItemHistoryState createState() => _ItemHistoryState(); +} + +class _ItemHistoryState extends State { + GlobalKey _scaffoldKey = GlobalKey(); + // Example user ID, replace it with the actual user ID + String userID = AuthService.currentUser!.uid; + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (context) => NavigationProvider(), + child: Scaffold( + key: _scaffoldKey, + appBar: AppBar( + iconTheme: const IconThemeData( + color: Colors.white, + ), + title: const SafeArea( + child: Text( + 'Leader Board', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + flexibleSpace: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111), + ], + begin: FractionalOffset(0.0, 0.0), + end: FractionalOffset(1.0, 0.0), + stops: [0.0, 1.0], + tileMode: TileMode.clamp, + ), + ), + ), + ), + drawer: const NavigationDrawerWidget(), + body: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111), + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: FutureBuilder( + future: _fetchUserHistory(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const CircularProgressIndicator(); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else if (!snapshot.hasData || snapshot.data!.isEmpty) { + return const Center(child: Text('No item history found.')); + } else { + // Display the fetched item history + return Column( + children: [ + Expanded( + child: ListView.builder( + itemCount: snapshot.data?.length, + itemBuilder: (context, index) { + var item = snapshot.data?[index]; + return _buildItemCard(item!); + }, + ), + ), + ], + ); + } + }, + ), + )), + ); + } + + Future>> _fetchUserHistory() async { + try { + // Fetch foundProductIds and lostProductIds from the Users collection + final userDoc = await FirebaseFirestore.instance + .collection('Users') + .doc(userID) + .get(); + + final foundProductIds = + List.from(userDoc['foundProductIds'] ?? []); + final lostProductIds = List.from(userDoc['lostProductIds'] ?? []); + + // Fetch details for each foundProductId and lostProductId + List> itemHistory = []; + for (var foundProductId in foundProductIds) { + var foundProductDoc = await FirebaseFirestore.instance + .collection('FoundProduct') + .doc(foundProductId) + .get(); + + if (foundProductDoc.exists) { + itemHistory.add(foundProductDoc.data() as Map); + } + } + + for (var lostProductId in lostProductIds) { + var lostProductDoc = await FirebaseFirestore.instance + .collection('LostProduct') + .doc(lostProductId) + .get(); + + if (lostProductDoc.exists) { + itemHistory.add(lostProductDoc.data() as Map); + } + } + + // Sort itemHistory by date in descending order + itemHistory.sort((a, b) => + (b['DateTime'] as Timestamp).compareTo(a['DateTime'] as Timestamp)); + + return itemHistory; + } catch (e) { + print('Error fetching item history: $e'); + return []; + } + } + + Widget _buildItemCard(Map item) { + // Customize this widget based on your UI design + return Card( + margin: const EdgeInsets.all(8), + child: ListTile( + title: Text(item['FoundItem'] ?? item['Category'] ?? 'Unknown'), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(item['ItemLocation'] ?? 'Unknown location'), + Text('Date: ${_formatDateTime(item['DateTime'] as Timestamp)}'), + ], + ), + leading: Image.network(item['ImageURL'] ?? ''), + // Add more details as needed + ), + ); + } + + String _formatDateTime(Timestamp timestamp) { + // Format timestamp to a readable date format + final dateTime = timestamp.toDate(); + final formatter = DateFormat('MMMM d, yyyy h:mm a'); + return formatter.format(dateTime); + } +} diff --git a/lib/pages/leaderBoardPage.dart b/lib/pages/leaderBoardPage.dart index 1d51a42..f97dcfe 100644 --- a/lib/pages/leaderBoardPage.dart +++ b/lib/pages/leaderBoardPage.dart @@ -24,34 +24,34 @@ class _LeaderBoardPageState extends State { return ChangeNotifierProvider( create: (context) => NavigationProvider(), child: Scaffold( - key: _scaffoldKey, - appBar: AppBar( - iconTheme: const IconThemeData( - color: Colors.white, - ), - title: const SafeArea( - child: Text( - 'Leader Board', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - ), + key: _scaffoldKey,appBar: AppBar( + iconTheme: const IconThemeData( + color: Colors.white, + ), + title: const SafeArea( + child: Text( + 'Leader Board', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, ), ), - flexibleSpace: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color.fromARGB(255, 45, 44, 46), - Color.fromARGB(255, 5, 63, 111), - ], - begin: FractionalOffset(0.0, 0.0), - end: FractionalOffset(1.0, 0.0), - stops: [0.0, 1.0], - tileMode: TileMode.clamp), - ), + ), + flexibleSpace: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111), + ], + begin: FractionalOffset(0.0, 0.0), + end: FractionalOffset(1.0, 0.0), + stops: [0.0, 1.0], + tileMode: TileMode.clamp), ), ), + ), + drawer: const NavigationDrawerWidget(), body: Container( decoration: const BoxDecoration( diff --git a/lib/pages/lostItemList.dart b/lib/pages/lostItemList.dart index 405ef92..e7c291f 100644 --- a/lib/pages/lostItemList.dart +++ b/lib/pages/lostItemList.dart @@ -60,6 +60,33 @@ class _LostItemListPageState extends State { return ChangeNotifierProvider( create: (BuildContext context) => NavigationProvider(), child: Scaffold( + appBar: AppBar( + iconTheme: const IconThemeData( + color: Colors.white, + ), + title: const SafeArea( + child: Text( + 'Lost Items', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + flexibleSpace: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111), + ], + begin: FractionalOffset(0.0, 0.0), + end: FractionalOffset(1.0, 0.0), + stops: [0.0, 1.0], + tileMode: TileMode.clamp), + ), + ), + ), drawer: const NavigationDrawerWidget(), key: _sKey, body: FutureBuilder( @@ -67,11 +94,13 @@ class _LostItemListPageState extends State { options: DefaultFirebaseOptions.currentPlatform, ), builder: (context, snapshot) { - return Container( + return SafeArea(child: + Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: [ Color.fromARGB(255, 45, 44, 46), + Color.fromARGB(255, 5, 63, 111), Color.fromARGB(255, 5, 63, 111) ], begin: Alignment.topCenter, @@ -83,7 +112,8 @@ class _LostItemListPageState extends State { viewSearchBar(), queryLostItems(), ], - )); + )) + ); }, ), ), diff --git a/lib/pages/postFoundItem.dart b/lib/pages/postFoundItem.dart index 7c51384..d7bb341 100644 --- a/lib/pages/postFoundItem.dart +++ b/lib/pages/postFoundItem.dart @@ -71,7 +71,35 @@ class _PostFoundItemPageState extends State { selectedImage != null && dateTimeController != null; } + Future addFoundProductToUser(String userId, String lostProductId) + async { + try { + // Reference to the user document in the database + DocumentReference userRef = + FirebaseFirestore.instance.collection('Users').doc(userId); + // Get the current data of the user + DocumentSnapshot userSnapshot = await userRef.get(); + Map userData = + userSnapshot.data() as Map; + + // Retrieve the existing list of lost product IDs or create an empty list + List foundProductIds = + List.from(userData['foundProductIds'] ?? []); + + // Add the new lost product ID to the list + foundProductIds.add(lostProductId); + + // Update the user document with the new list of lost product IDs + await userRef.update({ + 'foundProductIds': foundProductIds, + }); + + print('Lost product ID added to user document successfully.'); + } catch (e) { + print('Error adding lost product ID to user document: $e'); + } + } Future submitFoundItem() async { if (areAllFieldsFilled()) { try { @@ -94,7 +122,9 @@ class _PostFoundItemPageState extends State { 'LoserID': loserID, 'IsRetrieved': isRetrieved, }; - await collectionReference.add(foundItemData); + DocumentReference docId= await collectionReference.add(foundItemData); + print(docId.id); + await addFoundProductToUser(userID, docId.id); showDialog( context: context, diff --git a/lib/pages/postLostItem.dart b/lib/pages/postLostItem.dart index 8bc38ac..897a108 100644 --- a/lib/pages/postLostItem.dart +++ b/lib/pages/postLostItem.dart @@ -85,6 +85,36 @@ class _PostLostItemPageState extends State { dateTimeController != null; } +// Function to add a lost product ID to the user's document + Future addLostProductToUser(String userId, String lostProductId) async { + try { + // Reference to the user document in the database + DocumentReference userRef = + FirebaseFirestore.instance.collection('Users').doc(userId); + + // Get the current data of the user + DocumentSnapshot userSnapshot = await userRef.get(); + Map userData = + userSnapshot.data() as Map; + + // Retrieve the existing list of lost product IDs or create an empty list + List lostProductIds = + List.from(userData['lostProductIds'] ?? []); + + // Add the new lost product ID to the list + lostProductIds.add(lostProductId); + + // Update the user document with the new list of lost product IDs + await userRef.update({ + 'lostProductIds': lostProductIds, + }); + + print('Lost product ID added to user document successfully.'); + } catch (e) { + print('Error adding lost product ID to user document: $e'); + } + } + Future submitLostItem() async { if (areAllFieldsFilled()) { try { @@ -108,7 +138,8 @@ class _PostLostItemPageState extends State { 'IsRetrieved': isRetrieved, }; DocumentReference docId = await collectionReference.add(lostItemData); - + await addLostProductToUser(userID, docId.id); + print(docId.id); // ignore: use_build_context_synchronously showDialog( context: context, diff --git a/lib/pages/profilePage.dart b/lib/pages/profilePage.dart index c2e2a54..e4dd844 100644 --- a/lib/pages/profilePage.dart +++ b/lib/pages/profilePage.dart @@ -24,6 +24,7 @@ final FirebaseAuth _auth = FirebaseAuth.instance; User? get currentUser => _auth.currentUser; class ProfilePage extends StatefulWidget { + static const String routeName = '/profile'; const ProfilePage({Key? key}) : super(key: key); @override diff --git a/lib/pages/registration.dart b/lib/pages/registration.dart index 8de96d8..e78816e 100644 --- a/lib/pages/registration.dart +++ b/lib/pages/registration.dart @@ -20,6 +20,7 @@ import 'package:google_fonts/google_fonts.dart'; import '../model/UserModel.dart'; class RegistrationPage extends StatefulWidget { + static const String routeName = '/registration'; const RegistrationPage({Key? key}) : super(key: key); @override @@ -349,6 +350,9 @@ class RegistrationPageState extends State { final imageModel = await Provider.of(context, listen: false) .uploadImage(imageLocalPath!); + List lostProductIds =[]; + List foundProductIds =[]; + List messageProductIds =[]; final userModel = UserModel( userId: user.uid, email: user.email!, @@ -360,6 +364,9 @@ class RegistrationPageState extends State { rating: 0, contactNo: contactNumber, thumbnailImage: imageModel, + lostProductIds: lostProductIds, + foundProductIds: foundProductIds, + messageProductIds: messageProductIds, ); await db_helper.addUser(userModel); } catch (error) { From e66369507b457662b347735dffae37ef578b4058 Mon Sep 17 00:00:00 2001 From: ImranIF Date: Sun, 28 Jan 2024 20:00:00 +0600 Subject: [PATCH 18/19] modified title of leaderboard into item history --- lib/Components/navigation_drawer_widget.dart | 2 +- lib/pages/itemHistory.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Components/navigation_drawer_widget.dart b/lib/Components/navigation_drawer_widget.dart index 2079b8b..c70555f 100644 --- a/lib/Components/navigation_drawer_widget.dart +++ b/lib/Components/navigation_drawer_widget.dart @@ -177,7 +177,7 @@ class NavigationDrawerWidget extends StatelessWidget { navigateTo(ProfilePage()); break; case 'Item Case History': - navigateTo(ItemHistory()); + navigateTo(const ItemHistory()); break; case 'Logout': navigateTo(LoginPage()); diff --git a/lib/pages/itemHistory.dart b/lib/pages/itemHistory.dart index 8d20866..953c1e0 100644 --- a/lib/pages/itemHistory.dart +++ b/lib/pages/itemHistory.dart @@ -33,7 +33,7 @@ class _ItemHistoryState extends State { ), title: const SafeArea( child: Text( - 'Leader Board', + 'Item History', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, From f978a5b29c456ac2abf439dc044d0dad04e4536a Mon Sep 17 00:00:00 2001 From: ramisa-zahara Date: Sun, 28 Jan 2024 21:29:00 +0600 Subject: [PATCH 19/19] icon changed --- android/app/build.gradle | 2 +- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 8815 -> 12272 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 5366 -> 6203 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 14354 -> 19517 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 27095 -> 36633 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 42628 -> 55528 bytes macos/Flutter/GeneratedPluginRegistrant.swift | 2 - pubspec.lock | 60 +++++++++--------- pubspec.yaml | 2 +- 9 files changed, 32 insertions(+), 34 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 1f4f37d..61f7129 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -51,7 +51,7 @@ android { applicationId "com.kais29.retrieve_me" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdkVersion 19 + minSdkVersion 21 // minSdkVersion flutter.minSdkVersion targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 231166aa0c862d165ad33b62a1ed29f1cf8ab118..be663bbe713da8cd7741ff0762728811007cfab2 100644 GIT binary patch delta 11717 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 diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 860c899a89a7313ec2d720ed2d0b6a2c0e516462..d39fb75f50855bd5fba6fb6c8f6f74c8f4b4f5ee 100644 GIT binary patch delta 5600 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 jRaI4A(4Xz#e&O&xyQxBV2k{Nu5^GeU8Z|HJ?t z0RRF50|5a6000000000000svI2m%8H0SN&A!~j4M00II60s#Ym0|NsA1q2BN009C6 z1O*WW5+MKw69^(P6f!{-BT;b{Br{=w2{b}d7Z@f(Vse6!lA*D|(eeM<01N{G00I#M z5dc2`&{t;pG3DMBI=@}pa@JX^&6EsH$Lsn8D6`gv;6Cl}Q9CV@-UkdXylO^zvT5^1_Wc0lp|=f+=N~g&@0*sEwrA zW1$c37reZ4+v_!G+^>+zWUWND4nG?maBEg}WlI+=T%NUfgv^YvK^x6tK#eEFk$~r| z)!taRKW6GR?pL>jCb+K+Wg49=1+#~CyK{!K77FCVjCQ<#0_LBQWT?j7kRE0ca&XHW za%@(EWevYLT*TR%e1DJ}JyL3c$<;scEd7Vxc_tclKG$Sj|qH&z()i}a`Q;g+G%9VtrC{8hzEoxS9l%Y7v zl&s?k#&e%ftusha00AuC7hZOE_yhSm{{Z~;;~uI`x2<^p08_8e@#$Spc_=pPc)iiM z%at~#Vu`D*GBizrx8gP~rO@2-8GeIvEZHbEEw8sFlD(;GtC55YWoup4CZJ%qTXMO}gy0b&*Cik#*j|y?P@dM(sSNInPsS zgrZg7a)F&m?3+65pqEbQBt$Nt`xa58n87?xQcy?fMj?zZ?I5 z08d_$03`kZB$NCP^Zx)(Lr+unW}4%@SXSKKvu8!tT9}8gfD9yVXDpMmla7$wd~6&l z2pL7W@q~G181Vx~M+ON*7+ZNmZ9Ox`c-CK)WTM7l;1WvV-dUzC9atlb0?#zTA4F_* zjYB(~fIJ^TJlmaN_%9=>bn{X2N1 zbN=D2uA{kZj2{~bup&bi6Ix%a5#yI2$UnD>mXegA%gaTG?g9{rIXFXQ7+7pS5~D&3 z>0i(NpL`ulnY;zLtm7(_d2#c9M8frGoq{{ol|E0@!yB@n?i8`pY)cg+zWuEC?$0Q_ zM~?GcH9S^Q;drZMF}IDZb(vB!$qo2st58&$z*4^~4`QoMdWDT02rK&!!?!E;mf<6K zZ7J>319djDUaLqZfp>+7fjAnwBnu8pk#ltWBZ8jLPyL}P1i^$YEVM&^f#9_eL*X1# z-5y88F)N41SI19PCzg2L+!8#h(y?b=(YgY?n4ch@182vkZ!Gq6jB`Ax%jIlehSNlm zGSia3#=<2CtX6m>(F>&-&|f`tS+*^w^yP5FSi%*3>PFd9$n?T?g&hc6s{a5*ynJfa zm`+|^T+2;=^Ilh$(TwGPewi#^eR*Sozof&L{oNLn?nndoeX|V#wgl_I{{UYikM!rj z<6vIqY?3;LGGo`lJL}w1?fC(^j|6~7I`ne!pN}4K@#k`!j@Da8X+37#Fu=q|Yu(4U zE3yidVz(khi-%FQ$nf9CaP|Xx-9SP-soZ~soE5w&^^b#6# z85VqfCRt1MC`F0Db~_AqrI+@pJL~A%hx>cS_%xHYCiX>*l~~PtmLh1v{E^7csT5GF zKH~y1;fj*QG+dHfG0~a`?b3HS1-Gbj8|E%JiD{il8#vsJ+5{m0YEXq(qhs48n&GX* zI?Six=gWx}XCHpY#p|G0S&_A6qMf!$c zfo4~iMD$&sz$EDYJOTM64gUbscEO?j;4(lcq5#3b8U{}j8Bt&);hhsQB4IhgvRD{@ z?*+nCm3_l4m+6i@`-ZoLc9$82l z{P`R3N8pkEePKSuZq&8DMsvf*QFYa$$45wUuG20!?S&H^D$O%|QPV$dw^uEUOGnPs z5n-wA7>m?i#mg>TpeDz+jvT3gS>xYBaZPorlTJvS(w`nY!xMgrR*JKfX=zF#MJp0W zn%`vYCs>((2xp9fRf~rSqyC%yDA`&Tp`GSt0IJM3dZ}ge(E;!ro%m%6Nc6zC_iI%< zbGZC_YW`o@cP@n1UN0am8%Llz>fj+idv>r|^*NemwL}_x!G(T$$F`06r7jr@CBrJW zRl>6~X_A4HntCR_9_9}h$#NNb>4|PfVQkaEsRAm0!%`@)(5Vqb(snKa1tH>I(Z{&g z*5;ZkljEz@c9hYC#XXh`q1&>t3de3h@V$xCcKdb#KDBr|7+RD4uRD)-qLRZ(dHlAF z`na~6#&MTcmeRGQ8Om_4PwrAv>Z~rOmqZWFfb0JN#oO=+CtEu5e*^M-4@F)CWR_vs zb~f67AnRZ+`2PSO&WELoru>%cnZBO9@Xt-bgUkJOT9`5V6*|XdOpdbX&1ob_gwZxe zgxPYj@FUnBvDes3^4j`rD9dCd_*3vv>99WuB#7c`ylTM3!7ngnxuht z>pW;lSk?PS->4vfO7)T^Xh?FZWqP(if7?uYSf z!yZ7luEN{$``=<*Z;>q3YL}YkoZs{dC31*VbSi;^iy{HIE4dURrDNk>kah{v0A%Bu zlb2#OvPwP0lkv}Tc{dHiR>f1r;~}h%EQx0BK6IMb%H_++FlfZ=3ur%5-Fl6-y)Jow zFSHz6n`P$AWHK2fuk6e9Bx4%5cw$iQ#en$TQM_?2G z08uz6&X16P1HmAAh96FR909AjlcF1cWwFOZYz7;npg<%7G)B&~v%XgU08SSRe~ezb ze;CGb?a%clkiYZ%}@{1fg;JzMw6Mtk;%4 z{{Z>g0bOGXclQL*IvUsK)ikH|weAF21e)F}irAuL{_RMrSg#?7f8dVF-I7??>s{aG z9!Fq6-=~44cb6OaQ`1FN?%Mu;p>}c^*!i2*fZIU>IV(|`VWQ)~w8Y^*Yl*0~KO$>2 z{efQlQe&MnER%}t?ou*q*DB$Br`w#6uwGG8MtJFE>&8WU5x0{KsGqXIIoDQ#UdZHj zhDHZM?|WPCFAw*J7SiKp{XSZ>XxSb;ZfO4iT}+eJ=7f%h)gs+YcA}4e><+78A}8*c zMfk+w0b*=1Qyk|~*socC3f!Hua!uZMPS6xu!Z3=Qb!TwxD_yf|(PJtJN^?|?qFpN^ zz&-9P3^r@86yW1>oW{c~p#fd^tzNtlF=pEtAci>Nk(~bLc-i%!90BRFxSV?_)IE;K zEY8fpk>o2mEC-*$p1+@e9#5`;-QmifJBB+=m!dYOHR!nI8)AmrmAx-(yJ&rfbe9-; z`w*nu^_hD=WFNL9%PZk}PjlAcrEim>l^p?Su@V~%FJe*7a$onD?A6HJ&{IY^mMd|_ zKGo@2k|@?C3=5ci$F3HP>YS0B`33R2>x#I-Y^qy?5t-v1Z^B!iw?|6I$7Ae%8?P z-}BJkw0`cRO!LI&k2>Ft-aDjeRxueRwd{W#_kP?!_B)F{)0zZyNeU^x)Vf7xk_%%} z>Ihe&6%`mnx?60i`3$)o%DEJrhU~Kazore=B~U^b(U>7sK1Rlg-v0o{kO!$8PB|#V zBG#S4hC2Iym%-X-_#H{}t#)mbqE5|i^GJuj>3xq>o~`UFglvsYRE1S_E$UlYZ2JN6 zEdFXDCtqLTt&~%$R|BRafMUHiyL1d_k}fc*v#|)N1|1TuGgisLDw@cs(JMWu7Q_gT z_Pa?FEB8SkZKqZ(;14=Jq;H{W<~8m}QdB0xu~0gHh0z*fPlK_q^RGU#hq*i^c}nUi zigoLE@1AGc_XsF^3N`&dt|j&^@7ekWrfJT|Rka88Vg{a#O|qt$6nKQ)_KNkKd6JhE zNy<8O+<1Z-`=1rhICc^_DvTVKBAP{avsqHLX&s6@lSfgu@TimSjTD_|5TyQAnf@J~ z%_L8M7Jn&HV3ot<-(QcnC%T=#5fqL)ZyBOEnG)~s-@QcoUxDM;thjo7N=uI7M z<;!a|D{mHouWHo|0kSIh8k~Z4?!k_`RmB>Cf1;GJrydbH>bMk`GZol^O0%{EuiL+; z+&)u+oCmpc3qWnS$ynh6eHI!3E+u^%1e4o#%|4| z07@?8^0pR0P>!t?jD?6~RvR5&iQeqD>NbG)+7Zf zhuTYn$n2S*n|zq!9&KoR3VdomamX{2l4{^%oE*|(eZ2OQEzO(t)>>RX3ONe?x>!kn zp5an{+;mN)kq8<#CDcIu%CZ1-5AR>phZ**)HX9u!enHBeW8OA92r6TvkQObJnlf5B zdT6CM*=(M{q-YeWbmw04zu5uUnUS<>y$xooWQ?e)q;*==S1m#M{{ZX*Yhv9nXvHNt z&KfMp$tM0xVQ&cHeNpuExAgVH zq}2M{=aAnLU&V22RC~XAaZ|BXiV%J^j?!CsBW2o>?j;0|DWXTE6;X)4Up6$hqpfPU z&bozPl)T5UH+qy!N@HJ#EW{AgX|m0%7l5BGY`~y@XO#<*6Dmqx#Im50tYzA3`JI75(%{6<}F>SOqeFW27ORw`!(E5=R}G-@7YpJqY$mCux?nMMpRCn@>rU|5uPPqM@l1p? zYzQ0bbi-=FfgrYj{%-3=E$9k|xrquk-{{bgw`WqoaTc|D;Vq3ioaLb5tZsUxDJuzP zCSlJ^r|b?^7$GalxLa2*e-9f;TeCE^P!^uJC%Z_BJj(#`007Ar{Ps{=)ywv~-gxrS z*5mxbRH>Fz@X^aTRHu+r`(w1;60PQ8`SD)CJ5rCZWt}5`)R9`9rB*1+McXzTzQsPv zk7S4%yBYrMJvQWf&A42X$@IvOgBHt)MsQ4%;! zIx7&9!lYmx@)cp^Xm4JKeaZKRuN91Aa9^X#XP7R-NFA$Npq2vE{%O99+#apZv1AueYLZ}agAEYW^FI-Y%r2_R{^CMOy?d(M5q1SdofwakgaE4aXMKtRV4EqQrf|+@zMtD~m z!_AV(Db8AOR~XJ8K?!p#sf_&I{{WBszLis?qDHSOI=V;^ljCNQU&fcBg3Q|^N}!iI z*7xewM{c~Z353x!EeFoB{IQ6ngX1z8mQKMwB7?ul*dR~4U;;t~@BaWT>{h=oq~uVJgHcD;`2CR;6Ds64S|Z+=H(fY1nwTlm7sRTa}S*GQe41Y(0;b z;H{hHb=oSOmP)*OPv3Px`6IED*WDC;Rimh+5=Q3!SJ%&PsDG>q*pYLG`&n)~7nL3i zmn~2DbRX^#)WWvP*sv6olO>}JK$z-$%-^YhOy9d0Y`LY$$`n+Tl#ztUNXW>P`KO+F zudVXVJkpf;W|&**TjZ2W&k{?^Tdz8`t2z3&F;j*JVuG|uS}0IQ94Ng~IM4+|RUQ>k z0001g{rtqp@+%gnn$5dYPhxo_mTBdY=9+1wJ>-%}T$Xtqn6o<)#gCKfrrx_&tIt}0 z@Y}_JWJn(C*@>!GS$pltvd_BGo@gXJmfTR$!LXH|H6ezaz#$)!k@g#}?C5HS&fP*0(b@qY_4IleM?api7K3f(CA7W}a%CQWGAk4A}Qx%Nw z@%Bi`3nlxL0bYf7AWJ97Basv?Ng;24s%y)HWOc52F^|SY#yuw$avH-USX6uj*o-() z16*L`;EWauXe5l`gSjZ&WQ%DXM6m0vwUo+dF&tZwQi$jAxZJG>nJw3oAzm5aiHd!) z#AO64IyStGoqeDY<$dk9xjy!LL&UHCftT00iPLM{rArT#7_>n+U@;({LZ`!|qD_+QCa`!RMnYm`nfdkm7K235GPdtpVLtpgbS8kQy zfS!r!;2<}}a5*@lR?Dp@X&C7k@|Kmh>v?RzBqPod=VH>Oss??kw}b;6@ea_{*CetC9>64*1bJ4&SqhQ{3T0lmfIq=FM=I!*e1ty zydkEh9aBTF)!PYdL%t@{V{B6v^wEh7-?p*iKV6aIb)90GRp<38b%)MHFlkSin zhr(nfDJo79pG2uXn97o*EjUtCg(uZ2!qc2BDngW%rC3vWQge@0yEp}b*kw8)hKN7m zfzb#4L<8x_wc}-15UGj4Wp#FCWpBY&Sqi$g#+h~x`9GgX*R#BT)#zSY+Lj$DRn|5g z=X#|asC(&=_GrpoDziSyQ`(iW)RT?3Dojfxk?=C$<-I)FQufIB<{LRf7!6cSIB(dq+hXU_HHk5C+&f#i7W z$0>O3W2a#idv(#GDI%$31&Z<)k|_d?%Hf(h2FkX<+Yyt0jfjSclAWKBje~)P4cQ5K znL<(=Y+y{|8E~Ttd)m`2r`HKbu2i?3Q*1EXue#f7(Gt&MSmCV{lTR`06i7EDt*-$F z#{7OsAwcp-0G~mYjVyg>ZC`k5*RH+gu{@0$AR8pHEElo-1yD;9r39Z#8=^di?Cpa{ zKc2M}l5)F$qO$wLo^sOYR(qgo^}#Uhlb>vzZ(SJfe&_b09&Cwx=j56DV4ijl4PGtn zP9ly{K1r6LTF!Y98Z>gxR;+{qvWQRirn?vlzo_a$5&gZk+@O8J`iJEi4nJ#w@%+`w zoJ`0>-`oP-y5XC(NbC@1uZ@-1$Y{kPte$>WWp<5!SJ>b%J59Jt!idgR$oO=Z*b$64 z>b^DyOOLqQe=DlS8)S5^{9B>e#g?jRxLVNESyCpxJo}^iVd$Z`8DSr6oyk3D3VP!+1)+ zx6xjIxW~0#?@w+qpW#_owMPQ-W9Lodl;z7)nO_~k%(y}6k8?Bw#FOG;oziy ztb-nGvWiq(V*>;NMroBP&Ux|{>{qW+S=`pDtgu2!=&H=k_X2d}1E5Io6l+7%I}yQn zjt7zF`F1A*kEh9bH0eHPG>{`?EiywC0yyVjTC6e%mPw(h@U4m2rkFdoi-eaG&e~NY zC2tM9IvTRs5=%>tGb5}y+F>|!IL}mn`&|OnzP=<#NFzBx0O}zC6?nrp@*BpGWJvq$ z2bl;)00xe;?RTbA)=9`FHU#vq*)u7U1X>B zUdOPwJzrncsxnB!5z^A`l_4N3koDTcB@lS-P&t725v*AHkNVMz~kK zeHb}9Jvvgl2Yl%V|!pN*fYi;Yd8Ux;(XCo1D zU5{0ZCi`BhY1e_O2paQ+DV(^B<2hW~`jw<5D_<1P7vp9J^QJl{c2NE`umDyge~pht zxR0PdD^j{HW0-QQw>qOVwIsr0;4U?@91V`hNf;XZNoGdzt)Jk&*WNjQJcDVfRx8Tw z-aekHR~y0L5q##2>h3CVz^C5uh@Afbh)BE#SsN)!iEdbz0*7zh$YcZ>^1>I{uXXTw z+0BE8vqsaF>~Yo9ex}?%7XcCY2dssElxtuOYt~t`_k@`K)$RVa*Own4yu|@(qHdcVwpkv36@<@;1!X zPz9d6wc5O(u`ybWkjWDQS7_0y$T!gXZR0R7I*Ov?5ye#@uNnD&l0eZx8b+mELL`jJ zH14juW3U10JvAK}#oXVjJMOK|9yB@wn5ednbmfa)zUVEv(9@u8NsZgQw>HtQ%mYA( zuhDjHtCYCxT3s@g`8l>|N;;dX!a6>XR6~}j2mUA=en*vF;v6ZNLvHK!I`K_g7+)8}{jj~zkqnQ3s!lr}D^1q{;Pt>kA z^%16174g=8EH^AEEN>5D2i#;yASZ>gp=fw#7QwKmZ zkOY%D0(9Z~A`-;(0I4cL^uhXi_D%hm;n?A@h<*1 zZ@eMvwjd8n9#izKhrjQy4d?h;bn5W=@>Vlk+X#xVSBEu=iLYbq(1BD&D(CO4BIQ`Z z#aiSuOci0aQB5BORMCWo>8+BngKWDTbx%frwI=gfazrYrM~Sg+5s{_*m`JSIUxTK` zPOA;L;qamn7^NU%OT(jhnh;pHm*i6$&MlGS4jvH!DRA7+obriYqhxrod!i(5a0^n2?z?T~esi^LuZ9 zW&qTdvDH`v^DB=zmNBz0NBqj8>XDpJqQ2U~XpYNWh-dvst$!0dPBMbajl-PvqEfQi znM+l!n|*)prE}IAsDGD~?c5K<2_rU#t2@c^mpf78cuD^NPoLx;GNqN%HV+2@jWYa- zMgAJBa{iMTt)-taVzhfJ6v1jMniZ?s;VM^3N-lp3Lp{&tgeuke88|{T4qg8qJ0KNO#_bx1g{{WY`8D`RNTLxQk==M8C8j4<;utbX%)MLv&&XMm zkXXi+9~D@tvZ>a>$scv!_$%Rm`hU-+pBjLFPe()pd7Wjx=ixq7eCwk=;FDfsGE;oAETYuu<+V>XysA%?CL{a0Dn=So3Q zrW8$Vt384H4AgXo<3eSw4q=qc@tzR|M~;gz=JUDvaANgH+DnuvR;aUoNGKIk@L9bq z!UnK3@%%tW$V$4qKAdznX6c>5Cv~u(= zSnDjctX)_#DDf}~?OJ4Zg~=U(0FB=6@-L>&eVbeO47VcVmT52a+f!lqR986mLbWG! zf#Aio^coouv!cxekgLVim|LomF{bKHaiG1Ob-#J8!2vzc_cB?38gqGap1;&uzG~M4 zOiCd2j2`eu6*lKO42Q2S#6yU24~qH7Y# zYnJhds>6QTR_e5W@vj=pn8k*yEY)NA56_T^`P$z+iLN2)14Wnu2(sojTyBtb?X;d8b~%-GD((|uEjy3P?8J@$DAl@ zGG(xQUyxa@wQuI|i)$kkaR^~+u-Trxvc(YB$MT5QNfow#-y<>E8YZ#x?l(t<`-RK6 zrY>0~#o+UjSH~Hj<(4{A*Mj5_yo8e}foBj2Tker#4CKFUw>OwZF`S{a`YRd2u$1G| z{+_tTKc8QAez-jjlm2u7{GaeY>FWcZt9p&A1K!-Rv#X6nx3nzOZI?jW<;SJGI(QoT zLY*bAGh-=#tYL>|VPkFcP|bYqEb-tG4gntspvSV8zq591Ne*J1^0BJ~vCUtx`(raB z2^4=lR#fb&G&ds+9fRqA%b`V@ys<9YZpE~ql2$^SU3nqYjgKw0{E{>>1%zR0{>K_# z6O?+Xr<;2i#xv@lep^!gxz2N(W7jywbM)v^7!taFAQB4#2p^xxACCin>95bB23Jqq zjy!AzR$c!9r(i$G2mBvT6U4Vc#p?J?r%IV^!hn;pLs`pYJbb4BK4LKkiQz=fQlo_( z@!JMiW|fDKk^mvBsYt_5o$(}!cy3lbK2>y?dYwwhBQcjF{{Rq1&?C>2_&?1L`oiM( za(NDa8J>Z9Lj@e3Bs_$C3wi9N$m>kQVm6+;O(YC|b3-D4bah+!gym}2kv_@N+^e>% z4?^hrR2Ic0yPptpdoRPK4P)od*jK|8TjX<9N083LX6>cNiN z&vsTX_Kw7^?#=V2s~#^m_cqD%fkkVcYU#a~f7b5lcvqh~3qo(!sT12)68)wbC1o8C ztTvooPS*jnwK~c^s2uZfmfDa}&7UoQ5cEirPE(A?OK5h^;p<0bZj}i4Xc-ncBDTrY zO(ZfA@yf%xh67$%k7)-NBwZwz^p<4!z9Y6V$lXfG81UU&e{d)K{{Wv2GK1Q6si@E~ zY=m%=nnP<`)g;L2IN2XeC;su6gAEc!CB^3+t_O#UZKeB=-^Pq3w1~30jcBib`hpu^ z=>GtZ`u_me)XXyWV5;isN&B{cf#7||#{3<5{E@PKARi~PJiRyGq-`#lsuHbXxcJvy zX`LB$KbzX<`w$yjTy0IIaoRPiuDndC4OVaFQ?7M+8s)yh3prQCbXn&xI%Yv_Vl_B) zd0Y4>DPd^X$=|7(v1-j4*Q3XONFkO85-FZb5wvo_-X=0EWXOLfYRAxzAj(w1%X2vRg@P}>Ita~kuA()j zy^h(U>zxM1u83y`7YAb!p8;{u?(B)e6s)!_i)F}NpqLP10FDS336yYuna)Fz<#-zr zzE+MO2Q|Xeuz%_~8SJOpKKUzSEkdk`_Z5$!b|i)XX>s8EZyW9%S@JwG)EugeY*p@1 z%wV9Q4VKx`zC$rc{zxaFV;YdM07%%?r7WDubd1ecsc*eg9~rK9#J=dH>RRT2);(>e z_2p#vW1?yBdoIrEZ*rG^L>LUEmd0ka62Jv^v@ECrz=!fhqFvdzBh6=NJ?=Gw{;yHs z{WZHVO(rtiGIbf^FGGn1mp}@<+mZZOCiT<~jU770ym#ik)j2>`7Z8 zm=u~BXk_Gz)v?RY}d6Qno);gPfHrRUu%fidGu?b-JqNtvVb%OKl;$N{`24 zCTQmUDm?N^ut{PFOx9*uDlH0@?(ZH2gV98TMRBwgQa?M(Kc%g)F32p(CClsPkPNE_))gWmRTY_|&@vUc>@=?S}e;<9hSzQpJH9v5|s=40OBu!ueo4 z=#W1f(DUc~dR;u9&bl{m@}T}zdxuJPgfR+|$*9^~IFIEvu5E z4>Ky4in<3eENB7f3Etb(9eC2@ZI!zlOBq=j2qZn?jtEOGf}Jm7Q@@>Uk7MWYL2~@J zir>@^tGBg(A)X#@Mo;SX)?*sK#8UO8X8!z z#twev3b*z}tHzYDYJ{hhEi z!mV&QOF>M#O0>$=PLUax6#Fm4O@1dNsyv^%8B9Eu9mA?^D#en*<)=0A`AV-PX{WDV z)`9ZBG)p5y;AvPA{{Y;LhPDFh?ewnXTz3(jt&qXzarJVTy9eW%t(f~pb~k>rL6H^$bS*qih@Qlp^y~rNyvmBUM1HN@i-be7iEXYC!X%+p^TXULMHg z8V+E`d7dBrn8~&(jk|x-<%n2H@=nE6mSyVbght0lWtn&9M7QL(u+uJo zQn9l%F$)OskC&)tJ&-u^!^czn`6QkA{0RR5n7WypgKGG((NUM%4yc#D_aP56va0Yk zOBCHy0QvK9gkRyIE~A}THd;h?%8p_AxZ}W$L4T3^1IZbX+}pyeM_G9#%T>kNmGFuu ztnTq7qD!zU10-cw9^?`S@DGnZKW0RKlZr9NC&eMU6=WMdNJ2v$0)LMh2gn0j^)vqf zv7s5tUw6nKVtmO@_bVFz0FQ9A`*ELKdVfHD%gTSB^PFcN&VP*kXD2Pf9^d;bSGLdH z`r8aZCw_kA{Qm&1!6W<;>xg14Kit_yZ@~Wmf>}p_;Qim7@AA9+Z(o6)UnZP?=O@g) zy{xE(?|rSkV+rN!gv2zC)q>U#QuShFHg!O0@nN&7>U6lWW9Nl(GX<_vCD~?_3WNNM z@vk;37CYDsmOm{fX2on(Y;=_q;vpny%-TrZorIesKqq6+qipu-FXIH^AWHFrZHH$e&&X+8CV#?wjF4h)Zw_Jq-9AA zxRpY(Hcf2xB-U1pWv1}MeurMta#rNHX)OvOtYXZBMAIat82pO+byN;RLixr8f}rZUmV%Y5gv0*;ftZq!$y+yCT_>=7%*p3S5-Sn{L$IekLItuN zHS#O}0K2)YRx6t1t61ap?Z~c$W?K^1{@jbOIz~bQ8BYGdPRS&H>>pO!*!tHpp44zV zl4Pd&W#br+l1Wh5l47-014|>fZK@zpe3Ag(&yv!uJ{-=Btl5l&@+H;rlEYVLi46Iz zW5|+l!xTJ0q%!o_0%>T1iitwnPv5dUykScfPNZXndo8?`#5}hT`ikIjct`hRA-||d z3jY9c3Xo6dN606C{(qC>(_Ty^;r7Z*2~q>Jb6LtUl(t~cGNrKRyDhH^Zwgy}pHZCP82MglLElSC zg~w&=%LG8{WU%rH1Red~l1BYYVObv;U3?vhgDD;~W|P5x-+~F>{{YDJn7sb^9@}0u z0|m1m3_ZkwuM@i2Mc4aVT%eXFJ_4e0u)VRD&ZxSlxcesS~6~U9AH-9 zksBZ?B~nT4-x#aP?A*v_C$)7klEEAmCb1;3NMcB&LpsUax@mwhhYH<6ky~U4jzM}% zN+dL4iW6ghVp$M%e!Fqt{{VnN-n@{+0;kWc4#O-7I~;Si$paG?Avg-GQdoBdN~Sou zHnTM(hf7n=K7ZRdVM%n9zPHQA$oI^pFAK6TBw?eAu!%cHgYl(bwFmC-0-yjBur;In z`diz3BE6|=L?^fKSbEVpDwA4R-JprsXsSHD5sHw1RSDL#JwMHh`gHn=51Mu-MrsY! zr8*V;Ds}27bLvWDKGvmd`bC3QwD}tH6+Lkz;te-DY5BKZMB9P9)BEYCwKGpz%vNyrZYqf}3 z93XRlDESY_r9W_FbVlCwY5ufXB~9btcf4JQrCt{0;== zJ6NhE=Ntr6KGjFG2`>!Us2N2t&Rr8EA-D3%+ug-;$zXi}6qxwh7di_e>^pRQfZ85N z*(39<9r`BXq^%}W31#XTHUldJjeL*Kf(So<{`&QHd7yVtZ!P8HD_BY0q>&#n)0SdL zDv@`d)^{deh|>EqPB7|?vN3UXXyc>oSgsDaI3HCue5`CP3CVJZ8Bjbrd1+VWH=&9t z%veQ5j(A0i&oApCljD^LF}NtK#T)+s3O4+BJy~etnp}KN%@Vz%@&PBuC`LjHt821< zX}YLzH{14|{tDV3E%Q+{n$Z^y;PM*}W_B^Z%|@%pmr??tO>M_o%Q+VYxZ5d9NNXs= zZYi}PNy=8QUtg|4$}DJ)==^B;(JO|mPRHj=vJC^{#*g{f@#}Z=X!oVReRt$2vRLaw z&e(bK5Apc_0GKD%b^NhbH0FryyNYp)|Nyb}GESLx?6wkFP4xehXlr`i7JPAW06>Kpr?82j1T zRaCal^goljgY|*NGWl*1hR0y4Wb-!Tv%ubdZ%%1zMY%9Zq4zk>(I76G9GLiAELHiiWTPMbG;Du)gV^&?C=ukZ;6&~4dK^c^AOYi?K5u`Y9PIHqZ7 z5G;F>W!W}W#PrJ0XWnroTrMjjbok+x<4BJY_52ZIJcdWY7+0nle#Yh?lK|4&{+&VO zvm*Qy;7T<|#AQ%Y7|Q_7*tCRbF_AnFJSKjwc+OunjmE)*p_0nU95)hwK@e*)A!|6s zK+of@#BN6Xkh<2F%aZV;r?f8H(EIZ9eCgh$)egw@e$@^VH$`>k=h8H}UvA8o zwb2NMDp-UX%dg84(hfLhg<90(SY>%l`@NZ#w>ZiEpC5*|9Hu8pt>dfOnnWO~kvxPs zKmh6i9e4JDzZM7C92JUx{?zblcSYKk>G9lUTUAzRA$VqvxGs`Lq^h`M)bH>^56C(s zdQ`6#-?!}=xNj)ENqDm0=3p*#sXr#28Emb`N1ll&!$7*o4r}!IcF2%IA;=QVKOWM~ zapoaCt2<_;M!3 zydT_vA%o!P;(#D2K$hwZ2*#G%>>(>@ZV&UA#C)eR3K+XwW>CZ~<7m*vR52fDQPgM= zyg80Af}pVK3nWiF#;(ChRXwzIqfK+SD(jXv{{TbksGeKg#nLEK6S5K7g1y^T9bJu7 zWX-@qtFKFK0pb1~q(!2X2<67Q+EAAO7c(p&4Y=+VjlX)ZIE-Z+q`BMi;`0I-F*8@h zSGQ(xwbAZ>tkuQf@EB}AMhwhL9;5=kibvAlGUfRP!d2rOTK@ntwid0bdyk*NYvT>=86L-J)E?Rps-Gq@=MZtTnk;NO>yiFi0G}WuFutbk8?rqn;+O* zsuLAwsO6D8uA%BNl)asEt5u9BO-Xgw&?}nOrJ^~1`1g#7k41UL#xLp9lUA`#JjP!c zlg3lG6{M`So;zJ*luBWO+=0bYBO;khDb?Axt*G@tul;rVAz}*>P`8+=c6cR3l3K7& zP|nf1#P(s1>{7`JF-CZnUhardWQ>sEJnJnrH>xjB*+%6m+?`CFYZ*!Xl@q`2^ip#@ z5kHxK0j_fM`u4E|^z4G+J@Ae(EP~w1o*>_y4m*~xaqc&@T(6hKj7~3+$8e{k-Da9N zA<4D4c6vs^>$1i`>RGk2M}ik%j(Y+1qwJ@*=aK&a>00L`_ldI?>|V#4RGW_1!wJ47 zFj5j`uSja7i70}=>ItvN83#&mQBQGf#<>KDc^6V}i8X1e#GxwG4{-Yw%SEMaR zJBE!UuCXegi9n4@Z|%|l0FX82Ut9kGPn?51*ZAHyImB^>8p#eGIN-=6Qo|S$&H96X zcr*Occ5sZpZ)O|OKA@Q8Um*^>+e7TTd(JwvHiUm#b~Y5Z999yPW7YKf=Q&nC&OLMg z06hNy&+1YAv%Y|{Vle*zX#K?0Is-#mG3);T%lZ8H*Qhb|k?hXDxtq;~*NtK!Ctf^% z-w4@00Q?iL#`oyW;Qs&~ozrb96RY-rWfJGJ`F3Q%So?3NMSbM7} zWGepv405>(*Qp_peaNGKb(5Eh;Q78c7kia)D!JTqBzNl4KibhxT1@HD^}r+ zlt>e|f$^6G{aY6j}C zrd^y+if(p9n(HSj1h!+%6tLJeM*r{4>f~W^mCj%0BMw z%hX<;KJ{dgd*5tQckL%)Zhe57txj4I%HK}gs0CNE5;dIZBur+t`JJ`0jRE!v3HF$; z0@YrhSl3l6d1Kk6;USD&a7!X(hZ^QHay}yU>EZKH@q;0nOJcnU?WFJVvZ5nAe`^d9 zBlT$=m?#VY@1g-89+%tScrX?7mhcrhZX#nWRDZ42uNQF~h$WG0&H9EBG?D0bRCbag z3WAC1Inlm7e3xh|?0dJ!yLP6A-}Wnn#=rYcgjKW|X&9LIWuBthCiV52aZT*1-oG3t zhz{N`vXc-{h7>VJ<}l&L?c-PRf1LX3QLkc_S28;vO0Z0^#9>vUkXJ|* zR3kGp6i2>)Sbo-fr(cIA7n0}roAJynSj%o=B~ z)sNLX5hqyU1B*iIYu=ulf7#?u^PFYww{(|{m#S1@_twSLP_#GL7wzVL#vfnAM8XuQ zm$1vODY)U%!(+6{J;_cpf&O#s&pPDyYue-do}UrK1si{{{US708V@_0Qla2#zMsqY{mF1-nOws-lne?nk%u2fL(gM5o@$Szhoo!^2>N zBo+jpRlnX(tvqFae{^uZ=KCL(&R`+OTCFW!4Pv>ohoJS0lE;v1U)25^QyJM1LeNDr zbdFT9vHauo6k=8C z-`b}s%5b@l>0j8EKch-fM<4_U8#y#`f;P@oetidR25joOGn-bxn-)VC66lxL z`rgk)T%X3DyZB>kpj0j4L^}7oEo3>I$qvWy?{#R$z1c@Ql5d4&%v*aT50z|Dp=ODc ze*vqlYeEmefBRqN{GI5HRz64c?ZIA4;~(vYA#p7%!i(bhZ!*AgXet)|&wE)ZGhBYf z)Bcor*JG-R{I;M%S+0d`HD3udnn6^ zWhl-)e?_O}xdmnwaydp&SMHfHQ8@&j-Bv7Qi~D~7w~{}BuT2~$(VaQ!G@OYzb~5QQ zs?@=bW0$Uqu0&=_m-!ww-{e3YmMY_>`s}bij1F?_E>rA^<+7RkLW83(3WX)IYc}c5 zg|y0<4nsI*N^YigVEZk8a3FB*MmSkfqh$oae+Vs6D-R!fi9CNHwU(V}{MozCV=`Ez z%g5q|#42>_^DwD11F_gd5!7t<(Db7BE7)t^(nl8}kZ_!4B`;Qs5zKMx?iH(eypd*_ zt7I{X*{Znv1>q@Ot_xHw$_!g)aT9v8+<(t7FfEM@eu}z6gzF6fu9(K@ZU8}?c}mJf ze~G<93sP(l)TKN2ipy$N6t97&UdphkOn(>S?R93GhQ&rwUPE@oIGYEyiQ7C@EKbiM zBnBwNpDx<;FP{2^_fk9|tzX_~vkpEeTDCT?A;;RCNGj8OvtjX-kf(-lB~IHafSrObsa1mPKR%k}Ve{b2A9&FgTc;H$~-sNZQ84bL(lzJ^rd$F8P zO7`*781cBcrH87Om2SmT&)f_#fppC8}JyKk9tHo8B2#mSFJM#$Cxc zQb$>TR4oq8F3CIcy8b-+f^DrerEO%2%j8DvmKN4uc1A*+ReAXG(&x1Z8Huu`f0Uq;nOlH7&7x2KdviJjD2dd5wL~AHn+T`gGCR#sf%nLbR zg}2&m({*#ANbS9|586ot`hny5s#%*z zEpYxX4lWmrWF(~(c(M`JZLa7;nB){|PcrBQ5>665hLE4MFwaztzC+lpM{n&CR^|YM zP~A4UrhA%4nW=S%lnTxse{xZ(hOD_?Zgx^6GD#Sclf4fE91cYSKC_j!L8OE73{SYZ zna}ioRYMU-1?dcQZyEdl01nd0UM4Nz5*bu)f3$h^XFa;)e@WaM2^@L;1()P`+YKw^ za(tGz8qCOhN?tf=*R7hH8&<4q)lw?430$aYr$$C)5|AwQf09Okq4~Btew909 z*Lw@2q%RvvRe{{Xy8DbNaKRt!d)LFTr?^C9j%E zGExpQF%%CHHsh{me_lsw8#!4b#Ecbq>|ByqM3jpJvHDcC3_l@NC*N1jt<$$%d$B57 zyPf&EJQ3=2u3zO|f9E(Fgh28Bh?4#D(EEp7Y%3!cDuZn>GqUE0W)-Ly6haq=(`XObY>Gy~g^R zgN|fp!C`pqi}&wSNpP|J>GIo(X^O)v_;_NMC0ecc6ZKfMu<_c-Q*mkO)`g*I{{a8l Di|yb2 delta 13816 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 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 4edee25da46e2b0b96a9ec1f8ae3664bdbd76a3e..324460ea25f4ca9aba28bb23b2b26edb4fc289a4 100644 GIT binary patch delta 36269 zcmV)mK%T$X(*c>D07kVF(o?aeMIwaXY;a$frPx$CM*e^MAU$XxmIPTQ&AxhRELI+m2)OjrUfvlL22qwqk8)Ei1=`p z%X^BS;;JoIIH`yG>8L7Vh!6YE5{}sY_#=Wkk5TJQFL0^&e<~aOlCrZUMJ+Yr-8Dlv z;G}TJP-K=&@#Vy>=Lc$&$5Rj>hzIBp5$~f2l%eoF2=pfJp!;{}=tt~68g~X_6V#zW z%KC^oAc6;P;s;O7R1o2|qYmo%Rv%^!g024mD`CCL;Eue&06qi%0DrgspXfigjJu8A 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 delta 26656 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 literal 42628 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 TJ+?&{b*ZoK9?&T3e{=r_d9O!^ diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index aa4a268..667e7a7 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,7 +11,6 @@ import firebase_analytics import firebase_auth import firebase_core import firebase_storage -import google_sign_in_ios import path_provider_foundation import sqflite import url_launcher_macos @@ -23,7 +22,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) - FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 7b54a3f..4f91905 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -205,10 +205,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.2" convert: dependency: transitive description: @@ -221,10 +221,10 @@ packages: dependency: transitive description: name: cross_file - sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + sha256: "2f9d2cbccb76127ba28528cb3ae2c2326a122446a83de5a056aaa3880d3882c5" url: "https://pub.dev" source: hosted - version: "0.3.3+8" + version: "0.3.3+7" crypto: dependency: transitive description: @@ -556,18 +556,18 @@ packages: dependency: transitive description: name: google_identity_services_web - sha256: "0c56c2c5d60d6dfaf9725f5ad4699f04749fb196ee5a70487a46ef184837ccf6" + sha256: "000b7a31e1fa17ee04b6c0553a2b2ea18f9f9352e4dcc0c9fcc785cf10f2484e" url: "https://pub.dev" source: hosted - version: "0.3.0+2" + version: "0.2.2" google_sign_in: dependency: "direct main" description: name: google_sign_in - sha256: "0b8787cb9c1a68ad398e8010e8c8766bfa33556d2ab97c439fb4137756d7308f" + sha256: "8f8b94880f2753ccb796744259da529674e49b9af2e372abf6978c590c0ebfef" url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "6.1.6" google_sign_in_android: dependency: transitive description: @@ -580,10 +580,10 @@ packages: dependency: transitive description: name: google_sign_in_ios - sha256: f3336d9e44d4d28063ac90271f6db5caf99f0480cb07281330e7a432edb95226 + sha256: "8edfde9698b5951f3d02632eceb39cc283865c3cff0b03216bf951089f10345b" url: "https://pub.dev" source: hosted - version: "5.7.3" + version: "5.6.3" google_sign_in_platform_interface: dependency: transitive description: @@ -596,10 +596,10 @@ packages: dependency: transitive description: name: google_sign_in_web - sha256: a278ea2d01013faf341cbb093da880d0f2a552bbd1cb6ee90b5bebac9ba69d77 + sha256: "794f5494a945d6dd2654c52f979594ecd2558e5c82ce8272295ba371c93015e6" url: "https://pub.dev" source: hosted - version: "0.12.3+2" + version: "0.12.2+1" graphs: dependency: transitive description: @@ -796,10 +796,10 @@ packages: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.9.1" mgrs_dart: dependency: transitive description: @@ -1041,18 +1041,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" stream_transform: dependency: transitive description: @@ -1089,10 +1089,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.6.0" timing: dependency: transitive description: @@ -1169,10 +1169,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b + sha256: "7fd2f55fe86cea2897b963e864dc01a7eb0719ecc65fcef4c1cc3d686d718bb2" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.2.0" url_launcher_windows: dependency: transitive description: @@ -1185,10 +1185,10 @@ packages: dependency: transitive description: name: uuid - sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 + sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f" url: "https://pub.dev" source: hosted - version: "4.3.3" + version: "4.2.2" vector_math: dependency: transitive description: @@ -1209,10 +1209,10 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.1.4-beta" web_socket_channel: dependency: transitive description: @@ -1233,10 +1233,10 @@ packages: dependency: transitive description: name: win32 - sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" + sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574 url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.1.1" wkt_parser: dependency: transitive description: @@ -1262,5 +1262,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0 <4.0.0" - flutter: ">=3.16.0" + dart: ">=3.1.0 <4.0.0" + flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index 38cc149..1763544 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: geocoding: ^2.0.0 flutter_map: ^6.1.0 url_launcher: ^6.2.4 - google_sign_in: ^6.2.1 + google_sign_in: dev_dependencies: flutter_test: