diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index b40cdf6..63a0c1a 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -11,32 +11,38 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - target: [Android, Windows, Linux] + target: [Android, PlayStore, Windows, Linux] include: - - os: windows-2019 + - os: windows-latest target: Windows build_target: windows - build_path: build\windows\runner\Release + build_path: build\windows\x64\runner\Release asset_extension: .zip asset_content_type: application/zip - - os: ubuntu-20.04 + - os: ubuntu-latest target: Linux build_target: linux build_path: build/linux/x64/release/bundle asset_extension: .tar.gz asset_content_type: application/gzip - - os: ubuntu-20.04 + - os: ubuntu-latest target: Android build_target: apk build_path: build/app/outputs/flutter-apk asset_extension: .apk asset_content_type: application/vnd.android.package-archive + - os: ubuntu-latest + target: PlayStore + build_target: aab + build_path: build/app/outputs/bundle/release + asset_extension: .aab + asset_content_type: application/x-authorware-bin # Disable fail-fast as we want results from all even if one fails. fail-fast: false steps: # Set up Flutter. - name: Clone Flutter repository with master channel - uses: subosito/flutter-action@4389e6cbc6cb8a4b18c628ff96ff90be0e926aa8 + uses: subosito/flutter-action@v2 with: channel: master @@ -46,12 +52,13 @@ jobs: sudo apt-get update sudo apt-get install -y libgtk-3-dev libx11-dev pkg-config cmake ninja-build libblkid-dev - name: Install Android dependencies - if: matrix.target == 'Android' - uses: actions/setup-java@v1 + if: matrix.target == 'Android' || matrix.target == 'PlayStore' + uses: actions/setup-java@v4 with: - java-version: '12.x' + distribution: 'temurin' + java-version: '21' - name: Enable desktop support - if: matrix.target != 'Android' + if: matrix.target != 'Android' && matrix.target != 'PlayStore' run: | flutter config --enable-linux-desktop flutter config --enable-macos-desktop @@ -61,11 +68,11 @@ jobs: # Checkout NSSL code, recreate missing files, and get packages. - name: Checkout NSSL code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - run: flutter create . --project-name nssl --org de.susch19 - run: flutter pub get - name: Configure Keystore for Android - if: matrix.target == 'Android' + if: matrix.target == 'Android' || matrix.target == 'PlayStore' run: | echo "$KEY_STORE_FILE" | base64 --decode > app/nssl-keystore.jks echo "storeFile=nssl-keystore.jks" >> key.properties @@ -119,22 +126,22 @@ jobs: Copy-Item (vswhere -latest -find 'VC\Redist\MSVC\*\x64\*\msvcp140.dll') . Copy-Item (vswhere -latest -find 'VC\Redist\MSVC\*\x64\*\vcruntime140.dll') . Copy-Item (vswhere -latest -find 'VC\Redist\MSVC\*\x64\*\vcruntime140_1.dll') . - - name: Rename build for Android - if: matrix.target == 'Android' - run: mv app-release.apk $GITHUB_WORKSPACE/nssl_${{ matrix.target }}.apk + - name: Rename build for ${{ matrix.target }} + if: matrix.target == 'Android' || matrix.target == 'PlayStore' + run: mv app-release${{ matrix.asset_extension }} $GITHUB_WORKSPACE/nssl_${{ matrix.target }}${{ matrix.asset_extension }} working-directory: ${{ matrix.build_path }} - name: Compress build for Linux if: matrix.target == 'Linux' - run: tar czf $GITHUB_WORKSPACE/nssl_${{ matrix.target }}.tar.gz * + run: tar czf $GITHUB_WORKSPACE/nssl_${{ matrix.target }}${{ matrix.asset_extension }} * working-directory: ${{ matrix.build_path }} - name: Compress build for Windows if: matrix.target == 'Windows' - run: compress-archive -Path * -DestinationPath ${env:GITHUB_WORKSPACE}\nssl_${{ matrix.target }}.zip + run: compress-archive -Path * -DestinationPath ${env:GITHUB_WORKSPACE}\nssl_${{ matrix.target }}${{ matrix.asset_extension }} working-directory: ${{ matrix.build_path }} # Upload the build. - name: Add build into artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: nssl_${{ matrix.target }}${{ matrix.asset_extension }} path: ./nssl_${{ matrix.target }}${{ matrix.asset_extension }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b9e5162..8e7d709 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: future_release: ${{ github.ref }} #since_tag: ${{ steps.get_latest_release.outputs.release }} - name: Upload changelog - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: changelog path: CHANGELOG.md @@ -39,7 +39,7 @@ jobs: upload_url: ${{ steps.create_release.outputs.upload_url }} steps: - name: Download changelog - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: changelog - name: Draft release with changelog @@ -60,33 +60,39 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - target: [Android, Windows, Linux] + target: [Android, PlayStore, Windows, Linux] include: - - os: windows-2019 + - os: windows-latest target: Windows build_target: windows - build_path: build\windows\runner\Release + build_path: build\windows\x64\runner\Release asset_extension: .zip asset_content_type: application/zip - - os: ubuntu-20.04 + - os: ubuntu-latest target: Linux build_target: linux build_path: build/linux/x64/release/bundle asset_extension: .tar.gz asset_content_type: application/gzip - - os: ubuntu-20.04 + - os: ubuntu-latest target: Android build_target: apk build_path: build/app/outputs/flutter-apk asset_extension: .apk asset_content_type: application/vnd.android.package-archive + - os: ubuntu-latest + target: PlayStore + build_target: aab + build_path: build/app/outputs/bundle/release + asset_extension: .aab + asset_content_type: application/x-authorware-bin # Disable fail-fast as we want results from all even if one fails. fail-fast: false needs: draft-release steps: # Set up Flutter. - name: Clone Flutter repository with master channel - uses: subosito/flutter-action@4389e6cbc6cb8a4b18c628ff96ff90be0e926aa8 + uses: subosito/flutter-action@v2 with: channel: master @@ -96,12 +102,13 @@ jobs: sudo apt-get update sudo apt-get install -y libgtk-3-dev libx11-dev pkg-config cmake ninja-build libblkid-dev - name: Install Android dependencies - if: matrix.target == 'Android' - uses: actions/setup-java@v1 + if: matrix.target == 'Android' || matrix.target == 'PlayStore' + uses: actions/setup-java@v4 with: - java-version: '12.x' + distribution: 'temurin' + java-version: '21' - name: Enable desktop support - if: matrix.target != 'Android' + if: matrix.target != 'Android' && matrix.target != 'PlayStore' run: | flutter config --enable-linux-desktop flutter config --enable-macos-desktop @@ -111,11 +118,11 @@ jobs: # Checkout NSSL code, recreate missing files, and get packages. - name: Checkout NSSL code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - run: flutter create . --project-name nssl --org de.susch19 - run: flutter pub get - name: Configure Keystore for Android - if: matrix.target == 'Android' + if: matrix.target == 'Android' || matrix.target == 'PlayStore' run: | echo "$KEY_STORE_FILE" | base64 --decode > app/nssl-keystore.jks echo "storeFile=nssl-keystore.jks" >> key.properties @@ -169,9 +176,9 @@ jobs: Copy-Item (vswhere -latest -find 'VC\Redist\MSVC\*\x64\*\msvcp140.dll') . Copy-Item (vswhere -latest -find 'VC\Redist\MSVC\*\x64\*\vcruntime140.dll') . Copy-Item (vswhere -latest -find 'VC\Redist\MSVC\*\x64\*\vcruntime140_1.dll') . - - name: Rename build for Android - if: matrix.target == 'Android' - run: mv app-release.apk $GITHUB_WORKSPACE/nssl_${{ matrix.target }}.apk + - name: Rename build for ${{ matrix.target }} + if: matrix.target == 'Android' || matrix.target == 'PlayStore' + run: mv app-release${{ matrix.asset_extension }} $GITHUB_WORKSPACE/nssl_${{ matrix.target }}${{ matrix.asset_extension }} working-directory: ${{ matrix.build_path }} - name: Compress build for Linux if: matrix.target == 'Linux' @@ -179,7 +186,7 @@ jobs: working-directory: ${{ matrix.build_path }} - name: Compress build for Windows if: matrix.target == 'Windows' - run: compress-archive -Path * -DestinationPath ${env:GITHUB_WORKSPACE}\nssl_${{ matrix.target }}.zip + run: compress-archive -Path * -DestinationPath ${env:GITHUB_WORKSPACE}\nssl_${{ matrix.target }}${{ matrix.asset_extension }} working-directory: ${{ matrix.build_path }} # Upload the build. diff --git a/android/app/build.gradle b/android/app/build.gradle index 4723113..29e3443 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,3 +1,9 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { @@ -6,27 +12,34 @@ if (localPropertiesFile.exists()) { } } -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' } -apply plugin: 'com.android.application' -apply plugin: 'com.google.gms.google-services' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} - def keystoreProperties = new Properties() - def keystorePropertiesFile = rootProject.file('key.properties') - if (keystorePropertiesFile.exists()) { - keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) - } + +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} android { - compileSdkVersion 33 + namespace "de.susch19.nssl" + compileSdk flutter.compileSdkVersion - lintOptions { - checkReleaseBuilds false // Add this - disable 'InvalidPackage' + compileOptions { + coreLibraryDesugaringEnabled true + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" } defaultConfig { @@ -34,8 +47,14 @@ android { applicationId 'de.susch19.nssl' resValue "string", "app_name", "NSSL" multiDexEnabled true - minSdkVersion 21 - targetSdkVersion 33 + minSdk 23 + targetSdk flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' } signingConfigs { @@ -57,26 +76,13 @@ android { resValue "string", "app_name", "NSSL Debug" } } - } flutter { source '../..' } + dependencies { - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.2.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' -} -// -//configurations.all { -// resolutionStrategy.eachDependency { DependencyResolveDetails details -> -// def requested = details.requested -// if (requested.group == 'com.android.support') { -// if (!requested.name.startsWith("multidex")) { -// details.useVersion '27.0.0' -// } -// } -// } -//} + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4' +} \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index aa52e33..bc157bd 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,37 +1,18 @@ - - -buildscript { - ext.kotlin_version = '1.5.20' +allprojects { repositories { google() mavenCentral() } - - dependencies { - classpath 'com.android.tools.build:gradle:7.2.1' - classpath 'com.google.gms:google-services:4.3.14' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -rootProject.allprojects { - repositories { - google() - mavenCentral() -} } rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" } +subprojects { + project.evaluationDependsOn(':app') +} -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } - - -ext{ - -firebaseMessagingVersion = "21.1.0" -} \ No newline at end of file diff --git a/android/gradle.properties b/android/gradle.properties index 75e8721..1718492 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,4 @@ android.enableJetifier=true android.useAndroidX=true android.enableR8=true -org.gradle.jvmargs=-Xmx1536M \ No newline at end of file +org.gradle.jvmargs=-Xmx2048M \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle index 115da6c..78a20d7 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,15 +1,25 @@ -include ':app' +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withInputStream { stream -> plugins.load(stream) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "8.10.0" apply false + id "org.jetbrains.kotlin.android" version "2.1.20" apply false } + +include ":app" diff --git a/assets/vectors/nssl_icon.svg b/assets/vectors/nssl_icon.svg index cdb5f3d..bb5b5ce 100644 --- a/assets/vectors/nssl_icon.svg +++ b/assets/vectors/nssl_icon.svg @@ -1,65 +1,34 @@ - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + C369.778,393.076,364.632,398.222,358.284,398.222z" /> + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ios/Flutter/ephemeral/flutter_lldb_helper.py b/ios/Flutter/ephemeral/flutter_lldb_helper.py new file mode 100644 index 0000000..a88caf9 --- /dev/null +++ b/ios/Flutter/ephemeral/flutter_lldb_helper.py @@ -0,0 +1,32 @@ +# +# Generated file, do not edit. +# + +import lldb + +def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict): + """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages.""" + base = frame.register["x0"].GetValueAsAddress() + page_len = frame.register["x1"].GetValueAsUnsigned() + + # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the + # first page to see if handled it correctly. This makes diagnosing + # misconfiguration (e.g. missing breakpoint) easier. + data = bytearray(page_len) + data[0:8] = b'IHELPED!' + + error = lldb.SBError() + frame.GetThread().GetProcess().WriteMemory(base, data, error) + if not error.Success(): + print(f'Failed to write into {base}[+{page_len}]', error) + return + +def __lldb_init_module(debugger: lldb.SBDebugger, _): + target = debugger.GetDummyTarget() + # Caveat: must use BreakpointCreateByRegEx here and not + # BreakpointCreateByName. For some reasons callback function does not + # get carried over from dummy target for the later. + bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$") + bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__)) + bp.SetAutoContinue(True) + print("-- LLDB integration loaded --") diff --git a/ios/Flutter/ephemeral/flutter_lldbinit b/ios/Flutter/ephemeral/flutter_lldbinit new file mode 100644 index 0000000..e3ba6fb --- /dev/null +++ b/ios/Flutter/ephemeral/flutter_lldbinit @@ -0,0 +1,5 @@ +# +# Generated file, do not edit. +# + +command script import --relative-to-command-file flutter_lldb_helper.py diff --git a/lib/firebase/cloud_messsaging.dart b/lib/firebase/cloud_messsaging.dart index d207c89..ef11434 100644 --- a/lib/firebase/cloud_messsaging.dart +++ b/lib/firebase/cloud_messsaging.dart @@ -1,45 +1,57 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; import 'package:firebase_messaging/firebase_messaging.dart'; -import 'package:flutter/foundation.dart'; import 'package:nssl/helper/iterable_extensions.dart'; import 'package:nssl/manager/startup_manager.dart'; import 'package:nssl/models/model_export.dart'; +import 'package:nssl/server_communication/helper_methods.dart'; import 'package:riverpod/riverpod.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; -FirebaseMessaging? get firebaseMessaging => Startup.firebaseSupported() ? FirebaseMessaging.instance : null; +part 'cloud_messsaging.g.dart'; -final cloudMessagingProvider = Provider((ref) { - return CloudMessaging(ref); -}); +FirebaseMessaging? get firebaseMessaging => + Startup.firebaseSupported() ? FirebaseMessaging.instance : null; -class CloudMessaging { - static late Ref _ref; - - CloudMessaging(Ref ref) { - _ref = ref; +@Riverpod(keepAlive: true) +class CloudMessaging extends _$CloudMessaging { + @override + void build() { + return; } - static Future onMessage(RemoteMessage message) async { + Future onMessage(RemoteMessage message) async { final dynamic data = message.data; + final deviceToken = data["deviceToken"]; + if (deviceToken != null && deviceToken == HelperMethods.deviceToken) return; int listId = int.parse(data["listId"]); - var ownId = _ref.read(userIdProvider); - if (ownId == int.parse(data["userId"])) { + var ownId = ref.read(userIdProvider); + if (deviceToken == null && ownId == int.parse(data["userId"])) { return null; } - var listController = _ref.read(shoppingListsProvider); + var listController = ref.read(shoppingListsProvider); - var list = listController.shoppingLists.firstOrNull((element) => element.id == listId); + var list = listController.shoppingLists.firstOrNull( + (element) => element.id == listId, + ); if (list == null) { var mapp = jsonDecode(data["items"]); //User was added to new list - var items = _ref.watch(shoppingItemsProvider.notifier); + var items = ref.watch(shoppingItemsProvider.notifier); var newState = items.state.toList(); - newState - .addAll(mapp.map((x) => ShoppingItem(x["name"], listId, x["sortOrder"], id: x["id"], amount: x["amount"]))); + newState.addAll( + mapp.map( + (x) => ShoppingItem( + x["name"], + listId, + x["sortOrder"], + id: x["id"], + amount: x["amount"], + ), + ), + ); items.state = newState; listController.addList(ShoppingList(listId, data["name"])); } else if (data.length == 1) { @@ -51,7 +63,7 @@ class CloudMessaging { switch (action) { case "ItemChanged": //Id, Amount, action var id = int.parse(data["id"]); - var items = _ref.watch(shoppingItemsProvider.notifier); + var items = ref.watch(shoppingItemsProvider.notifier); var newState = items.state.toList(); var item = newState.firstWhere((x) => x.id == id); newState.remove(item); @@ -65,13 +77,20 @@ class CloudMessaging { break; case "NewItemAdded": //Id, Name, Gtin, Amount, action var newItemId = int.parse(data["id"]); - var existing = _ref.read(shoppingItemProvider.create(newItemId)); + var existing = ref.read(shoppingItemProvider(newItemId)); if (existing != null) break; listController.addSingleItem( - list, - ShoppingItem(data["name"], list.id, int.parse(data["sortOrder"]), - id: int.parse(data["id"]), amount: int.parse(data["amount"]), crossedOut: false)); + list, + ShoppingItem( + data["name"], + list.id, + int.parse(data["sortOrder"]), + id: int.parse(data["id"]), + amount: int.parse(data["amount"]), + crossedOut: false, + ), + ); break; case "ListRename": //Name, action listController.rename(list.id, data["name"] as String); @@ -81,26 +100,26 @@ class CloudMessaging { break; case "ItemRenamed": //product.Id, product.Name var itemId = int.parse(data["id"]); - var items = _ref.watch(shoppingItemsProvider.notifier); + var items = ref.watch(shoppingItemsProvider.notifier); var newState = items.state.toList(); var item = newState.firstWhere((x) => x.id == itemId); newState.remove(item); - newState.add( - item.cloneWith(newName: data["name"]), - ); + newState.add(item.cloneWith(newName: data["name"])); items.state = newState; listController.save(list); break; case "OrderChanged": var itemId = int.parse(data["id"]); - var items = _ref.watch(shoppingItemsProvider.notifier); + var items = ref.watch(shoppingItemsProvider.notifier); var newState = items.state.toList(); var item = newState.firstWhere((x) => x.id == itemId); newState.remove(item); - newState.add(item.cloneWith( - newAmount: int.parse(data["amount"]), - newSortOrder: int.parse(data["sortOrder"]), - )); + newState.add( + item.cloneWith( + newAmount: int.parse(data["amount"]), + newSortOrder: int.parse(data["sortOrder"]), + ), + ); items.state = newState; listController.save(list); break; diff --git a/lib/firebase/cloud_messsaging.g.dart b/lib/firebase/cloud_messsaging.g.dart new file mode 100644 index 0000000..4abda6b --- /dev/null +++ b/lib/firebase/cloud_messsaging.g.dart @@ -0,0 +1,63 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'cloud_messsaging.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +@ProviderFor(CloudMessaging) +const cloudMessagingProvider = CloudMessagingProvider._(); + +final class CloudMessagingProvider + extends $NotifierProvider { + const CloudMessagingProvider._() + : super( + from: null, + argument: null, + retry: null, + name: r'cloudMessagingProvider', + isAutoDispose: false, + dependencies: null, + $allTransitiveDependencies: null, + ); + + @override + String debugGetCreateSourceHash() => _$cloudMessagingHash(); + + @$internal + @override + CloudMessaging create() => CloudMessaging(); + + /// {@macro riverpod.override_with_value} + Override overrideWithValue(void value) { + return $ProviderOverride( + origin: this, + providerOverride: $SyncValueProvider(value), + ); + } +} + +String _$cloudMessagingHash() => r'e7b1ca03a469d2c91c63648330681342dfd39a86'; + +abstract class _$CloudMessaging extends $Notifier { + void build(); + @$mustCallSuper + @override + void runBuild() { + build(); + final ref = this.ref as $Ref; + final element = + ref.element + as $ClassProviderElement< + AnyNotifier, + void, + Object?, + Object? + >; + element.handleValue(ref, null); + } +} + +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/helper/iterable_extensions.dart b/lib/helper/iterable_extensions.dart index ea5b6b9..fd589f7 100644 --- a/lib/helper/iterable_extensions.dart +++ b/lib/helper/iterable_extensions.dart @@ -1,16 +1,25 @@ extension Linq on List { - bool removeElements(Iterable elements) { + bool sequenceEquals(final List other) { + if (other.length != length) return false; + + for (var i = 0; i < length; i++) { + if (other[i] != this[i]) return false; + } + return true; + } + + bool removeElements(final Iterable elements) { bool b = true; - for (var e in elements) { + for (final e in elements) { if (!b) return b; - b = this.remove(e); + b = remove(e); } return b; } List copy() { - List items = []; - this.forEach((element) { + final List items = []; + forEach((final element) { items.add(element); }); return items; @@ -18,7 +27,7 @@ extension Linq on List { } extension MoreMath on double { - double clamp(double lower, double maximum) { + double clamp(final double lower, final double maximum) { if (this <= lower) return lower; if (this >= maximum) return maximum; return this; @@ -26,17 +35,17 @@ extension MoreMath on double { } extension Maps on Map { - List select(T Function(K, E) keyFunction) { - var retList = []; - for (var entry in this.entries) { + List select(final T Function(K, E) keyFunction) { + final retList = []; + for (final entry in entries) { retList.add(keyFunction(entry.key, entry.value)); } return retList; } - MapEntry? elementAt(int index, {MapEntry? orElse}) { + MapEntry? elementAt(final int index, {final MapEntry? orElse}) { int i = 0; - for (var el in this.entries) { + for (final el in entries) { if (index == i) return el; i++; } @@ -44,66 +53,120 @@ extension Maps on Map { } } +extension StringShortcuts on String { + String substringReverse(final int end, {final int start = 0}) { + return substring(start, length - start - end); + } +} + extension Iterables on Iterable { - Map> groupBy(K Function(E) keyFunction) => fold( - >{}, - (Map> map, E element) => - map..putIfAbsent(keyFunction(element), () => []).add(element)); - - Map> groupManyBy(List Function(E) keyFunction) => - fold(>{}, (Map> map, E element) { - for (var r in keyFunction(element)) { - map..putIfAbsent(r, () => []).add(element); + Iterable mapMany(final Iterable Function(E) func) sync* { + for (final e in this) { + for (final ret in func(e)) { + yield ret; + } + } + } + + Iterable distinct() { + final list = []; + for (final e in this) { + if (!list.any((final element) => element == e)) list.add(e); + } + return list; + } + + Map> groupBy(final K Function(E) keyFunction) => fold(>{}, + (final Map> map, final E element) => map..putIfAbsent(keyFunction(element), () => []).add(element)); + + Map> groupManyBy(final List Function(E) keyFunction) => + fold(>{}, (final Map> map, final E element) { + for (final r in keyFunction(element)) { + map.putIfAbsent(r, () => []).add(element); } return map; }); - E? firstOrNull(bool Function(E element) keyFunction) { - for (var item in [...this]) { + E? firstOrNull(final bool Function(E element) keyFunction) { + for (final item in this) { if (keyFunction(item)) return item; } return null; } - Iterable injectForIndex(E? Function(int index) indexFunc) sync* { + Iterable injectForIndex(final E? Function(int index) indexFunc) sync* { int index = 0; - for (var item in [...this]) { - var res = indexFunc(index); + for (final item in [...this]) { + final res = indexFunc(index); if (res != null) yield res; yield item; index++; } } - int sum(int Function(E element) keyFunction) { + int sum(final int Function(E element) keyFunction) { int sum = 0; - for (var item in [...this]) { + for (final item in [...this]) { sum += keyFunction(item); } return sum; } - int bitOr(int Function(E element) keyFunction) { + int bitOr(final int Function(E element) keyFunction) { int sum = 0; - for (var item in [...this]) { + for (final item in [...this]) { sum |= keyFunction(item); } return sum; } - int bitAnd(int Function(E element) keyFunction) { + int bitAnd(final int Function(E element) keyFunction) { int sum = 0; - for (var item in [...this]) { + for (final item in [...this]) { sum &= keyFunction(item); } return sum; } - int bitXor(int Function(E element) keyFunction) { + int bitXor(final int Function(E element) keyFunction) { int sum = 0; - for (var item in [...this]) { + for (final item in [...this]) { sum ^= keyFunction(item); } return sum; } + + Map toMap( + final TKey Function(E element) keyFunction, final TValue Function(E element) valueFunction) { + final map = {}; + for (final item in [...this]) { + map[keyFunction(item)] = valueFunction(item); + } + return map; + } + + num minBy(final num initial, final num Function(E element) func) { + num min = initial; + for (final item in [...this]) { + final ret = func(item); + if (ret < min) min = ret; + } + return min; + } + + num maxBy(final num initial, final num Function(E element) func) { + num max = initial; + for (final item in [...this]) { + final ret = func(item); + if (ret > max) max = ret; + } + return max; + } + + bool all(final bool Function(E element) func) { + for (final item in [...this]) { + if (!func(item)) return false; + } + return true; + } } diff --git a/lib/localization/nssl_messages_de.dart b/lib/localization/nssl_messages_de.dart index 2c990f3..5b05bd4 100644 --- a/lib/localization/nssl_messages_de.dart +++ b/lib/localization/nssl_messages_de.dart @@ -5,181 +5,275 @@ final messages = MessageLookup(); class MessageLookup extends MessageLookupByLibrary { get localeName => 'de'; - final Map messages = _notInlinedMessages(_notInlinedMessages); + final Map messages = + _notInlinedMessages(_notInlinedMessages); static _notInlinedMessages(_) => { "options": MessageLookupByLibrary.simpleMessage("Optionen"), "changeTheme": MessageLookupByLibrary.simpleMessage("Design ändern"), "scanPB": MessageLookupByLibrary.simpleMessage("SCANNEN"), - "addPB": MessageLookupByLibrary.simpleMessage("ADD"), //TODO find good german word + "addPB": MessageLookupByLibrary.simpleMessage( + "ADD"), //TODO find good german word "searchPB": MessageLookupByLibrary.simpleMessage("SUCHEN"), - "deleteCrossedOutPB": MessageLookupByLibrary.simpleMessage("Lösche Markierte"), + "deleteCrossedOutPB": + MessageLookupByLibrary.simpleMessage("Lösche Markierte"), "addListPB": MessageLookupByLibrary.simpleMessage("LISTE HINZUFÜGEN"), "contributors": MessageLookupByLibrary.simpleMessage("Teilnehmer"), "rename": MessageLookupByLibrary.simpleMessage("Umbenennen"), "remove": MessageLookupByLibrary.simpleMessage("Entfernen"), - "addProduct": MessageLookupByLibrary.simpleMessage("Artikel hinzufügen"), - "addProductWithoutSearch": MessageLookupByLibrary.simpleMessage("Name des Artikels"), + "addProduct": + MessageLookupByLibrary.simpleMessage("Artikel hinzufügen"), + "addProductWithoutSearch": + MessageLookupByLibrary.simpleMessage("Name des Artikels"), "productName": MessageLookupByLibrary.simpleMessage("Artikelname"), - "messageDeleteAllCrossedOut": - MessageLookupByLibrary.simpleMessage("Alle durchgestrichenen Artikel wurden gelöscht"), + "messageDeleteAllCrossedOut": MessageLookupByLibrary.simpleMessage( + "Alle durchgestrichenen Artikel wurden gelöscht"), "undo": MessageLookupByLibrary.simpleMessage("RÜCKG."), - "removedShoppingListMessage": MessageLookupByLibrary.simpleMessage(" entfernt "), //\${User.shoppingLists} - "noListsInDrawerMessage": MessageLookupByLibrary.simpleMessage(" Hier werden deine Listen angezeigt"), - "notLoggedInYet": MessageLookupByLibrary.simpleMessage("Noch nicht eingeloggt"), - "newNameOfListHint": MessageLookupByLibrary.simpleMessage("Neuer Listenname"), + "removedShoppingListMessage": MessageLookupByLibrary.simpleMessage( + " entfernt "), //\${User.shoppingLists} + "noListsInDrawerMessage": MessageLookupByLibrary.simpleMessage( + " Hier werden deine Listen angezeigt"), + "notLoggedInYet": + MessageLookupByLibrary.simpleMessage("Noch nicht eingeloggt"), + "newNameOfListHint": + MessageLookupByLibrary.simpleMessage("Neuer Listenname"), "listName": MessageLookupByLibrary.simpleMessage("Listenname"), - "renameListTitle": MessageLookupByLibrary.simpleMessage("Liste umbenennen"), - "renameListHint": MessageLookupByLibrary.simpleMessage("Der neue Name der Liste"), - "chooseListToAddTitle": MessageLookupByLibrary.simpleMessage("Welche Liste hinzufügen?"), - "addNewListTitle": MessageLookupByLibrary.simpleMessage("Füge eine neue Liste hinzu"), - "recipeCreateError": MessageLookupByLibrary.simpleMessage("Konnte Rezept nicht erstellen"), - "recipeFromShareTitle": MessageLookupByLibrary.simpleMessage("Zu welcher Liste hinzufügen?"), + "renameListTitle": + MessageLookupByLibrary.simpleMessage("Liste umbenennen"), + "renameListHint": + MessageLookupByLibrary.simpleMessage("Der neue Name der Liste"), + "chooseListToAddTitle": + MessageLookupByLibrary.simpleMessage("Welche Liste hinzufügen?"), + "addNewListTitle": + MessageLookupByLibrary.simpleMessage("Füge eine neue Liste hinzu"), + "recipeCreateError": MessageLookupByLibrary.simpleMessage( + "Konnte Rezept nicht erstellen"), + "recipeFromShareTitle": MessageLookupByLibrary.simpleMessage( + "Zu welcher Liste hinzufügen?"), "recipeFromShareNew": MessageLookupByLibrary.simpleMessage("NEU"), "recipeName": MessageLookupByLibrary.simpleMessage("Rezept"), - "recipeNameHint": MessageLookupByLibrary.simpleMessage("Rezept ID oder URL"), - "addNewRecipeTitle": MessageLookupByLibrary.simpleMessage("Neues Rezept hinzufügen"), - "importNewRecipe": MessageLookupByLibrary.simpleMessage("Rezept importieren"), - "importNewRecipeTitle": MessageLookupByLibrary.simpleMessage("Neues Rezept importieren"), - "chooseAddListDialog": MessageLookupByLibrary.simpleMessage("Einkaufen"), - "chooseAddRecipeDialog": MessageLookupByLibrary.simpleMessage("Chefkoch"), - "youHaveActionItemMessage": MessageLookupByLibrary.simpleMessage('Du hast '), //\$action \$item + "recipeNameHint": + MessageLookupByLibrary.simpleMessage("Rezept ID oder URL"), + "addNewRecipeTitle": + MessageLookupByLibrary.simpleMessage("Neues Rezept hinzufügen"), + "importNewRecipe": + MessageLookupByLibrary.simpleMessage("Rezept importieren"), + "importNewRecipeTitle": + MessageLookupByLibrary.simpleMessage("Neues Rezept importieren"), + "chooseAddListDialog": + MessageLookupByLibrary.simpleMessage("Einkaufsliste"), + "chooseAddRecipeDialog": + MessageLookupByLibrary.simpleMessage("Chefkoch Rezept"), + "youHaveActionItemMessage": + MessageLookupByLibrary.simpleMessage('Du hast '), //\$action \$item "archived": MessageLookupByLibrary.simpleMessage('archiviert'), "deleted": MessageLookupByLibrary.simpleMessage('gelöscht'), - "actionsForMessage": MessageLookupByLibrary.simpleMessage("archiviert" "gelöscht"), - "youHaveActionNameMessage": MessageLookupByLibrary.simpleMessage("Du hast "), //\${s.name} \$action + "actionsForMessage": + MessageLookupByLibrary.simpleMessage("archiviert" "gelöscht"), + "youHaveActionNameMessage": MessageLookupByLibrary.simpleMessage( + "Du hast "), //\${s.name} \$action "demoteMenu": MessageLookupByLibrary.simpleMessage("Degradieren"), "promoteMenu": MessageLookupByLibrary.simpleMessage("Befördern"), "contributorUser": MessageLookupByLibrary.simpleMessage(" - User"), "contributorAdmin": MessageLookupByLibrary.simpleMessage(" - Admin"), - "genericErrorMessageSnackbar": - MessageLookupByLibrary.simpleMessage("Etwas Unerwartetes ist passiert!\n "), //\${z.error} - "nameOfNewContributorHint": MessageLookupByLibrary.simpleMessage("Name des neuen Teilnehmers"), - "wasRemovedSuccessfullyMessage": MessageLookupByLibrary.simpleMessage(" wurde erfolgreich gelöscht"), - "loginSuccessfullMessage": MessageLookupByLibrary.simpleMessage("Login erfolgreich, die Listen werden geladen"), - "nameEmailRequiredError": MessageLookupByLibrary.simpleMessage("Name oder EMail wird benötigt."), - "usernameToShortError": - MessageLookupByLibrary.simpleMessage("Der Benutzername muss aus mindestens 4 Zeichen bestehen"), - "emailRequiredError": MessageLookupByLibrary.simpleMessage("EMail ist erforderlich"), - "emailIncorrectFormatError": - MessageLookupByLibrary.simpleMessage("Die EMail-Adresse scheint ein falsches Format zu haben"), - "chooseAPassword": MessageLookupByLibrary.simpleMessage("Bitte ein Passwort eingeben"), + "genericErrorMessageSnackbar": MessageLookupByLibrary.simpleMessage( + "Etwas Unerwartetes ist passiert!\n "), //\${z.error} + "nameOfNewContributorHint": + MessageLookupByLibrary.simpleMessage("Name des neuen Teilnehmers"), + "wasRemovedSuccessfullyMessage": + MessageLookupByLibrary.simpleMessage(" wurde erfolgreich gelöscht"), + "loginSuccessfullMessage": MessageLookupByLibrary.simpleMessage( + "Login erfolgreich, die Listen werden geladen"), + "nameEmailRequiredError": MessageLookupByLibrary.simpleMessage( + "Name oder EMail wird benötigt."), + "usernameToShortError": MessageLookupByLibrary.simpleMessage( + "Der Benutzername muss aus mindestens 4 Zeichen bestehen"), + "emailRequiredError": + MessageLookupByLibrary.simpleMessage("EMail ist erforderlich"), + "emailIncorrectFormatError": MessageLookupByLibrary.simpleMessage( + "Die EMail-Adresse scheint ein falsches Format zu haben"), + "chooseAPassword": + MessageLookupByLibrary.simpleMessage("Bitte ein Passwort eingeben"), "login": MessageLookupByLibrary.simpleMessage("Login"), - "usernameOrEmailForLoginHint": - MessageLookupByLibrary.simpleMessage("Benutzername oder EMail kann für's einloggen genutzt werden"), - "usernameOrEmailTitle": MessageLookupByLibrary.simpleMessage("Benutzername oder EMail"), + "usernameOrEmailForLoginHint": MessageLookupByLibrary.simpleMessage( + "Benutzername oder EMail kann für's einloggen genutzt werden"), + "usernameOrEmailTitle": + MessageLookupByLibrary.simpleMessage("Benutzername oder EMail"), "emailTitle": MessageLookupByLibrary.simpleMessage('EMail'), - "choosenPasswordHint": MessageLookupByLibrary.simpleMessage("Dein gewähltes Passwort"), + "choosenPasswordHint": + MessageLookupByLibrary.simpleMessage("Dein gewähltes Passwort"), "password": MessageLookupByLibrary.simpleMessage("Passwort"), "loginButton": MessageLookupByLibrary.simpleMessage("LOGIN"), - "registerTextOnLogin": - MessageLookupByLibrary.simpleMessage("Du hast noch keinen Account? Erstelle jetzt einen."), - "usernameEmptyError": MessageLookupByLibrary.simpleMessage("Benutzername muss ausgefüllt sein"), - "passwordEmptyError": MessageLookupByLibrary.simpleMessage("Passwort muss ausgefüllt sein"), - "passwordTooShortError": MessageLookupByLibrary.simpleMessage("Passwort muss mindestens 6 Zeichen lang sein"), + "registerTextOnLogin": MessageLookupByLibrary.simpleMessage( + "Du hast noch keinen Account? Erstelle jetzt einen."), + "usernameEmptyError": MessageLookupByLibrary.simpleMessage( + "Benutzername muss ausgefüllt sein"), + "passwordEmptyError": MessageLookupByLibrary.simpleMessage( + "Passwort muss ausgefüllt sein"), + "passwordTooShortError": MessageLookupByLibrary.simpleMessage( + "Passwort muss mindestens 6 Zeichen lang sein"), "passwordMissingCharactersError": MessageLookupByLibrary.simpleMessage( "Passwort muss mindestens ein spezielles Zeichen (Kann jedes Symbol/Emoji sein) und Buchstabe oder Zahl enthalten"), - "emailEmptyError": MessageLookupByLibrary.simpleMessage("EMail muss ausgefüllt sein"), - "reenterPasswordError": - MessageLookupByLibrary.simpleMessage("Die Passwörter stimmen nicht überein oder sind leer"), - "unknownUsernameError": MessageLookupByLibrary.simpleMessage("Es stimmt etwas mit deinem Benutzername nicht"), - "unknownEmailError": MessageLookupByLibrary.simpleMessage("Es stimmt etwas mit deiner EMail nicht"), - "unknownPasswordError": MessageLookupByLibrary.simpleMessage("Es stimmt etwas mit deinem Passwort nicht"), - "unknownReenterPasswordError": - MessageLookupByLibrary.simpleMessage("Es stimmt etwas mit dem wiederholten Passwort nicht"), - "registrationSuccessfulMessage": MessageLookupByLibrary.simpleMessage("Registrierung erfolgreich"), - "registrationTitle": MessageLookupByLibrary.simpleMessage("Registrierung"), - "nameEmptyError": MessageLookupByLibrary.simpleMessage("Name ist erforderlich"), - "chooseAPasswordPrompt": MessageLookupByLibrary.simpleMessage("Bitte gib ein Passwort ein"), - "reenterPasswordPrompt": MessageLookupByLibrary.simpleMessage("Bitte gib dein Passwort erneut ein"), - "passwordsDontMatchError": MessageLookupByLibrary.simpleMessage("Die Passwörter stimmen nicht überein"), - "usernameRegisterHint": - MessageLookupByLibrary.simpleMessage("Kann zum einloggen und zum gefunden werden genutzt werden"), + "emailEmptyError": + MessageLookupByLibrary.simpleMessage("EMail muss ausgefüllt sein"), + "reenterPasswordError": MessageLookupByLibrary.simpleMessage( + "Die Passwörter stimmen nicht überein oder sind leer"), + "unknownUsernameError": MessageLookupByLibrary.simpleMessage( + "Es stimmt etwas mit deinem Benutzername nicht"), + "unknownEmailError": MessageLookupByLibrary.simpleMessage( + "Es stimmt etwas mit deiner EMail nicht"), + "unknownPasswordError": MessageLookupByLibrary.simpleMessage( + "Es stimmt etwas mit deinem Passwort nicht"), + "unknownReenterPasswordError": MessageLookupByLibrary.simpleMessage( + "Es stimmt etwas mit dem wiederholten Passwort nicht"), + "registrationSuccessfulMessage": + MessageLookupByLibrary.simpleMessage("Registrierung erfolgreich"), + "registrationTitle": + MessageLookupByLibrary.simpleMessage("Registrierung"), + "nameEmptyError": + MessageLookupByLibrary.simpleMessage("Name ist erforderlich"), + "chooseAPasswordPrompt": + MessageLookupByLibrary.simpleMessage("Bitte gib ein Passwort ein"), + "reenterPasswordPrompt": MessageLookupByLibrary.simpleMessage( + "Bitte gib dein Passwort erneut ein"), + "passwordsDontMatchError": MessageLookupByLibrary.simpleMessage( + "Die Passwörter stimmen nicht überein"), + "usernameRegisterHint": MessageLookupByLibrary.simpleMessage( + "Kann zum einloggen und zum gefunden werden genutzt werden"), "username": MessageLookupByLibrary.simpleMessage("Benutzername"), - "emailRegisterHint": - MessageLookupByLibrary.simpleMessage("Kann zum einloggen und zum gefunden werden genutzt werden"), - "passwordRegisterHint": MessageLookupByLibrary.simpleMessage("Das Passwort schützt deinen Account"), - "retypePasswordHint": - MessageLookupByLibrary.simpleMessage("Bitte wiederhole dein Passwort um Fehler zu vermeiden"), - "retypePasswordTitle": MessageLookupByLibrary.simpleMessage("Passwortwiederholung"), + "emailRegisterHint": MessageLookupByLibrary.simpleMessage( + "Kann zum einloggen und zum gefunden werden genutzt werden"), + "passwordRegisterHint": MessageLookupByLibrary.simpleMessage( + "Das Passwort schützt deinen Account"), + "retypePasswordHint": MessageLookupByLibrary.simpleMessage( + "Bitte wiederhole dein Passwort um Fehler zu vermeiden"), + "retypePasswordTitle": + MessageLookupByLibrary.simpleMessage("Passwortwiederholung"), "registerButton": MessageLookupByLibrary.simpleMessage("REGISTRIEREN"), - "discardNewProduct": MessageLookupByLibrary.simpleMessage("Änderungen verwerfen?"), + "discardNewProduct": + MessageLookupByLibrary.simpleMessage("Änderungen verwerfen?"), "cancelButton": MessageLookupByLibrary.simpleMessage("ABBRECHEN"), "acceptButton": MessageLookupByLibrary.simpleMessage('ANNEHMEN'), "discardButton": MessageLookupByLibrary.simpleMessage("VERWERFEN"), - "fixErrorsBeforeSubmittingPrompt": - MessageLookupByLibrary.simpleMessage("Bitte behebe die Fehler, gekennzeichnet in Rot"), - "newProductTitle": MessageLookupByLibrary.simpleMessage("Neues Produkt"), + "fixErrorsBeforeSubmittingPrompt": MessageLookupByLibrary.simpleMessage( + "Bitte behebe die Fehler, gekennzeichnet in Rot"), + "newProductTitle": + MessageLookupByLibrary.simpleMessage("Neues Produkt"), "saveButton": MessageLookupByLibrary.simpleMessage("SPEICHERN"), "newProductName": MessageLookupByLibrary.simpleMessage("Produktname *"), - "newProductNameHint": MessageLookupByLibrary.simpleMessage("Was steht auf der Verpackung?"), - "newProductBrandName": MessageLookupByLibrary.simpleMessage("Markenname"), - "newProductBrandNameHint": MessageLookupByLibrary.simpleMessage("Von welcher Marke ist das Produkt?"), - "newProductWeight": MessageLookupByLibrary.simpleMessage("Menge mit Einheit"), - "newProductWeightHint": MessageLookupByLibrary.simpleMessage("Zum Beispiel: 1,5l oder 100g"), - "newProductAddToList": MessageLookupByLibrary.simpleMessage("Füge es der aktuellen Liste hinzu"), - "newProductAddedToList": MessageLookupByLibrary.simpleMessage(" wurde hinzugefügt zur Liste "), - "newProductStarExplanation": MessageLookupByLibrary.simpleMessage("* kennzeichnet die benötigten Felder"), - "fieldRequiredError": MessageLookupByLibrary.simpleMessage("Dieses Feld wird benötigt!"), - "newProductNameToShort": MessageLookupByLibrary.simpleMessage("Dieser Name scheint zu kurz zu sein"), - "addedProduct": MessageLookupByLibrary.simpleMessage(' hinzugefügt'), //"\$name" + "newProductNameHint": MessageLookupByLibrary.simpleMessage( + "Was steht auf der Verpackung?"), + "newProductBrandName": + MessageLookupByLibrary.simpleMessage("Markenname"), + "newProductBrandNameHint": MessageLookupByLibrary.simpleMessage( + "Von welcher Marke ist das Produkt?"), + "newProductWeight": + MessageLookupByLibrary.simpleMessage("Menge mit Einheit"), + "newProductWeightHint": MessageLookupByLibrary.simpleMessage( + "Zum Beispiel: 1,5l oder 100g"), + "newProductAddToList": MessageLookupByLibrary.simpleMessage( + "Füge es der aktuellen Liste hinzu"), + "newProductAddedToList": MessageLookupByLibrary.simpleMessage( + " wurde hinzugefügt zur Liste "), + "newProductStarExplanation": MessageLookupByLibrary.simpleMessage( + "* kennzeichnet die benötigten Felder"), + "fieldRequiredError": + MessageLookupByLibrary.simpleMessage("Dieses Feld wird benötigt!"), + "newProductNameToShort": MessageLookupByLibrary.simpleMessage( + "Dieser Name scheint zu kurz zu sein"), + "addedProduct": + MessageLookupByLibrary.simpleMessage(' hinzugefügt'), //"\$name" "productWasAlreadyInList": MessageLookupByLibrary.simpleMessage( ' ist bereits in der Liste. Die Menge wurde um 1 erhöht'), //"\$name" ist - "searchProductHint": MessageLookupByLibrary.simpleMessage("Produktsuche"), - "noMoreProductsMessage": - MessageLookupByLibrary.simpleMessage("Es konnten keine weiteren Produkte mit dem Namen gefunden werden"), + "searchProductHint": + MessageLookupByLibrary.simpleMessage("Produktsuche"), + "noMoreProductsMessage": MessageLookupByLibrary.simpleMessage( + "Es konnten keine weiteren Produkte mit dem Namen gefunden werden"), "codeText": MessageLookupByLibrary.simpleMessage("Code: "), "removed": MessageLookupByLibrary.simpleMessage("entfernt"), - "changePrimaryColor": MessageLookupByLibrary.simpleMessage("Hauptfarbe"), - "changeAccentColor": MessageLookupByLibrary.simpleMessage("Akzentfarbe"), - "changeDarkTheme": MessageLookupByLibrary.simpleMessage("Dunkles Design"), - "changeAccentTextColor": MessageLookupByLibrary.simpleMessage("Helle Icons"), + "changePrimaryColor": + MessageLookupByLibrary.simpleMessage("Hauptfarbe"), + "changeAccentColor": + MessageLookupByLibrary.simpleMessage("Akzentfarbe"), + "changeDarkTheme": + MessageLookupByLibrary.simpleMessage("Dunkles Design"), + "changeAccentTextColor": + MessageLookupByLibrary.simpleMessage("Helle Icons"), "autoSync": MessageLookupByLibrary.simpleMessage("Auto-Sync"), - "changePasswordButton": MessageLookupByLibrary.simpleMessage("ÄNDERE PASSWORT"), - "currentPassword": MessageLookupByLibrary.simpleMessage("Aktuelles Passwort"), - "currentPasswordHint": MessageLookupByLibrary.simpleMessage("Das aktuelle Passwort, dass geändert werden soll"), + "changePasswordButton": + MessageLookupByLibrary.simpleMessage("ÄNDERE PASSWORT"), + "currentPassword": + MessageLookupByLibrary.simpleMessage("Aktuelles Passwort"), + "currentPasswordHint": MessageLookupByLibrary.simpleMessage( + "Das aktuelle Passwort, dass geändert werden soll"), "newPassword": MessageLookupByLibrary.simpleMessage("Neues Passwort"), - "newPasswordHint": MessageLookupByLibrary.simpleMessage("Das neu gewählte Passwort"), - "repeatNewPassword": MessageLookupByLibrary.simpleMessage("Neues Passwort wiederholen"), - "repeatNewPasswordHint": MessageLookupByLibrary.simpleMessage("Wiederholung des neu gewählten Passworts"), - "changePasswordPD": MessageLookupByLibrary.simpleMessage("Ändere Passwort"), + "newPasswordHint": + MessageLookupByLibrary.simpleMessage("Das neu gewählte Passwort"), + "repeatNewPassword": + MessageLookupByLibrary.simpleMessage("Neues Passwort wiederholen"), + "repeatNewPasswordHint": MessageLookupByLibrary.simpleMessage( + "Wiederholung des neu gewählten Passworts"), + "changePasswordPD": + MessageLookupByLibrary.simpleMessage("Ändere Passwort"), "successful": MessageLookupByLibrary.simpleMessage("Erfolgreich"), - "passwordSet": MessageLookupByLibrary.simpleMessage("Dein Passwort wurde erfolgreich geändert"), - "tokenExpired": MessageLookupByLibrary.simpleMessage("Token abgelaufen"), + "passwordSet": MessageLookupByLibrary.simpleMessage( + "Dein Passwort wurde erfolgreich geändert"), + "tokenExpired": + MessageLookupByLibrary.simpleMessage("Token abgelaufen"), "tokenExpiredExplanation": MessageLookupByLibrary.simpleMessage( "Der Token ist abgelaufen. Deshalb wird ein erneuter Login benötigt. Es handelt sich hierbei erst um ein Fehler, falls diese Meldung mehrmals im Monat aufkommt."), - "noListLoaded": MessageLookupByLibrary.simpleMessage("Keine Liste geladen"), - "renameListItem": MessageLookupByLibrary.simpleMessage("Produkt umbenennen"), - "renameListItemHint": MessageLookupByLibrary.simpleMessage("Der neue Name des Produktes"), - "renameListItemLabel": MessageLookupByLibrary.simpleMessage("Neuer Prdouktname"), - "discardNewTheme": MessageLookupByLibrary.simpleMessage("Änderungen verwerfen?"), - "forgotPassword": MessageLookupByLibrary.simpleMessage("Passwort vergessen?"), - "bePatient": MessageLookupByLibrary.simpleMessage('Der Server bearbeitet diese Anfrage bereits'), + "noListLoaded": + MessageLookupByLibrary.simpleMessage("Keine Liste geladen"), + "renameListItem": + MessageLookupByLibrary.simpleMessage("Produkt umbenennen"), + "renameListItemHint": + MessageLookupByLibrary.simpleMessage("Der neue Name des Produktes"), + "renameListItemLabel": + MessageLookupByLibrary.simpleMessage("Neuer Prdouktname"), + "discardNewTheme": + MessageLookupByLibrary.simpleMessage("Änderungen verwerfen?"), + "forgotPassword": + MessageLookupByLibrary.simpleMessage("Passwort vergessen?"), + "bePatient": MessageLookupByLibrary.simpleMessage( + 'Der Server bearbeitet diese Anfrage bereits'), "logout": MessageLookupByLibrary.simpleMessage('Ausloggen'), - "deleteListTitle": MessageLookupByLibrary.simpleMessage('Lösche Liste '), + "deleteListTitle": + MessageLookupByLibrary.simpleMessage('Lösche Liste '), "deleteListText": MessageLookupByLibrary.simpleMessage( 'Soll diese Liste wirklich gelöscht werden? Das kann NICHT rückgängig gemacht werden!'), - "exportAsPdf": MessageLookupByLibrary.simpleMessage('Als PDF exportieren'), + "exportAsPdf": + MessageLookupByLibrary.simpleMessage('Als PDF exportieren'), "boughtProducts": MessageLookupByLibrary.simpleMessage('Eingekauft'), - "nothingBoughtYet": MessageLookupByLibrary.simpleMessage('Noch nichts eingekauft'), + "nothingBoughtYet": + MessageLookupByLibrary.simpleMessage('Noch nichts eingekauft'), "reorderItems": MessageLookupByLibrary.simpleMessage('Reihenfolge'), "refresh": MessageLookupByLibrary.simpleMessage('Aktualisieren'), "okayButton": MessageLookupByLibrary.simpleMessage('OKAY'), - "requestPasswordResetButton": MessageLookupByLibrary.simpleMessage("PASSWORT ZURÜCKSETZUNG BEANTRAGEN"), - "requestPasswordResetTitle": MessageLookupByLibrary.simpleMessage("Passwort zurücksetzen"), + "requestPasswordResetButton": MessageLookupByLibrary.simpleMessage( + "PASSWORT ZURÜCKSETZUNG BEANTRAGEN"), + "requestPasswordResetTitle": + MessageLookupByLibrary.simpleMessage("Passwort zurücksetzen"), "requestPasswordResetSuccess": MessageLookupByLibrary.simpleMessage( 'Die Passwort zurücksetzen Email wurde erfolgreich an die Adresse gesendet, sollte diese existieren. Weitere Schritte für das abschließen des Resets sind in der Email enthalten.'), "settings": MessageLookupByLibrary.simpleMessage('Einstellungen'), "about": MessageLookupByLibrary.simpleMessage('Über'), - "codeOnGithub": MessageLookupByLibrary.simpleMessage('Schau doch mal in den Code auf GitHub rein'), - "playstoreEntry": MessageLookupByLibrary.simpleMessage('Play Store Eintrag'), - "iconSource": MessageLookupByLibrary.simpleMessage('Wer hat dieses schicke Icon gemacht? Finde es heraus!'), - "scanditCredit": - MessageLookupByLibrary.simpleMessage('hat diesen super Scanner in der App zur Verfügung gestellt'), + "codeOnGithub": MessageLookupByLibrary.simpleMessage( + 'Schau doch mal in den Code auf GitHub rein'), + "playstoreEntry": + MessageLookupByLibrary.simpleMessage('Play Store Eintrag'), + "iconSource": MessageLookupByLibrary.simpleMessage( + 'Wer hat dieses schicke Icon gemacht? Finde es heraus!'), + "scanditCredit": MessageLookupByLibrary.simpleMessage( + 'hat diesen super Scanner in der App zur Verfügung gestellt'), "aboutText": MessageLookupByLibrary.simpleMessage( 'In jahrelanger Handarbeit geschmiedet mit dem einzigen Ziel, die Einkaufsplanung mit anderen zu vereinfachen und dabei seine Lieblingsprodukte blitzschnell per Kamera zu erfassen.'), - "freeText": MessageLookupByLibrary.simpleMessage('Kostenlos, Werbefrei, für immer!'), + "freeText": MessageLookupByLibrary.simpleMessage( + 'Kostenlos, Werbefrei, für immer!'), "questionsErrors": MessageLookupByLibrary.simpleMessage( 'Bei Fragen, Anregungen, Fehlern oder sonstigen Belangen kann jederzeit auf GitHub vorbeigeschaut werden, um ein Issue zu eröffnen.'), + "useMaterial3": MessageLookupByLibrary.simpleMessage( + 'Aktiviere Material Design 3 (Farben basierend auf Android Einstellungen)'), + "elevateAppBar": + MessageLookupByLibrary.simpleMessage('Hebe Titel farblich hervor'), }; } diff --git a/lib/localization/nssl_messages_en.dart b/lib/localization/nssl_messages_en.dart index 5c6cd0e..50c7e5c 100644 --- a/lib/localization/nssl_messages_en.dart +++ b/lib/localization/nssl_messages_en.dart @@ -5,162 +5,249 @@ final messages = MessageLookup(); class MessageLookup extends MessageLookupByLibrary { get localeName => 'en'; - final Map messages = _notInlinedMessages(_notInlinedMessages); + final Map messages = + _notInlinedMessages(_notInlinedMessages); static _notInlinedMessages(_) => { "options": MessageLookupByLibrary.simpleMessage("Options"), "changeTheme": MessageLookupByLibrary.simpleMessage("Change Theme"), "scanPB": MessageLookupByLibrary.simpleMessage("SCAN"), "addPB": MessageLookupByLibrary.simpleMessage("ADD"), "searchPB": MessageLookupByLibrary.simpleMessage("SEARCH"), - "deleteCrossedOutPB": MessageLookupByLibrary.simpleMessage("Delete crossed out"), + "deleteCrossedOutPB": + MessageLookupByLibrary.simpleMessage("Delete crossed out"), "addListPB": MessageLookupByLibrary.simpleMessage("ADD LIST"), "contributors": MessageLookupByLibrary.simpleMessage("Contributors"), "rename": MessageLookupByLibrary.simpleMessage("Rename"), "remove": MessageLookupByLibrary.simpleMessage("Remove"), "addProduct": MessageLookupByLibrary.simpleMessage('Add Product'), - "addProductWithoutSearch": - MessageLookupByLibrary.simpleMessage('Insert the name of the product, without searching in the database'), + "addProductWithoutSearch": MessageLookupByLibrary.simpleMessage( + 'Insert the name of the product, without searching in the database'), "productName": MessageLookupByLibrary.simpleMessage('product name'), - "messageDeleteAllCrossedOut": MessageLookupByLibrary.simpleMessage("You have deleted all crossed out items"), + "messageDeleteAllCrossedOut": MessageLookupByLibrary.simpleMessage( + "You have deleted all crossed out items"), "undo": MessageLookupByLibrary.simpleMessage("UNDO"), - "removedShoppingListMessage": - MessageLookupByLibrary.simpleMessage(" removed"), //"Removed \${User.shoppingLists} " - "noListsInDrawerMessage": MessageLookupByLibrary.simpleMessage("here is the place for your lists"), - "notLoggedInYet": MessageLookupByLibrary.simpleMessage("Not logged in yet"), - "newNameOfListHint": MessageLookupByLibrary.simpleMessage('The new name of the new list'), + "removedShoppingListMessage": MessageLookupByLibrary.simpleMessage( + " removed"), //"Removed \${User.shoppingLists} " + "noListsInDrawerMessage": MessageLookupByLibrary.simpleMessage( + "here is the place for your lists"), + "notLoggedInYet": + MessageLookupByLibrary.simpleMessage("Not logged in yet"), + "newNameOfListHint": MessageLookupByLibrary.simpleMessage( + 'The new name of the new list'), "listName": MessageLookupByLibrary.simpleMessage('listname'), "renameListTitle": MessageLookupByLibrary.simpleMessage("Rename List"), - "renameListHint": MessageLookupByLibrary.simpleMessage('The name of the new list'), - "chooseListToAddTitle": MessageLookupByLibrary.simpleMessage('Which list to add?'), + "renameListHint": + MessageLookupByLibrary.simpleMessage('The name of the new list'), + "chooseListToAddTitle": + MessageLookupByLibrary.simpleMessage('Which list to add?'), "addNewListTitle": MessageLookupByLibrary.simpleMessage("Add new List"), - "recipeCreateError": MessageLookupByLibrary.simpleMessage("Could not create recipe"), - "recipeFromShareTitle": MessageLookupByLibrary.simpleMessage("To which list to add?"), + "recipeCreateError": + MessageLookupByLibrary.simpleMessage("Could not create recipe"), + "recipeFromShareTitle": + MessageLookupByLibrary.simpleMessage("To which list to add?"), "recipeFromShareNew": MessageLookupByLibrary.simpleMessage("NEW"), "recipeName": MessageLookupByLibrary.simpleMessage("Recipe"), - "recipeNameHint": MessageLookupByLibrary.simpleMessage("Recipe ID or URL"), - "addNewRecipeTitle": MessageLookupByLibrary.simpleMessage("Add new recipe"), - "importNewRecipe": MessageLookupByLibrary.simpleMessage("Import recipe"), - "importNewRecipeTitle": MessageLookupByLibrary.simpleMessage("Import new recipe"), - "chooseAddListDialog": MessageLookupByLibrary.simpleMessage("Shopping"), - "chooseAddRecipeDialog": MessageLookupByLibrary.simpleMessage("Chefkoch"), - "youHaveActionItemMessage": MessageLookupByLibrary.simpleMessage('You have '), //\$action \$item + "recipeNameHint": + MessageLookupByLibrary.simpleMessage("Recipe ID or URL"), + "addNewRecipeTitle": + MessageLookupByLibrary.simpleMessage("Add new recipe"), + "importNewRecipe": + MessageLookupByLibrary.simpleMessage("Import recipe"), + "importNewRecipeTitle": + MessageLookupByLibrary.simpleMessage("Import new recipe"), + "chooseAddListDialog": + MessageLookupByLibrary.simpleMessage("Shoppinglist"), + "chooseAddRecipeDialog": + MessageLookupByLibrary.simpleMessage("Chefkoch Recipe"), + "youHaveActionItemMessage": + MessageLookupByLibrary.simpleMessage('You have '), //\$action \$item "archived": MessageLookupByLibrary.simpleMessage('archived'), "deleted": MessageLookupByLibrary.simpleMessage('deleted'), - "youHaveActionNameMessage": MessageLookupByLibrary.simpleMessage('You have '), //\$action \${s.name} + "youHaveActionNameMessage": MessageLookupByLibrary.simpleMessage( + 'You have '), //\$action \${s.name} "demoteMenu": MessageLookupByLibrary.simpleMessage('Demote'), "promoteMenu": MessageLookupByLibrary.simpleMessage('Promote'), "contributorUser": MessageLookupByLibrary.simpleMessage(" - User"), "contributorAdmin": MessageLookupByLibrary.simpleMessage(" - Admin"), - "genericErrorMessageSnackbar": MessageLookupByLibrary.simpleMessage("Something went wrong!\n"), //\${z.error} - "nameOfNewContributorHint": MessageLookupByLibrary.simpleMessage("Name of new Contributor"), - "wasRemovedSuccessfullyMessage": MessageLookupByLibrary.simpleMessage(" was removed successfully"), - "loginSuccessfullMessage": MessageLookupByLibrary.simpleMessage("Login successfull."), - "nameEmailRequiredError": MessageLookupByLibrary.simpleMessage('Name or Email is required.'), - "usernameToShortError": - MessageLookupByLibrary.simpleMessage('Your username has to be at least 4 characters long'), - "emailRequiredError": MessageLookupByLibrary.simpleMessage('EMail is required.'), - "emailIncorrectFormatError": - MessageLookupByLibrary.simpleMessage('The email seems to be in the incorrect format.'), - "chooseAPassword": MessageLookupByLibrary.simpleMessage('Please choose a password.'), + "genericErrorMessageSnackbar": MessageLookupByLibrary.simpleMessage( + "Something went wrong!\n"), //\${z.error} + "nameOfNewContributorHint": + MessageLookupByLibrary.simpleMessage("Name of new Contributor"), + "wasRemovedSuccessfullyMessage": + MessageLookupByLibrary.simpleMessage(" was removed successfully"), + "loginSuccessfullMessage": + MessageLookupByLibrary.simpleMessage("Login successfull."), + "nameEmailRequiredError": + MessageLookupByLibrary.simpleMessage('Name or Email is required.'), + "usernameToShortError": MessageLookupByLibrary.simpleMessage( + 'Your username has to be at least 4 characters long'), + "emailRequiredError": + MessageLookupByLibrary.simpleMessage('EMail is required.'), + "emailIncorrectFormatError": MessageLookupByLibrary.simpleMessage( + 'The email seems to be in the incorrect format.'), + "chooseAPassword": + MessageLookupByLibrary.simpleMessage('Please choose a password.'), "login": MessageLookupByLibrary.simpleMessage("Login"), - "usernameOrEmailForLoginHint": MessageLookupByLibrary.simpleMessage('Username or email can be used to login'), - "usernameOrEmailTitle": MessageLookupByLibrary.simpleMessage('Username or Email'), + "usernameOrEmailForLoginHint": MessageLookupByLibrary.simpleMessage( + 'Username or email can be used to login'), + "usernameOrEmailTitle": + MessageLookupByLibrary.simpleMessage('Username or Email'), "emailTitle": MessageLookupByLibrary.simpleMessage('Email'), - "choosenPasswordHint": MessageLookupByLibrary.simpleMessage('The password you have choosen'), + "choosenPasswordHint": MessageLookupByLibrary.simpleMessage( + 'The password you have choosen'), "password": MessageLookupByLibrary.simpleMessage('Password'), "loginButton": MessageLookupByLibrary.simpleMessage('LOGIN'), - "registerTextOnLogin": MessageLookupByLibrary.simpleMessage("Don't have an account? Create one now."), - "usernameEmptyError": MessageLookupByLibrary.simpleMessage("Username has to be filled in"), - "passwordEmptyError": MessageLookupByLibrary.simpleMessage("Password has to be filled in"), - "passwordTooShortError": MessageLookupByLibrary.simpleMessage("Password has to be at least 6 charactes long"), + "registerTextOnLogin": MessageLookupByLibrary.simpleMessage( + "Don't have an account? Create one now."), + "usernameEmptyError": MessageLookupByLibrary.simpleMessage( + "Username has to be filled in"), + "passwordEmptyError": MessageLookupByLibrary.simpleMessage( + "Password has to be filled in"), + "passwordTooShortError": MessageLookupByLibrary.simpleMessage( + "Password has to be at least 6 charactes long"), "passwordMissingCharactersError": MessageLookupByLibrary.simpleMessage( "Password has to contain a special character (Can be emoji or any other symbol) and a letter or number"), - "emailEmptyError": MessageLookupByLibrary.simpleMessage("Email has to be filled in"), - "reenterPasswordError": MessageLookupByLibrary.simpleMessage("Passwords doesn't match or are empty"), - "unknownUsernameError": MessageLookupByLibrary.simpleMessage("There is something wrong with your username"), - "unknownEmailError": MessageLookupByLibrary.simpleMessage("There is something wrong with your email"), - "unknownPasswordError": MessageLookupByLibrary.simpleMessage("There is something wrong with your password"), - "unknownReenterPasswordError": - MessageLookupByLibrary.simpleMessage("There is something wrong with your password validation"), - "registrationSuccessfulMessage": MessageLookupByLibrary.simpleMessage("Registration successfull."), - "registrationTitle": MessageLookupByLibrary.simpleMessage("Registration"), - "nameEmptyError": MessageLookupByLibrary.simpleMessage('Name is required.'), - "chooseAPasswordPrompt": MessageLookupByLibrary.simpleMessage('Please choose a password.'), - "reenterPasswordPrompt": MessageLookupByLibrary.simpleMessage('Please reenter your password.'), - "passwordsDontMatchError": MessageLookupByLibrary.simpleMessage('Passwords don\'t match'), - "usernameRegisterHint": MessageLookupByLibrary.simpleMessage('The name to login and to be found by others'), + "emailEmptyError": + MessageLookupByLibrary.simpleMessage("Email has to be filled in"), + "reenterPasswordError": MessageLookupByLibrary.simpleMessage( + "Passwords doesn't match or are empty"), + "unknownUsernameError": MessageLookupByLibrary.simpleMessage( + "There is something wrong with your username"), + "unknownEmailError": MessageLookupByLibrary.simpleMessage( + "There is something wrong with your email"), + "unknownPasswordError": MessageLookupByLibrary.simpleMessage( + "There is something wrong with your password"), + "unknownReenterPasswordError": MessageLookupByLibrary.simpleMessage( + "There is something wrong with your password validation"), + "registrationSuccessfulMessage": + MessageLookupByLibrary.simpleMessage("Registration successfull."), + "registrationTitle": + MessageLookupByLibrary.simpleMessage("Registration"), + "nameEmptyError": + MessageLookupByLibrary.simpleMessage('Name is required.'), + "chooseAPasswordPrompt": + MessageLookupByLibrary.simpleMessage('Please choose a password.'), + "reenterPasswordPrompt": MessageLookupByLibrary.simpleMessage( + 'Please reenter your password.'), + "passwordsDontMatchError": + MessageLookupByLibrary.simpleMessage('Passwords don\'t match'), + "usernameRegisterHint": MessageLookupByLibrary.simpleMessage( + 'The name to login and to be found by others'), "username": MessageLookupByLibrary.simpleMessage('Username'), - "emailRegisterHint": MessageLookupByLibrary.simpleMessage('The email to login and to be found by others'), - "passwordRegisterHint": MessageLookupByLibrary.simpleMessage('The password to secure your account'), - "retypePasswordHint": MessageLookupByLibrary.simpleMessage('Re-type your password for validation'), - "retypePasswordTitle": MessageLookupByLibrary.simpleMessage('Re-type Password'), + "emailRegisterHint": MessageLookupByLibrary.simpleMessage( + 'The email to login and to be found by others'), + "passwordRegisterHint": MessageLookupByLibrary.simpleMessage( + 'The password to secure your account'), + "retypePasswordHint": MessageLookupByLibrary.simpleMessage( + 'Re-type your password for validation'), + "retypePasswordTitle": + MessageLookupByLibrary.simpleMessage('Re-type Password'), "registerButton": MessageLookupByLibrary.simpleMessage('REGISTER'), - "discardNewProduct": MessageLookupByLibrary.simpleMessage('Discard new product?'), + "discardNewProduct": + MessageLookupByLibrary.simpleMessage('Discard new product?'), "cancelButton": MessageLookupByLibrary.simpleMessage('CANCEL'), "acceptButton": MessageLookupByLibrary.simpleMessage('ACCEPT'), "discardButton": MessageLookupByLibrary.simpleMessage('DISCARD'), - "fixErrorsBeforeSubmittingPrompt": - MessageLookupByLibrary.simpleMessage('Please fix the errors in red before submitting.'), + "fixErrorsBeforeSubmittingPrompt": MessageLookupByLibrary.simpleMessage( + 'Please fix the errors in red before submitting.'), "newProductTitle": MessageLookupByLibrary.simpleMessage('New Product'), "saveButton": MessageLookupByLibrary.simpleMessage('SAVE'), - "newProductName": MessageLookupByLibrary.simpleMessage("Product Name *"), - "newProductNameHint": MessageLookupByLibrary.simpleMessage("How is this product called?"), - "newProductBrandName": MessageLookupByLibrary.simpleMessage("Brand Name *"), - "newProductBrandNameHint": MessageLookupByLibrary.simpleMessage("Which company sells this product?"), - "newProductWeight": MessageLookupByLibrary.simpleMessage("Amount with Unit"), - "newProductWeightHint": MessageLookupByLibrary.simpleMessage("Example: 1.5l or 100g"), - "newProductAddToList": MessageLookupByLibrary.simpleMessage("Add to current list"), - "newProductAddedToList": MessageLookupByLibrary.simpleMessage(" was added to list "), - "newProductStarExplanation": MessageLookupByLibrary.simpleMessage('* indicates required field'), - "fieldRequiredError": MessageLookupByLibrary.simpleMessage("This field is required!"), - "newProductNameToShort": MessageLookupByLibrary.simpleMessage("This name seems to be to short"), - "addedProduct": MessageLookupByLibrary.simpleMessage(' added'), //'Added "\$name"' - "productWasAlreadyInList": - MessageLookupByLibrary.simpleMessage(' was already in list. The amount was increased by 1'), //"\$name" was - "searchProductHint": MessageLookupByLibrary.simpleMessage("Search Product"), - "noMoreProductsMessage": MessageLookupByLibrary.simpleMessage("No more products found!}"), + "newProductName": + MessageLookupByLibrary.simpleMessage("Product Name *"), + "newProductNameHint": + MessageLookupByLibrary.simpleMessage("How is this product called?"), + "newProductBrandName": + MessageLookupByLibrary.simpleMessage("Brand Name *"), + "newProductBrandNameHint": MessageLookupByLibrary.simpleMessage( + "Which company sells this product?"), + "newProductWeight": + MessageLookupByLibrary.simpleMessage("Amount with Unit"), + "newProductWeightHint": + MessageLookupByLibrary.simpleMessage("Example: 1.5l or 100g"), + "newProductAddToList": + MessageLookupByLibrary.simpleMessage("Add to current list"), + "newProductAddedToList": + MessageLookupByLibrary.simpleMessage(" was added to list "), + "newProductStarExplanation": + MessageLookupByLibrary.simpleMessage('* indicates required field'), + "fieldRequiredError": + MessageLookupByLibrary.simpleMessage("This field is required!"), + "newProductNameToShort": MessageLookupByLibrary.simpleMessage( + "This name seems to be to short"), + "addedProduct": + MessageLookupByLibrary.simpleMessage(' added'), //'Added "\$name"' + "productWasAlreadyInList": MessageLookupByLibrary.simpleMessage( + ' was already in list. The amount was increased by 1'), //"\$name" was + "searchProductHint": + MessageLookupByLibrary.simpleMessage("Search Product"), + "noMoreProductsMessage": + MessageLookupByLibrary.simpleMessage("No more products found!}"), "codeText": MessageLookupByLibrary.simpleMessage("Code: "), "removed": MessageLookupByLibrary.simpleMessage("removed"), - "changePrimaryColor": MessageLookupByLibrary.simpleMessage("Primary Color"), - "changeAccentColor": MessageLookupByLibrary.simpleMessage("Accent Color"), + "changePrimaryColor": + MessageLookupByLibrary.simpleMessage("Primary Color"), + "changeAccentColor": + MessageLookupByLibrary.simpleMessage("Accent Color"), "changeDarkTheme": MessageLookupByLibrary.simpleMessage("Dark Theme"), - "changeAccentTextColor": MessageLookupByLibrary.simpleMessage("Bright Icons"), + "changeAccentTextColor": + MessageLookupByLibrary.simpleMessage("Bright Icons"), "autoSync": MessageLookupByLibrary.simpleMessage("Auto-Sync"), - "changePasswordButton": MessageLookupByLibrary.simpleMessage("CHANGE PASSWORD"), - "currentPassword": MessageLookupByLibrary.simpleMessage("Current password"), - "currentPasswordHint": MessageLookupByLibrary.simpleMessage("Current password that should be changed"), + "changePasswordButton": + MessageLookupByLibrary.simpleMessage("CHANGE PASSWORD"), + "currentPassword": + MessageLookupByLibrary.simpleMessage("Current password"), + "currentPasswordHint": MessageLookupByLibrary.simpleMessage( + "Current password that should be changed"), "newPassword": MessageLookupByLibrary.simpleMessage("New password"), - "newPasswordHint": MessageLookupByLibrary.simpleMessage("The new password you have chosen"), - "repeatNewPassword": MessageLookupByLibrary.simpleMessage("Repeat new password"), - "repeatNewPasswordHint": MessageLookupByLibrary.simpleMessage("Repeat the new password you have chosen"), - "changePasswordPD": MessageLookupByLibrary.simpleMessage("Change Password"), + "newPasswordHint": MessageLookupByLibrary.simpleMessage( + "The new password you have chosen"), + "repeatNewPassword": + MessageLookupByLibrary.simpleMessage("Repeat new password"), + "repeatNewPasswordHint": MessageLookupByLibrary.simpleMessage( + "Repeat the new password you have chosen"), + "changePasswordPD": + MessageLookupByLibrary.simpleMessage("Change Password"), "successful": MessageLookupByLibrary.simpleMessage("Successful"), - "passwordSet": MessageLookupByLibrary.simpleMessage("Your password has been set"), + "passwordSet": + MessageLookupByLibrary.simpleMessage("Your password has been set"), "tokenExpired": MessageLookupByLibrary.simpleMessage("Token expired"), "tokenExpiredExplanation": MessageLookupByLibrary.simpleMessage( "Your token has expired. Login is required. If this happends multiple times per month, please contact us."), "noListLoaded": MessageLookupByLibrary.simpleMessage("No List Loaded"), - "renameListItem": MessageLookupByLibrary.simpleMessage("Rename Product"), - "renameListItemHint": MessageLookupByLibrary.simpleMessage("The new name of the product"), - "renameListItemLabel": MessageLookupByLibrary.simpleMessage("new product name"), - "discardNewTheme": MessageLookupByLibrary.simpleMessage('Discard new theme?'), - "forgotPassword": MessageLookupByLibrary.simpleMessage('Forgot password?'), - "bePatient": - MessageLookupByLibrary.simpleMessage('Please be patient, the server is processing your request already'), + "renameListItem": + MessageLookupByLibrary.simpleMessage("Rename Product"), + "renameListItemHint": + MessageLookupByLibrary.simpleMessage("The new name of the product"), + "renameListItemLabel": + MessageLookupByLibrary.simpleMessage("new product name"), + "discardNewTheme": + MessageLookupByLibrary.simpleMessage('Discard new theme?'), + "forgotPassword": + MessageLookupByLibrary.simpleMessage('Forgot password?'), + "bePatient": MessageLookupByLibrary.simpleMessage( + 'Please be patient, the server is processing your request already'), "logout": MessageLookupByLibrary.simpleMessage('Logout'), "deleteListTitle": MessageLookupByLibrary.simpleMessage('Delete List '), - "deleteListText": - MessageLookupByLibrary.simpleMessage('Do you really want to delete the list? This CAN\'T be undone!'), + "deleteListText": MessageLookupByLibrary.simpleMessage( + 'Do you really want to delete the list? This CAN\'T be undone!'), "exportAsPdf": MessageLookupByLibrary.simpleMessage('Export as PDF'), - "boughtProducts": MessageLookupByLibrary.simpleMessage('Bought Products'), - "nothingBoughtYet": MessageLookupByLibrary.simpleMessage('Nothing bought yet'), + "boughtProducts": + MessageLookupByLibrary.simpleMessage('Bought Products'), + "nothingBoughtYet": + MessageLookupByLibrary.simpleMessage('Nothing bought yet'), "reorderItems": MessageLookupByLibrary.simpleMessage('Reorder'), "refresh": MessageLookupByLibrary.simpleMessage('Refresh'), "okayButton": MessageLookupByLibrary.simpleMessage('OKAY'), - "requestPasswordResetButton": MessageLookupByLibrary.simpleMessage("REQUEST PASSWORD RESET"), - "requestPasswordResetTitle": MessageLookupByLibrary.simpleMessage("Password Reset"), + "requestPasswordResetButton": + MessageLookupByLibrary.simpleMessage("REQUEST PASSWORD RESET"), + "requestPasswordResetTitle": + MessageLookupByLibrary.simpleMessage("Password Reset"), "requestPasswordResetSuccess": MessageLookupByLibrary.simpleMessage( 'If the email exists, the password request was successfully requested. Further instructions can be found in the email, that was send to the address.'), "settings": MessageLookupByLibrary.simpleMessage('Settings'), + "useMaterial3": MessageLookupByLibrary.simpleMessage( + 'Use Material Design 3 (Colors based on Android Version)'), + "elevateAppBar": + MessageLookupByLibrary.simpleMessage('Colorize Title Background'), }; } diff --git a/lib/localization/nssl_strings.dart b/lib/localization/nssl_strings.dart index fc17aa2..0cc3e3c 100644 --- a/lib/localization/nssl_strings.dart +++ b/lib/localization/nssl_strings.dart @@ -21,221 +21,354 @@ class NSSLStrings { } // static final NSSLStrings instance = NSSLStrings(); - String options() => Intl.message('Options', name: 'options', locale: _localeName); - String changeTheme() => Intl.message('Change Theme', name: 'changeTheme', locale: _localeName); + String options() => + Intl.message('Options', name: 'options', locale: _localeName); + String changeTheme() => + Intl.message('Change Theme', name: 'changeTheme', locale: _localeName); String scanPB() => Intl.message('SCAN', name: 'scanPB', locale: _localeName); String addPB() => Intl.message('ADD', name: 'addPB', locale: _localeName); - String searchPB() => Intl.message('SEARCH', name: 'searchPB', locale: _localeName); - String deleteCrossedOutPB() => Intl.message('DELETE CROSSED OUT', name: 'deleteCrossedOutPB', locale: _localeName); - String addListPB() => Intl.message('ADD LIST', name: 'addListPB', locale: _localeName); - String contributors() => Intl.message('Contributors', name: 'contributors', locale: _localeName); - String rename() => Intl.message('Rename', name: 'rename', locale: _localeName); - String remove() => Intl.message('Remove', name: 'remove', locale: _localeName); - String addProduct() => Intl.message('Add Product', name: 'addProduct', locale: _localeName); - String addProductWithoutSearch() => Intl.message('Insert the name of the product, without searching in the database', - name: 'addProductWithoutSearch', locale: _localeName); - String productName() => Intl.message('Product name', name: 'productName', locale: _localeName); + String searchPB() => + Intl.message('SEARCH', name: 'searchPB', locale: _localeName); + String deleteCrossedOutPB() => Intl.message('DELETE CROSSED OUT', + name: 'deleteCrossedOutPB', locale: _localeName); + String addListPB() => + Intl.message('ADD LIST', name: 'addListPB', locale: _localeName); + String contributors() => + Intl.message('Contributors', name: 'contributors', locale: _localeName); + String rename() => + Intl.message('Rename', name: 'rename', locale: _localeName); + String remove() => + Intl.message('Remove', name: 'remove', locale: _localeName); + String addProduct() => + Intl.message('Add Product', name: 'addProduct', locale: _localeName); + String addProductWithoutSearch() => Intl.message( + 'Insert the name of the product, without searching in the database', + name: 'addProductWithoutSearch', + locale: _localeName); + String productName() => + Intl.message('Product name', name: 'productName', locale: _localeName); String messageDeleteAllCrossedOut() => - Intl.message('You have deleted all crossed out items', name: 'messageDeleteAllCrossedOut', locale: _localeName); + Intl.message('You have deleted all crossed out items', + name: 'messageDeleteAllCrossedOut', locale: _localeName); String undo() => Intl.message('UNDO', name: 'undo', locale: _localeName); String noListsInDrawerMessage() => - Intl.message('Here is the place for your lists', name: 'noListsInDrawerMessage', locale: _localeName); - String notLoggedInYet() => Intl.message('Not logged in yet', name: 'notLoggedInYet', locale: _localeName); - String newNameOfListHint() => - Intl.message('The new name of the new list', name: 'newNameOfListHint', locale: _localeName); - String listName() => Intl.message('Listname', name: 'listName', locale: _localeName); - String renameListTitle() => Intl.message('Rename List', name: 'renameListTitle', locale: _localeName); - String renameListHint() => Intl.message('The name of the new list', name: 'renameListHint', locale: _localeName); - String chooseListToAddTitle() => - Intl.message('Which list to add?', name: 'chooseListToAddTitle', locale: _localeName); - String addNewListTitle() => Intl.message('Add new List', name: 'addNewListTitle', locale: _localeName); - String recipeCreateError() => Intl.message('Could not create recipe', name: 'recipeCreateError', locale: _localeName); - String recipeFromShareTitle() => - Intl.message('To which list to add?', name: 'recipeFromShareTitle', locale: _localeName); - String recipeFromShareNew() => Intl.message('NEW', name: 'recipeFromShareNew', locale: _localeName); - String recipeName() => Intl.message('Recipe', name: 'recipeName', locale: _localeName); - String recipeNameHint() => Intl.message('Recipe ID or URL', name: 'recipeNameHint', locale: _localeName); - String addNewRecipeTitle() => Intl.message('Add new recipe', name: 'addNewRecipeTitle', locale: _localeName); - String importNewRecipe() => Intl.message('Import recipe', name: 'importNewRecipe', locale: _localeName); - String importNewRecipeTitle() => Intl.message('Import new recipe', name: 'importNewRecipeTitle', locale: _localeName); - String chooseAddListDialog() => Intl.message('Shopping', name: 'chooseAddListDialog', locale: _localeName); - String chooseAddRecipeDialog() => Intl.message('Chefkoch', name: 'chooseAddRecipeDialog', locale: _localeName); - String youHaveActionItemMessage() => Intl.message('You have ', name: 'youHaveActionItemMessage', locale: _localeName); - String archived() => Intl.message('archived', name: 'archived', locale: _localeName); - String deleted() => Intl.message('deleted', name: 'deleted', locale: _localeName); - String youHaveActionNameMessage() => Intl.message('You have ', name: 'youHaveActionNameMessage', locale: _localeName); - String demoteMenu() => Intl.message('Demote', name: 'demoteMenu', locale: _localeName); - String promoteMenu() => Intl.message('Promote', name: 'promoteMenu', locale: _localeName); - String contributorUser() => Intl.message(" - User", name: 'contributorUser', locale: _localeName); - String contributorAdmin() => Intl.message(" - Admin", name: 'contributorAdmin', locale: _localeName); + Intl.message('Here is the place for your lists', + name: 'noListsInDrawerMessage', locale: _localeName); + String notLoggedInYet() => Intl.message('Not logged in yet', + name: 'notLoggedInYet', locale: _localeName); + String newNameOfListHint() => Intl.message('The new name of the new list', + name: 'newNameOfListHint', locale: _localeName); + String listName() => + Intl.message('Listname', name: 'listName', locale: _localeName); + String renameListTitle() => + Intl.message('Rename List', name: 'renameListTitle', locale: _localeName); + String renameListHint() => Intl.message('The name of the new list', + name: 'renameListHint', locale: _localeName); + String chooseListToAddTitle() => Intl.message('Which list to add?', + name: 'chooseListToAddTitle', locale: _localeName); + String addNewListTitle() => Intl.message('Add new List', + name: 'addNewListTitle', locale: _localeName); + String recipeCreateError() => Intl.message('Could not create recipe', + name: 'recipeCreateError', locale: _localeName); + String recipeFromShareTitle() => Intl.message('To which list to add?', + name: 'recipeFromShareTitle', locale: _localeName); + String recipeFromShareNew() => + Intl.message('NEW', name: 'recipeFromShareNew', locale: _localeName); + String recipeName() => + Intl.message('Recipe', name: 'recipeName', locale: _localeName); + String recipeNameHint() => Intl.message('Recipe ID or URL', + name: 'recipeNameHint', locale: _localeName); + String addNewRecipeTitle() => Intl.message('Add new recipe', + name: 'addNewRecipeTitle', locale: _localeName); + String importNewRecipe() => Intl.message('Import recipe', + name: 'importNewRecipe', locale: _localeName); + String importNewRecipeTitle() => Intl.message('Import new recipe', + name: 'importNewRecipeTitle', locale: _localeName); + String chooseAddListDialog() => Intl.message('Shoppinglist', + name: 'chooseAddListDialog', locale: _localeName); + String chooseAddRecipeDialog() => Intl.message('Chefkoch Recipe', + name: 'chooseAddRecipeDialog', locale: _localeName); + String youHaveActionItemMessage() => Intl.message('You have ', + name: 'youHaveActionItemMessage', locale: _localeName); + String archived() => + Intl.message('archived', name: 'archived', locale: _localeName); + String deleted() => + Intl.message('deleted', name: 'deleted', locale: _localeName); + String youHaveActionNameMessage() => Intl.message('You have ', + name: 'youHaveActionNameMessage', locale: _localeName); + String demoteMenu() => + Intl.message('Demote', name: 'demoteMenu', locale: _localeName); + String promoteMenu() => + Intl.message('Promote', name: 'promoteMenu', locale: _localeName); + String contributorUser() => + Intl.message(" - User", name: 'contributorUser', locale: _localeName); + String contributorAdmin() => + Intl.message(" - Admin", name: 'contributorAdmin', locale: _localeName); String genericErrorMessageSnackbar() => - Intl.message('Something went wrong!\n', name: 'genericErrorMessageSnackbar', locale: _localeName); - String nameOfNewContributorHint() => - Intl.message('Name of new Contributor', name: 'nameOfNewContributorHint', locale: _localeName); + Intl.message('Something went wrong!\n', + name: 'genericErrorMessageSnackbar', locale: _localeName); + String nameOfNewContributorHint() => Intl.message('Name of new Contributor', + name: 'nameOfNewContributorHint', locale: _localeName); String wasRemovedSuccessfullyMessage() => - Intl.message(' was removed successfully', name: 'wasRemovedSuccessfullyMessage', locale: _localeName); + Intl.message(' was removed successfully', + name: 'wasRemovedSuccessfullyMessage', locale: _localeName); String loginSuccessfulMessage() => - Intl.message('Login successfull, lists will be loaded.', name: 'loginSuccessfullMessage', locale: _localeName); - String nameEmailRequiredError() => - Intl.message('Name or Email is required.', name: 'nameEmailRequiredError', locale: _localeName); - String usernameToShortError() => Intl.message('Your username has to be at least 4 characters long', - name: 'usernameToShortError', locale: _localeName); - String emailRequiredError() => Intl.message('EMail is required.', name: 'emailRequiredError', locale: _localeName); - String emailIncorrectFormatError() => Intl.message('The email seems to be in the incorrect format.', - name: 'emailIncorrectFormatError', locale: _localeName); - String chooseAPassword() => Intl.message('Please choose a password.', name: 'chooseAPassword', locale: _localeName); + Intl.message('Login successfull, lists will be loaded.', + name: 'loginSuccessfullMessage', locale: _localeName); + String nameEmailRequiredError() => Intl.message('Name or Email is required.', + name: 'nameEmailRequiredError', locale: _localeName); + String usernameToShortError() => + Intl.message('Your username has to be at least 4 characters long', + name: 'usernameToShortError', locale: _localeName); + String emailRequiredError() => Intl.message('EMail is required.', + name: 'emailRequiredError', locale: _localeName); + String emailIncorrectFormatError() => + Intl.message('The email seems to be in the incorrect format.', + name: 'emailIncorrectFormatError', locale: _localeName); + String chooseAPassword() => Intl.message('Please choose a password.', + name: 'chooseAPassword', locale: _localeName); String login() => Intl.message('Login', name: 'login', locale: _localeName); String usernameOrEmailForLoginHint() => - Intl.message('Username or email can be used to login', name: 'usernameOrEmailForLoginHint', locale: _localeName); - String usernameOrEmailTitle() => Intl.message('Username or Email', name: 'usernameOrEmailTitle', locale: _localeName); - String emailTitle() => Intl.message('Email', name: 'emailTitle', locale: _localeName); - String choosenPasswordHint() => - Intl.message('The password you have choosen', name: 'choosenPasswordHint', locale: _localeName); - String password() => Intl.message('Password', name: 'password', locale: _localeName); - String loginButton() => Intl.message('LOGIN', name: 'loginButton', locale: _localeName); + Intl.message('Username or email can be used to login', + name: 'usernameOrEmailForLoginHint', locale: _localeName); + String usernameOrEmailTitle() => Intl.message('Username or Email', + name: 'usernameOrEmailTitle', locale: _localeName); + String emailTitle() => + Intl.message('Email', name: 'emailTitle', locale: _localeName); + String choosenPasswordHint() => Intl.message('The password you have choosen', + name: 'choosenPasswordHint', locale: _localeName); + String password() => + Intl.message('Password', name: 'password', locale: _localeName); + String loginButton() => + Intl.message('LOGIN', name: 'loginButton', locale: _localeName); String registerTextOnLogin() => - Intl.message('Don\'t have an account? Create one now.', name: 'registerTextOnLogin', locale: _localeName); - String usernameEmptyError() => - Intl.message('Username has to be filled in', name: 'usernameEmptyError', locale: _localeName); - String passwordEmptyError() => - Intl.message('Password has to be filled in', name: 'passwordEmptyError', locale: _localeName); + Intl.message('Don\'t have an account? Create one now.', + name: 'registerTextOnLogin', locale: _localeName); + String usernameEmptyError() => Intl.message('Username has to be filled in', + name: 'usernameEmptyError', locale: _localeName); + String passwordEmptyError() => Intl.message('Password has to be filled in', + name: 'passwordEmptyError', locale: _localeName); String passwordTooShortError() => - Intl.message('Password has to be at least 6 charactes long', name: 'passwordTooShortError', locale: _localeName); + Intl.message('Password has to be at least 6 charactes long', + name: 'passwordTooShortError', locale: _localeName); String passwordMissingCharactersError() => Intl.message( 'Password has to contain a special character (Can be emoji or any other symbol) and a letter or number', name: 'passwordMissingCharactersError', locale: _localeName); - String emailEmptyError() => Intl.message('Email has to be filled in', name: 'emailEmptyError', locale: _localeName); + String emailEmptyError() => Intl.message('Email has to be filled in', + name: 'emailEmptyError', locale: _localeName); String reenterPasswordError() => - Intl.message('Passwords doesn\'t match or are empty', name: 'reenterPasswordError', locale: _localeName); + Intl.message('Passwords doesn\'t match or are empty', + name: 'reenterPasswordError', locale: _localeName); String unknownUsernameError() => - Intl.message('There is something wrong with your username', name: 'unknownUsernameError', locale: _localeName); + Intl.message('There is something wrong with your username', + name: 'unknownUsernameError', locale: _localeName); String unknownEmailError() => - Intl.message('There is something wrong with your email', name: 'unknownEmailError', locale: _localeName); + Intl.message('There is something wrong with your email', + name: 'unknownEmailError', locale: _localeName); String unknownPasswordError() => - Intl.message('There is something wrong with your password', name: 'unknownPasswordError', locale: _localeName); - String unknownReenterPasswordError() => Intl.message('There is something wrong with your password validation', - name: 'unknownReenterPasswordError', locale: _localeName); + Intl.message('There is something wrong with your password', + name: 'unknownPasswordError', locale: _localeName); + String unknownReenterPasswordError() => + Intl.message('There is something wrong with your password validation', + name: 'unknownReenterPasswordError', locale: _localeName); String registrationSuccessfulMessage() => - Intl.message('Registration successfull.', name: 'registrationSuccessfullMessage', locale: _localeName); - String registrationTitle() => Intl.message('Registration', name: 'registrationTitle', locale: _localeName); - String nameEmptyError() => Intl.message('Name is required.', name: 'nameEmptyError', locale: _localeName); - String chooseAPasswordPrompt() => - Intl.message('Please choose a password.', name: 'chooseAPasswordPrompt', locale: _localeName); + Intl.message('Registration successfull.', + name: 'registrationSuccessfullMessage', locale: _localeName); + String registrationTitle() => Intl.message('Registration', + name: 'registrationTitle', locale: _localeName); + String nameEmptyError() => Intl.message('Name is required.', + name: 'nameEmptyError', locale: _localeName); + String chooseAPasswordPrompt() => Intl.message('Please choose a password.', + name: 'chooseAPasswordPrompt', locale: _localeName); String reenterPasswordPrompt() => - Intl.message('Please reenter your password.', name: 'reenterPasswordPromt', locale: _localeName); - String passwordsDontMatchError() => - Intl.message('Passwords don\'t match', name: 'passwordsDontMatchError', locale: _localeName); + Intl.message('Please reenter your password.', + name: 'reenterPasswordPromt', locale: _localeName); + String passwordsDontMatchError() => Intl.message('Passwords don\'t match', + name: 'passwordsDontMatchError', locale: _localeName); String usernameRegisterHint() => - Intl.message('The name to login and to be found by others', name: 'usernameRegisterHint', locale: _localeName); - String username() => Intl.message('Username', name: 'username', locale: _localeName); + Intl.message('The name to login and to be found by others', + name: 'usernameRegisterHint', locale: _localeName); + String username() => + Intl.message('Username', name: 'username', locale: _localeName); String emailRegisterHint() => - Intl.message('The email to login and to be found by others', name: 'emailRegisterHint', locale: _localeName); + Intl.message('The email to login and to be found by others', + name: 'emailRegisterHint', locale: _localeName); String passwordRegisterHint() => - Intl.message('The password to secure your account', name: 'passwordRegisterHint', locale: _localeName); + Intl.message('The password to secure your account', + name: 'passwordRegisterHint', locale: _localeName); String retypePasswordHint() => - Intl.message('Re-type your password for validation', name: 'retypePasswordHint', locale: _localeName); - String retypePasswordTitle() => Intl.message('Re-type Password', name: 'retypePasswordTitle', locale: _localeName); - String registerButton() => Intl.message('REGISTER', name: 'registerButton', locale: _localeName); - String discardNewProduct() => Intl.message('Discard new product?', name: 'discardNewProduct', locale: _localeName); - String cancelButton() => Intl.message('CANCEL', name: 'cancelButton', locale: _localeName); - String acceptButton() => Intl.message('ACCEPT', name: 'acceptButton', locale: _localeName); - String discardButton() => Intl.message('DISCARD', name: 'discardButton', locale: _localeName); - String fixErrorsBeforeSubmittingPrompt() => Intl.message('Please fix the errors in red before submitting.', - name: 'fixErrorsBeforeSubmittingPrompt', locale: _localeName); - String newProductTitle() => Intl.message('New Product', name: 'newProductTitle', locale: _localeName); - String saveButton() => Intl.message('SAVE', name: 'saveButton', locale: _localeName); - String newProductName() => Intl.message('Product Name *', name: 'newProductName', locale: _localeName); - String newProductNameHint() => - Intl.message('How is this product called?', name: 'newProductNameHint', locale: _localeName); - String newProductBrandName() => Intl.message('Brand Name *', name: 'newProductBrandName', locale: _localeName); + Intl.message('Re-type your password for validation', + name: 'retypePasswordHint', locale: _localeName); + String retypePasswordTitle() => Intl.message('Re-type Password', + name: 'retypePasswordTitle', locale: _localeName); + String registerButton() => + Intl.message('REGISTER', name: 'registerButton', locale: _localeName); + String discardNewProduct() => Intl.message('Discard new product?', + name: 'discardNewProduct', locale: _localeName); + String cancelButton() => + Intl.message('CANCEL', name: 'cancelButton', locale: _localeName); + String acceptButton() => + Intl.message('ACCEPT', name: 'acceptButton', locale: _localeName); + String discardButton() => + Intl.message('DISCARD', name: 'discardButton', locale: _localeName); + String fixErrorsBeforeSubmittingPrompt() => + Intl.message('Please fix the errors in red before submitting.', + name: 'fixErrorsBeforeSubmittingPrompt', locale: _localeName); + String newProductTitle() => + Intl.message('New Product', name: 'newProductTitle', locale: _localeName); + String saveButton() => + Intl.message('SAVE', name: 'saveButton', locale: _localeName); + String newProductName() => Intl.message('Product Name *', + name: 'newProductName', locale: _localeName); + String newProductNameHint() => Intl.message('How is this product called?', + name: 'newProductNameHint', locale: _localeName); + String newProductBrandName() => Intl.message('Brand Name *', + name: 'newProductBrandName', locale: _localeName); String newProductBrandNameHint() => - Intl.message('Which company sells this product?', name: 'newProductBrandNameHint', locale: _localeName); - String newProductWeight() => Intl.message('Weight', name: 'newProductWeight', locale: _localeName); + Intl.message('Which company sells this product?', + name: 'newProductBrandNameHint', locale: _localeName); + String newProductWeight() => + Intl.message('Weight', name: 'newProductWeight', locale: _localeName); String newProductWeightHint() => - Intl.message('What is the normal packaging size?', name: 'newProductWeightHint', locale: _localeName); - String newProductAddToList() => Intl.message('Add to current list', name: 'newProductAddToList', locale: _localeName); - String newProductAddedToList() => Intl.message(' added to list ', name: 'newProductAddedToList', locale: _localeName); + Intl.message('What is the normal packaging size?', + name: 'newProductWeightHint', locale: _localeName); + String newProductAddToList() => Intl.message('Add to current list', + name: 'newProductAddToList', locale: _localeName); + String newProductAddedToList() => Intl.message(' added to list ', + name: 'newProductAddedToList', locale: _localeName); String newProductStarExplanation() => - Intl.message('* indicates required field', name: 'newProductStarExplanation', locale: _localeName); - String fieldRequiredError() => - Intl.message('This field is required!', name: 'fieldRequiredError', locale: _localeName); + Intl.message('* indicates required field', + name: 'newProductStarExplanation', locale: _localeName); + String fieldRequiredError() => Intl.message('This field is required!', + name: 'fieldRequiredError', locale: _localeName); String newProductNameToShort() => - Intl.message('This name seems to be to short', name: 'newProductNameToShort', locale: _localeName); - String addedProduct() => Intl.message(' added', name: 'addedProduct', locale: _localeName); - String productWasAlreadyInList() => Intl.message(' was already in list. The amount was increased by 1', - name: 'productWasAlreadyInList', locale: _localeName); - String searchProductHint() => Intl.message('Search Product', name: 'searchProductHint', locale: _localeName); - String noMoreProductsMessage() => - Intl.message('No more products found!', name: 'noMoreProductsMessage', locale: _localeName); - String codeText() => Intl.message('Code: ', name: 'codeText', locale: _localeName); - String removed() => Intl.message('removed', name: 'removed', locale: _localeName); - String changePrimaryColor() => Intl.message('Primary Color', name: 'changePrimaryColor', locale: _localeName); - String changeAccentColor() => Intl.message('Accent Color', name: 'changeAccentColor', locale: _localeName); - String changeDarkTheme() => Intl.message('Dark Theme', name: 'changeDarkTheme', locale: _localeName); - String changeAccentTextColor() => Intl.message('Dark Icons', name: 'changeAccentTextColor', locale: _localeName); - String autoSync() => Intl.message('Auto-Sync', name: 'autoSync', locale: _localeName); - String changePasswordButton() => Intl.message('CHANGE PASSWORD', name: 'changePasswordButton', locale: _localeName); - String oldPassword() => Intl.message('Current password', name: 'currentPassword', locale: _localeName); + Intl.message('This name seems to be to short', + name: 'newProductNameToShort', locale: _localeName); + String addedProduct() => + Intl.message(' added', name: 'addedProduct', locale: _localeName); + String productWasAlreadyInList() => + Intl.message(' was already in list. The amount was increased by 1', + name: 'productWasAlreadyInList', locale: _localeName); + String searchProductHint() => Intl.message('Search Product', + name: 'searchProductHint', locale: _localeName); + String noMoreProductsMessage() => Intl.message('No more products found!', + name: 'noMoreProductsMessage', locale: _localeName); + String codeText() => + Intl.message('Code: ', name: 'codeText', locale: _localeName); + String removed() => + Intl.message('removed', name: 'removed', locale: _localeName); + String changePrimaryColor() => Intl.message('Primary Color', + name: 'changePrimaryColor', locale: _localeName); + String changeAccentColor() => Intl.message('Accent Color', + name: 'changeAccentColor', locale: _localeName); + String changeDarkTheme() => + Intl.message('Dark Theme', name: 'changeDarkTheme', locale: _localeName); + String changeAccentTextColor() => Intl.message('Dark Icons', + name: 'changeAccentTextColor', locale: _localeName); + String autoSync() => + Intl.message('Auto-Sync', name: 'autoSync', locale: _localeName); + String changePasswordButton() => Intl.message('CHANGE PASSWORD', + name: 'changePasswordButton', locale: _localeName); + String oldPassword() => Intl.message('Current password', + name: 'currentPassword', locale: _localeName); String oldPasswordHint() => - Intl.message('Current password that should be changed', name: 'currentPasswordHint', locale: _localeName); - String newPassword() => Intl.message('New password', name: 'newPassword', locale: _localeName); - String newPasswordHint() => - Intl.message('The new password you have chosen', name: 'newPasswordHint', locale: _localeName); - String new2Password() => Intl.message('Repeat new password', name: 'repeatNewPassword', locale: _localeName); + Intl.message('Current password that should be changed', + name: 'currentPasswordHint', locale: _localeName); + String newPassword() => + Intl.message('New password', name: 'newPassword', locale: _localeName); + String newPasswordHint() => Intl.message('The new password you have chosen', + name: 'newPasswordHint', locale: _localeName); + String new2Password() => Intl.message('Repeat new password', + name: 'repeatNewPassword', locale: _localeName); String new2PasswordHint() => - Intl.message('repeat the new password you have chosen', name: 'repeatNewPasswordHint', locale: _localeName); - String changePasswordPD() => Intl.message('Change Password', name: 'changePasswordPD', locale: _localeName); - String successful() => Intl.message('Successful', name: 'successful', locale: _localeName); - String passwordSet() => Intl.message('Your password has been set', name: 'passwordSet', locale: _localeName); - String tokenExpired() => Intl.message('Token expired', name: 'tokenExpired', locale: _localeName); + Intl.message('repeat the new password you have chosen', + name: 'repeatNewPasswordHint', locale: _localeName); + String changePasswordPD() => Intl.message('Change Password', + name: 'changePasswordPD', locale: _localeName); + String successful() => + Intl.message('Successful', name: 'successful', locale: _localeName); + String passwordSet() => Intl.message('Your password has been set', + name: 'passwordSet', locale: _localeName); + String tokenExpired() => + Intl.message('Token expired', name: 'tokenExpired', locale: _localeName); String tokenExpiredExplanation() => Intl.message( 'Your token has expired. Login is required. If this happends multiple times per month, please contact us.', name: 'tokenExpiredExplanation', locale: _localeName); - String noListLoaded() => Intl.message('No List Loaded', name: 'noListLoaded', locale: _localeName); - String renameListItem() => Intl.message('Rename Product', name: 'renameListItem', locale: _localeName); - String renameListItemHint() => - Intl.message('The new name of the product', name: 'renameListItemHint', locale: _localeName); - String renameListItemLabel() => Intl.message('new product name', name: 'renameListItemLabel', locale: _localeName); - String discardNewTheme() => Intl.message('Discard new theme?', name: 'discardNewTheme', locale: _localeName); - String forgotPassword() => Intl.message('Forgot password?', name: 'forgotPassword', locale: _localeName); - String bePatient() => Intl.message('Please be patient, the server is processing your request already', - name: 'bePatient', locale: _localeName); - String logout() => Intl.message('Logout', name: 'logout', locale: _localeName); - String deleteListTitle() => Intl.message('Delete List', name: 'deleteListTitle', locale: _localeName); - String deleteListText() => Intl.message('Do you really want to delete the list? This CAN\'T be undone!', - name: 'deleteListText', locale: _localeName); - String exportAsPdf() => Intl.message('Export as PDF', name: 'exportAsPdf', locale: _localeName); - String boughtProducts() => Intl.message('Bought Products', name: 'boughtProducts', locale: _localeName); - String nothingBoughtYet() => Intl.message('Nothing bought yet', name: 'nothingBoughtYet', locale: _localeName); - String reorderItems() => Intl.message('Reorder', name: 'reorderItems', locale: _localeName); + String noListLoaded() => + Intl.message('No List Loaded', name: 'noListLoaded', locale: _localeName); + String renameListItem() => Intl.message('Rename Product', + name: 'renameListItem', locale: _localeName); + String renameListItemHint() => Intl.message('The new name of the product', + name: 'renameListItemHint', locale: _localeName); + String renameListItemLabel() => Intl.message('new product name', + name: 'renameListItemLabel', locale: _localeName); + String discardNewTheme() => Intl.message('Discard new theme?', + name: 'discardNewTheme', locale: _localeName); + String forgotPassword() => Intl.message('Forgot password?', + name: 'forgotPassword', locale: _localeName); + String bePatient() => Intl.message( + 'Please be patient, the server is processing your request already', + name: 'bePatient', + locale: _localeName); + String logout() => + Intl.message('Logout', name: 'logout', locale: _localeName); + String deleteListTitle() => + Intl.message('Delete List', name: 'deleteListTitle', locale: _localeName); + String deleteListText() => Intl.message( + 'Do you really want to delete the list? This CAN\'T be undone!', + name: 'deleteListText', + locale: _localeName); + String exportAsPdf() => + Intl.message('Export as PDF', name: 'exportAsPdf', locale: _localeName); + String boughtProducts() => Intl.message('Bought Products', + name: 'boughtProducts', locale: _localeName); + String nothingBoughtYet() => Intl.message('Nothing bought yet', + name: 'nothingBoughtYet', locale: _localeName); + String reorderItems() => + Intl.message('Reorder', name: 'reorderItems', locale: _localeName); - String refresh() => Intl.message('Refresh', name: "refresh", locale: _localeName); - String settings() => Intl.message('Settings', name: "settings", locale: _localeName); + String refresh() => + Intl.message('Refresh', name: "refresh", locale: _localeName); + String settings() => + Intl.message('Settings', name: "settings", locale: _localeName); String about() => Intl.message('About', name: "about", locale: _localeName); - String codeOnGithub() => Intl.message('View Source Code on GitHub', name: "codeOnGithub", locale: _localeName); - String playstoreEntry() => Intl.message('Entry on Play Store', name: "playstoreEntry", locale: _localeName); - String iconSource() => Intl.message('Source of the App Icon', name: "iconSource", locale: _localeName); + String codeOnGithub() => Intl.message('View Source Code on GitHub', + name: "codeOnGithub", locale: _localeName); + String playstoreEntry() => Intl.message('Entry on Play Store', + name: "playstoreEntry", locale: _localeName); + String iconSource() => Intl.message('Source of the App Icon', + name: "iconSource", locale: _localeName); String scanditCredit() => - Intl.message('has provided the Scanner for this App', name: "scanditCredit", locale: _localeName); + Intl.message('has provided the Scanner for this App', + name: "scanditCredit", locale: _localeName); String aboutText() => Intl.message( 'Forged over many years with the only intention to make it easier for multiple people to plan their shopping and add their favorite products via camera in an unmatched speed.', name: "aboutText", locale: _localeName); String freeText() => - Intl.message('Free of charge, no Advertisments, forever!', name: "freeText", locale: _localeName); - String questionsErrors() => Intl.message('Questions, Errors or everything else can be send by a GitHub issue.', - name: "questionsErrors", locale: _localeName); - String okayButton() => Intl.message('OKAY', name: "okayButton", locale: _localeName); - String requestPasswordResetButton() => - Intl.message('REQUEST PASSWORD RESET', name: 'requestPasswordResetButton', locale: _localeName); - String requestPasswordResetTitle() => - Intl.message('Password Reset', name: "requestPasswordResetTitle", locale: _localeName); + Intl.message('Free of charge, no Advertisments, forever!', + name: "freeText", locale: _localeName); + String questionsErrors() => Intl.message( + 'Questions, Errors or everything else can be send by a GitHub issue.', + name: "questionsErrors", + locale: _localeName); + String okayButton() => + Intl.message('OKAY', name: "okayButton", locale: _localeName); + String requestPasswordResetButton() => Intl.message('REQUEST PASSWORD RESET', + name: 'requestPasswordResetButton', locale: _localeName); + String requestPasswordResetTitle() => Intl.message('Password Reset', + name: "requestPasswordResetTitle", locale: _localeName); String requestPasswordResetSuccess() => Intl.message( 'If the email exists, the password request was successfully requested. Further instructions can be found in the email, that was send to the address.', name: "requestPasswordResetSuccess", locale: _localeName); + String useMaterial3() => + Intl.message('Use Material Design 3 (Colors based on Android Version)', + name: 'useMaterial3', locale: _localeName); + String elevateAppBar() => Intl.message('Colorize Title Background', + name: 'elevateAppBar', locale: _localeName); //String openAppDrawerTooltip() => Intl.message('Open navigation menu', name: 'openNavigationMenu', locale: _localeName); } diff --git a/lib/main.dart b/lib/main.dart index 2d0492f..481e128 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,8 @@ import 'dart:convert'; -import 'dart:io'; import 'dart:ui'; import 'package:adaptive_theme/adaptive_theme.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:nssl/options/themes.dart'; import 'package:nssl/pages/forgot_password.dart'; @@ -17,56 +15,81 @@ import 'package:nssl/localization/nssl_strings.dart'; import 'package:nssl/firebase/cloud_messsaging.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_riverpod/legacy.dart'; // import 'package:shared_preferences/shared_preferences.dart'; class CustomScrollBehavior extends MaterialScrollBehavior { @override Set get dragDevices => { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - PointerDeviceKind.stylus, - }; + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + PointerDeviceKind.stylus, + }; } @pragma('vm:entry-point') Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { await Startup.initializeMinFunction(); - var dir = await Startup.fs.systemTempDirectory.childDirectory("message").create(); + var dir = await Startup.fs.systemTempDirectory + .childDirectory("message") + .create(); var file = dir.childFile(DateTime.now().microsecondsSinceEpoch.toString()); await file.writeAsString(jsonEncode(message.data)); } -final appRestartProvider = StateProvider( - (ref) => 0, -); +final appRestartProvider = StateProvider((ref) => 0); Future main() async { -// iWonderHowLongThisTakes(); - runApp(ProviderScope(child: Consumer( - builder: (context, ref, child) { - return FutureBuilder( - builder: (c, t) { - if (t.connectionState == ConnectionState.done) { - ref.watch(appRestartProvider); - return NSSLPage(); - } else - return MaterialApp( - builder: (context, child) { - return Center( - child: SizedBox( - height: 200, - width: 200, - child: SvgPicture.asset("assets/vectors/app_icon.svg"), - ), - ); + // iWonderHowLongThisTakes(); + runApp( + ProviderScope( + child: Consumer( + builder: (context, ref, child) { + return EagerInitialize( + FutureBuilder( + builder: (c, t) { + if (t.connectionState == ConnectionState.done) { + ref.watch(appRestartProvider); + return NSSLPage(); + } else + return MaterialApp( + builder: (context, child) { + return Center( + child: SizedBox( + height: 200, + width: 200, + child: SvgPicture.asset( + "assets/vectors/app_icon.svg", + ), + ), + ); + }, + ); }, - ); + future: Startup.initialize(ref).then( + (value) => FirebaseMessaging.onBackgroundMessage( + _firebaseMessagingBackgroundHandler, + ), + ), + ), + ); }, - future: Startup.initialize(ref) - .then((value) => FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler)), - ); - }, - ))); + ), + ), + ); +} + +class EagerInitialize extends ConsumerWidget { + final Widget child; + + const EagerInitialize(this.child); + @override + Widget build(BuildContext context, WidgetRef ref) { + ref.watch(themeProvider); + ref.watch(cloudMessagingProvider); + + return child; + } } class NSSL extends StatelessWidget { @@ -94,14 +117,13 @@ class _NSSLState extends ConsumerState { @override void initState() { super.initState(); - ref.read(cloudMessagingProvider); //Neded for ref on onMessage subscribeFirebase(context); FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { - CloudMessaging.onMessage(message); + ref.read(cloudMessagingProvider.notifier).onMessage(message); }); FirebaseMessaging.onMessage.listen((event) { - CloudMessaging.onMessage(event); + ref.read(cloudMessagingProvider.notifier).onMessage(event); }); for (var list in ref.read(shoppingListsProvider).shoppingLists) @@ -110,11 +132,10 @@ class _NSSLState extends ConsumerState { Future subscribeFirebase(BuildContext context) async { if (!Startup.firebaseSupported()) return; - var initMessage = await FirebaseMessaging.instance.getInitialMessage(); if (initMessage != null) { - CloudMessaging.onMessage(initMessage); + ref.read(cloudMessagingProvider.notifier).onMessage(initMessage); } } @@ -156,14 +177,16 @@ class _NSSLState extends ConsumerState { } Scaffold mainAppHome() => Scaffold( - key: _mainScaffoldKey, resizeToAvoidBottomInset: false, body: MainPage() //CustomThemePage()//LoginPage(), - ); + key: _mainScaffoldKey, + resizeToAvoidBottomInset: false, + body: MainPage(), //CustomThemePage()//LoginPage(), + ); Scaffold mainAppLoginRegister() => Scaffold( - key: _mainScaffoldKey, - resizeToAvoidBottomInset: false, - body: LoginPage(), - ); + key: _mainScaffoldKey, + resizeToAvoidBottomInset: false, + body: LoginPage(), + ); } class _NSSLLocalizationsDelegate extends LocalizationsDelegate { diff --git a/lib/manager/database_manager.dart b/lib/manager/database_manager.dart index 671fedc..a1cf8bd 100644 --- a/lib/manager/database_manager.dart +++ b/lib/manager/database_manager.dart @@ -105,6 +105,38 @@ class FakeDatabase extends Database { {String? where, List? whereArgs, ConflictAlgorithm? conflictAlgorithm}) { return Future.value(0); } + + @override + Future queryCursor(String table, + {bool? distinct, + List? columns, + String? where, + List? whereArgs, + String? groupBy, + String? having, + String? orderBy, + int? limit, + int? offset, + int? bufferSize}) { + // TODO: implement queryCursor + throw UnimplementedError(); + } + + @override + Future rawQueryCursor(String sql, List? arguments, {int? bufferSize}) { + // TODO: implement rawQueryCursor + throw UnimplementedError(); + } + + @override + // TODO: implement database + Database get database => throw UnimplementedError(); + + @override + Future readTransaction(Future Function(Transaction txn) action) { + // TODO: implement readTransaction + throw UnimplementedError(); + } } class DatabaseManager { diff --git a/lib/manager/startup_manager.dart b/lib/manager/startup_manager.dart index 9d0ea08..74ffde4 100644 --- a/lib/manager/startup_manager.dart +++ b/lib/manager/startup_manager.dart @@ -20,20 +20,28 @@ class Startup { static List remoteMessages = []; static const LocalFileSystem fs = const LocalFileSystem(); - static bool firebaseSupported() => kIsWeb || Platform.isAndroid || Platform.isIOS || Platform.isMacOS; + static bool firebaseSupported() => + kIsWeb || Platform.isAndroid || Platform.isIOS || Platform.isMacOS; static Future initializeMinFunction() async { if (!firebaseSupported()) return true; var initTask = Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); if (!kIsWeb && !Platform.isMacOS) - return initTask.then((value) async => await ScanditFlutterDataCaptureBarcode.initialize()).then((value) => true); + return initTask + .then( + (value) async => + await ScanditFlutterDataCaptureBarcode.initialize(), + ) + .then((value) => true); return initTask.then((value) => true); } static Future loadMessagesFromFolder(WidgetRef ref) async { - var dir = await Startup.fs.systemTempDirectory.childDirectory("message").create(); + var dir = await Startup.fs.systemTempDirectory + .childDirectory("message") + .create(); var subFiles = dir.listSync(); if (subFiles.length == 0) return; subFiles.sort((a, b) => a.basename.compareTo(b.basename)); @@ -41,24 +49,25 @@ class Startup { .where((event) => Startup.fs.isFileSync(event.path)) .map((event) => Startup.fs.file(event.path)) .forEach((subFile) { - var str = subFile.readAsStringSync(); - var remoteMessage = RemoteMessage(data: jsonDecode(str)); - ref.read(cloudMessagingProvider); - CloudMessaging.onMessage(remoteMessage); - subFile.delete(); - }); + var str = subFile.readAsStringSync(); + var remoteMessage = RemoteMessage(data: jsonDecode(str)); + ref.read(cloudMessagingProvider.notifier).onMessage(remoteMessage); + subFile.delete(); + }); } static Future deleteMessagesFromFolder() async { - var dir = await Startup.fs.systemTempDirectory.childDirectory("message").create(); + var dir = await Startup.fs.systemTempDirectory + .childDirectory("message") + .create(); var subFiles = dir.listSync(); if (subFiles.length == 0) return; subFiles .where((event) => Startup.fs.isFileSync(event.path)) .map((event) => Startup.fs.file(event.path)) .forEach((subFile) { - subFile.delete(); - }); + subFile.delete(); + }); } static Future initialize(WidgetRef ref) async { @@ -68,7 +77,6 @@ class Startup { var user = await ref.read(userFromDbProvider.future); if (user == null || user.username == "" || user.eMail == "") return false; - ref.read(themeProvider); await Themes.loadTheme(); var provider = ref.read(shoppingListsProvider); diff --git a/lib/models/shopping_item.dart b/lib/models/shopping_item.dart index 612b194..e150c1b 100644 --- a/lib/models/shopping_item.dart +++ b/lib/models/shopping_item.dart @@ -1,6 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:nssl/helper/iterable_extensions.dart'; +import 'package:flutter_riverpod/legacy.dart'; class TestClass { int test; @@ -13,7 +14,10 @@ class TestClass { final shoppingItemsProvider = StateProvider>(((ref) => [])); -final shoppingItemsPerListProvider = Provider.family, int>((ref, listId) { +final shoppingItemsPerListProvider = Provider.family, int>(( + ref, + listId, +) { var items = ref.watch(shoppingItemsProvider); return items.where((element) => element.listId == listId).toList(); }); @@ -35,6 +39,7 @@ class ShoppingItem { final int listId; int get sortWithOffset => sortOrder + (crossedOut ? 0xFFFFFFFF : 0); + String get cleanedName => name.replaceFirst('0.0', '').replaceAll('null', ''); const ShoppingItem( this.name, @@ -60,25 +65,38 @@ class ShoppingItem { /// Creates an identical clone, where all fields are the same as /// the parent item ShoppingItem clone() { - return ShoppingItem(name, listId, sortOrder, - amount: amount, id: id, changed: changed, created: created, crossedOut: crossedOut); + return ShoppingItem( + name, + listId, + sortOrder, + amount: amount, + id: id, + changed: changed, + created: created, + crossedOut: crossedOut, + ); } - ShoppingItem cloneWith( - {String? newName, - int? newListId, - int? newAmount, - int? newId, - DateTime? newCreated, - DateTime? newChanged, - bool? newCrossedOut, - int? newSortOrder}) { - return ShoppingItem(newName ?? name, newListId ?? listId, newSortOrder ?? sortOrder, - amount: newAmount ?? amount, - id: newId ?? id, - changed: newChanged ?? changed, - created: newCreated ?? created, - crossedOut: newCrossedOut ?? crossedOut); + ShoppingItem cloneWith({ + String? newName, + int? newListId, + int? newAmount, + int? newId, + DateTime? newCreated, + DateTime? newChanged, + bool? newCrossedOut, + int? newSortOrder, + }) { + return ShoppingItem( + newName ?? name, + newListId ?? listId, + newSortOrder ?? sortOrder, + amount: newAmount ?? amount, + id: newId ?? id, + changed: newChanged ?? changed, + created: newCreated ?? created, + crossedOut: newCrossedOut ?? crossedOut, + ); } // ShoppingItem.fromJson(String s) : name = s; @@ -96,7 +114,8 @@ class ShoppingItem { other.listId == listId; @override - int get hashCode => Object.hash(name, amount, id, crossedOut, sortOrder, listId); + int get hashCode => + Object.hash(name, amount, id, crossedOut, sortOrder, listId); void exchange(ShoppingItem newItem, WidgetRef ref) { var items = ref.watch(shoppingItemsProvider.notifier); diff --git a/lib/models/shopping_list.dart b/lib/models/shopping_list.dart index fc00296..c11041f 100644 --- a/lib/models/shopping_list.dart +++ b/lib/models/shopping_list.dart @@ -8,8 +8,10 @@ import 'dart:async'; import 'package:nssl/server_communication/return_classes.dart'; import 'package:nssl/server_communication/shopping_list_sync.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_riverpod/legacy.dart'; -final shoppingListsProvider = ChangeNotifierProvider((ref) { +final shoppingListsProvider = + ChangeNotifierProvider((ref) { var userId = ref.watch(userIdProvider); if (userId == null) return ShoppingListController(ref, -1); @@ -28,16 +30,17 @@ final listProvider = Provider.family((ref, indx) { final currentListProvider = Provider((ref) { var index = ref.watch(currentListIndexProvider); if (index == null) return null; - return ref.watch(listProvider.create(index)); + return ref.watch(listProvider(index)); }); final currentShoppingItemsProvider = Provider>((ref) { var list = ref.watch(currentListProvider); if (list == null || list.id < 0) return []; - return ref.watch(shoppingItemsPerListProvider.create(list.id)); + return ref.watch(shoppingItemsPerListProvider(list.id)); }); -final shoppingListByIndexProvider = Provider.family((ref, indx) { +final shoppingListByIndexProvider = + Provider.family((ref, indx) { var shoppingListController = ref.watch(shoppingListsProvider); if (indx > shoppingListController.shoppingLists.length) return null; @@ -47,7 +50,8 @@ final shoppingListByIndexProvider = Provider.family((ref, in final shoppingListByIdProvider = Provider.family((ref, id) { var shoppingListController = ref.watch(shoppingListsProvider); - return shoppingListController.shoppingLists.firstOrNull((element) => element.id == id); + return shoppingListController.shoppingLists + .firstOrNull((element) => element.id == id); }); class ShoppingListController with ChangeNotifier { @@ -62,20 +66,30 @@ class ShoppingListController with ChangeNotifier { Future save(ShoppingList list) async { await DatabaseManager.database.transaction((z) async { - await z.execute('INSERT OR REPLACE INTO ShoppingLists(id, name, messaging, user_id) VALUES(?, ?, ?, ?)', + await z.execute( + 'INSERT OR REPLACE INTO ShoppingLists(id, name, messaging, user_id) VALUES(?, ?, ?, ?)', [list.id, list.name, list.messagingEnabled ? 1 : 0, _userId]); - var shoppingItems = _ref.read(shoppingItemsPerListProvider.create(list.id)); - await z.rawDelete("DELETE FROM ShoppingItems WHERE res_list_id = ? and id not in (?)", + var shoppingItems = _ref.read(shoppingItemsPerListProvider(list.id)); + await z.rawDelete( + "DELETE FROM ShoppingItems WHERE res_list_id = ? and id not in (?)", [list.id, shoppingItems.map((e) => e.id).join(",")]); for (var item in shoppingItems) { await z.execute( "INSERT OR REPLACE INTO ShoppingItems(id, name, amount, crossed, res_list_id, sortorder) VALUES (?, ?, ?, ?, ?, ?)", - [item.id, item.name, item.amount, item.crossedOut ? 1 : 0, list.id, item.sortOrder]); + [ + item.id, + item.name, + item.amount, + item.crossedOut ? 1 : 0, + list.id, + item.sortOrder + ]); } }); } - Future addSingleItem(ShoppingList list, ShoppingItem item, {int index = -1}) async { + Future addSingleItem(ShoppingList list, ShoppingItem item, + {int index = -1}) async { // var shoppingItems = _ref.read(shoppingItemsPerListProvider.create(list.id)); // if (index < 0) index = shoppingItems.length; // shoppingItems.insert(index, item); @@ -89,7 +103,14 @@ class ShoppingListController with ChangeNotifier { await DatabaseManager.database.execute( "INSERT OR REPLACE INTO ShoppingItems(id, name, amount, crossed, res_list_id, sortorder) VALUES (?, ?, ?, ?, ?, ?)", - [item.id, item.name, item.amount, item.crossedOut ? 1 : 0, list.id, item.sortOrder]); + [ + item.id, + item.name, + item.amount, + item.crossedOut ? 1 : 0, + list.id, + item.sortOrder + ]); save(list); notifyListeners(); } @@ -102,7 +123,8 @@ class ShoppingListController with ChangeNotifier { // var newList = ShoppingList(list.id, list.name, list.shoppingItems.where((element) => element != item).toList(), // messagingEnabled: list.messagingEnabled); // _exchangeLists(list, newList); - await DatabaseManager.database.rawDelete("DELETE FROM ShoppingItems WHERE id = ?", [itemId]); + await DatabaseManager.database + .rawDelete("DELETE FROM ShoppingItems WHERE id = ?", [itemId]); save(list); } @@ -114,14 +136,17 @@ class ShoppingListController with ChangeNotifier { // var newList = ShoppingList(list.id, list.name, list.shoppingItems.where((element) => element != item).toList(), // messagingEnabled: list.messagingEnabled); // _exchangeLists(list, newList); - await DatabaseManager.database.rawDelete("DELETE FROM ShoppingItems WHERE id = ?", [item.id]); + await DatabaseManager.database + .rawDelete("DELETE FROM ShoppingItems WHERE id = ?", [item.id]); save(list); } Future> load() async { - var lists = await DatabaseManager.database.rawQuery("SELECT * FROM ShoppingLists WHERE user_id = ?", [_userId]); + var lists = await DatabaseManager.database + .rawQuery("SELECT * FROM ShoppingLists WHERE user_id = ?", [_userId]); - var items = await DatabaseManager.database.rawQuery("SELECT * FROM ShoppingItems ORDER BY res_list_id, sortorder"); + var items = await DatabaseManager.database.rawQuery( + "SELECT * FROM ShoppingItems ORDER BY res_list_id, sortorder"); int curSortOrder = 0; var newShoppingItems = items.map( @@ -143,8 +168,8 @@ class ShoppingListController with ChangeNotifier { ).toList(); shoppingLists = lists - .map((x) => - ShoppingList(x["id"] as int, x["name"] as String, messagingEnabled: x["messaging"] == 0 ? false : true)) + .map((x) => ShoppingList(x["id"] as int, x["name"] as String, + messagingEnabled: x["messaging"] == 0 ? false : true)) .toList(); var sip = _ref.watch(shoppingItemsProvider.notifier); @@ -159,8 +184,9 @@ class ShoppingListController with ChangeNotifier { var newListResult = GetListResult.fromJson(res.body); List> items; - items = (await DatabaseManager.database - .rawQuery("SELECT id, crossed, sortorder FROM ShoppingItems WHERE res_list_id = ?", [list.id])); + items = (await DatabaseManager.database.rawQuery( + "SELECT id, crossed, sortorder FROM ShoppingItems WHERE res_list_id = ?", + [list.id])); var shoppingItems = []; var sip = _ref.watch(shoppingItemsProvider.notifier); @@ -176,13 +202,17 @@ class ShoppingListController with ChangeNotifier { amount: item.amount, changed: item.changed, created: item.created, - crossedOut: - (items.firstWhere((x) => x["id"] == item.id, orElse: () => {"crossed": 0})["crossed"] == 0 ? false : true), + crossedOut: (items.firstWhere((x) => x["id"] == item.id, + orElse: () => {"crossed": 0})["crossed"] == + 0 + ? false + : true), )); shoppingItems.sort((a, b) => a.sortWithOffset.compareTo(b.sortWithOffset)); newState.addAll(shoppingItems); - var newList = ShoppingList(list.id, list.name, messagingEnabled: list.messagingEnabled); + var newList = ShoppingList(list.id, list.name, + messagingEnabled: list.messagingEnabled); _exchangeLists(list, newList); sip.state = newState; save(newList); @@ -205,11 +235,12 @@ class ShoppingListController with ChangeNotifier { var result = GetListsResult.fromJson(res.body); shoppingLists.clear(); - await DatabaseManager.database.delete("ShoppingLists", where: "user_id = ?", whereArgs: [_userId]); + await DatabaseManager.database + .delete("ShoppingLists", where: "user_id = ?", whereArgs: [_userId]); List> items; - items = (await DatabaseManager.database - .rawQuery("SELECT id, crossed, sortorder FROM ShoppingItems where crossed = 1 or sortorder > 0")); + items = (await DatabaseManager.database.rawQuery( + "SELECT id, crossed, sortorder FROM ShoppingItems where crossed = 1 or sortorder > 0")); var shoppintItemsState = _ref.watch(shoppingItemsProvider.notifier); var shoppingItems = []; @@ -230,7 +261,9 @@ class ShoppingListController with ChangeNotifier { amount: item.amount, changed: item.changed, created: item.created, - crossedOut: (items.firstWhere((x) => x["id"] == item.id, orElse: () => {"crossed": 0})["crossed"] == 0 + crossedOut: (items.firstWhere((x) => x["id"] == item.id, + orElse: () => {"crossed": 0})["crossed"] == + 0 ? false : true), )); @@ -270,7 +303,8 @@ class ShoppingListController with ChangeNotifier { void removeList(int listId) { shoppingLists.removeWhere((x) => x.id == listId); - firebaseMessaging?.unsubscribeFromTopic(listId.toString() + "shoppingListTopic"); + firebaseMessaging + ?.unsubscribeFromTopic(listId.toString() + "shoppingListTopic"); notifyListeners(); } @@ -281,8 +315,11 @@ class ShoppingListController with ChangeNotifier { void toggleFirebaseMessaging(int listId) { var list = shoppingLists.firstWhere((element) => element.id == listId); - var newList = ShoppingList(listId, list.name, messagingEnabled: !list.messagingEnabled); - newList.messagingEnabled ? list.subscribeForFirebaseMessaging() : list.unsubscribeFromFirebaseMessaging(); + var newList = ShoppingList(listId, list.name, + messagingEnabled: !list.messagingEnabled); + newList.messagingEnabled + ? list.subscribeForFirebaseMessaging() + : list.unsubscribeFromFirebaseMessaging(); _exchangeLists(list, newList); save(newList); } @@ -290,7 +327,8 @@ class ShoppingListController with ChangeNotifier { void rename(int id, String name) { var list = shoppingLists.firstWhere((element) => element.id == id); - var newList = ShoppingList(id, name, messagingEnabled: list.messagingEnabled); + var newList = + ShoppingList(id, name, messagingEnabled: list.messagingEnabled); _exchangeLists(list, newList); saveAndNotify(list); } @@ -305,9 +343,11 @@ class ShoppingList { // final List shoppingItems; final bool messagingEnabled; - const ShoppingList(this.id, this.name, /*this.shoppingItems,*/ {this.messagingEnabled = true}); + const ShoppingList(this.id, this.name, + /*this.shoppingItems,*/ {this.messagingEnabled = true}); - const ShoppingList.messaging(this.id, this.name, /*this.shoppingItems,*/ this.messagingEnabled); + const ShoppingList.messaging( + this.id, this.name, /*this.shoppingItems,*/ this.messagingEnabled); void subscribeForFirebaseMessaging() { if (kIsWeb) return; @@ -316,6 +356,7 @@ class ShoppingList { void unsubscribeFromFirebaseMessaging() { if (kIsWeb) return; - firebaseMessaging?.unsubscribeFromTopic(id.toString() + "shoppingListTopic"); + firebaseMessaging + ?.unsubscribeFromTopic(id.toString() + "shoppingListTopic"); } } diff --git a/lib/models/user.dart b/lib/models/user.dart index b6ecabf..c9ec8c2 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -4,10 +4,12 @@ import 'package:nssl/main.dart'; import 'package:nssl/manager/database_manager.dart'; import 'package:nssl/server_communication/jwt.dart'; import 'package:riverpod/riverpod.dart'; +import 'package:flutter_riverpod/legacy.dart'; final userFromDbProvider = FutureProvider((ref) async { ref.watch(appRestartProvider); - var list = (await DatabaseManager.database.rawQuery("SELECT * FROM User LIMIT 1")); + var list = + (await DatabaseManager.database.rawQuery("SELECT * FROM User LIMIT 1")); if (list.length == 0) return null; var z = list.first; var username = z["username"] as String; @@ -37,8 +39,11 @@ final userStateProvider = StateProvider((ref) { final userProvider = Provider((ref) { var fromDb = ref.watch(userFromDbProvider); var fromState = ref.watch(userStateProvider); - if (fromState.ownId == -1 && !fromDb.hasError && !fromDb.isLoading && fromDb.hasValue) { - return fromDb.valueOrNull ?? fromState; + if (fromState.ownId == -1 && + !fromDb.hasError && + !fromDb.isLoading && + fromDb.hasValue) { + return fromDb.value ?? fromState; } return fromState; }); @@ -63,7 +68,10 @@ class User { @override bool operator ==(final Object other) => - other is User && other.username == username && other.eMail == eMail && other.ownId == ownId; + other is User && + other.username == username && + other.eMail == eMail && + other.ownId == ownId; @override int get hashCode => Object.hash(username, eMail, ownId); @@ -96,9 +104,12 @@ class User { } Future delete() async { - await DatabaseManager.database.rawDelete("DELETE FROM User where own_id = ?", [ownId]); + await DatabaseManager.database + .rawDelete("DELETE FROM User where own_id = ?", [ownId]); await DatabaseManager.database.rawDelete( - "DELETE FROM ShoppingItems where res_list_id in( SELECT id FROM ShoppingLists where user_id = ?)", [ownId]); - await DatabaseManager.database.rawDelete("DELETE FROM ShoppingLists where user_id = ?", [ownId]); + "DELETE FROM ShoppingItems where res_list_id in( SELECT id FROM ShoppingLists where user_id = ?)", + [ownId]); + await DatabaseManager.database + .rawDelete("DELETE FROM ShoppingLists where user_id = ?", [ownId]); } } diff --git a/lib/options/themes.dart b/lib/options/themes.dart index 9d34913..52ebbeb 100644 --- a/lib/options/themes.dart +++ b/lib/options/themes.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/legacy.dart'; import 'package:nssl/manager/database_manager.dart'; import 'package:nssl/models/user.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -16,46 +17,54 @@ class Themes with ChangeNotifier { } static NSSLThemeData lightTheme = NSSLThemeData( - ThemeData( - primarySwatch: Colors.blue, - brightness: Brightness.light, - secondaryHeaderColor: Colors.teal, - floatingActionButtonTheme: FloatingActionButtonThemeData(backgroundColor: Colors.teal.shade400), - checkboxTheme: CheckboxThemeData( - fillColor: MaterialStateColor.resolveWith( - (s) { - if (s.contains(MaterialState.selected)) { - return Colors.teal.shade200; - } - return Colors.black; - }, - ), - ), + ThemeData( + useMaterial3: false, + primarySwatch: Colors.blue, + brightness: Brightness.light, + secondaryHeaderColor: Colors.teal, + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: Colors.teal.shade400, ), - 0, - 0); + checkboxTheme: CheckboxThemeData( + fillColor: MaterialStateColor.resolveWith((s) { + if (s.contains(MaterialState.selected)) { + return Colors.teal.shade200; + } + return Colors.black; + }), + ), + ), + 0, + 0, + ); static NSSLThemeData darkTheme = NSSLThemeData( - ThemeData( - primarySwatch: Colors.blue, - brightness: Brightness.dark, - secondaryHeaderColor: Colors.teal, - floatingActionButtonTheme: FloatingActionButtonThemeData(backgroundColor: Colors.teal.shade100), - checkboxTheme: CheckboxThemeData( - fillColor: MaterialStateColor.resolveWith( - (s) { - if (s.contains(MaterialState.selected)) { - return Colors.teal.shade600; - } - return Colors.white; - }, - ), - ), + ThemeData( + useMaterial3: false, + primarySwatch: Colors.blue, + brightness: Brightness.dark, + secondaryHeaderColor: Colors.teal, + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: Colors.teal.shade100, + ), + checkboxTheme: CheckboxThemeData( + fillColor: MaterialStateColor.resolveWith((s) { + if (s.contains(MaterialState.selected)) { + return Colors.teal.shade600; + } + return Colors.white; + }), ), - 0, - 0); + ), + 0, + 0, + ); static ThemeMode tm = ThemeMode.system; - static Future saveTheme(ThemeData t, MaterialColor primary, MaterialAccentColor accent) async { + static Future saveTheme( + ThemeData t, + MaterialColor primary, + MaterialAccentColor accent, + ) async { // await DatabaseManager.database.rawDelete("DELETE FROM Themes"); var userId = _ref.watch(userIdProvider); if (userId == null) return; @@ -63,46 +72,64 @@ class Themes with ChangeNotifier { (await SharedPreferences.getInstance()).setInt("lastTheme", id); tm = t.brightness == Brightness.dark ? ThemeMode.dark : ThemeMode.light; await DatabaseManager.database.rawInsert( - "INSERT OR REPLACE INTO Themes(id, primary_color, accent_color, brightness, accent_color_brightness, user_id) VALUES(?, ?, ?, ?, ?, ?)", - [id, Colors.primaries.indexOf(primary), Colors.accents.indexOf(accent), t.brightness.toString(), "", userId]); + "INSERT OR REPLACE INTO Themes(id, primary_color, accent_color, brightness, accent_color_brightness, user_id) VALUES(?, ?, ?, ?, ?, ?)", + [ + id, + Colors.primaries.indexOf(primary), + Colors.accents.indexOf(accent), + t.brightness.toString(), + "", + userId, + ], + ); } static Future loadTheme() async { late var t; - var lastId = (await SharedPreferences.getInstance()).getInt("lastTheme") ?? 0; + var lastId = + (await SharedPreferences.getInstance()).getInt("lastTheme") ?? 0; var userId = _ref.watch(userIdProvider); try { if (userId != null) - t = (await DatabaseManager.database.rawQuery("SELECT * FROM Themes where user_id = ?", [userId])); + t = (await DatabaseManager.database.rawQuery( + "SELECT * FROM Themes where user_id = ?", + [userId], + )); } catch (e) { - var temp = (await DatabaseManager.database.rawQuery("SELECT * FROM Themes")).first; + var temp = (await DatabaseManager.database.rawQuery( + "SELECT * FROM Themes", + )).first; await DatabaseManager.database.execute("DROP TABLE Themes"); await DatabaseManager.database.execute( - "CREATE TABLE Themes (id INTEGER PRIMARY KEY, primary_color INTEGER, accent_color INTEGER, brightness TEXT, accent_color_brightness TEXT, user_id INTEGER)"); + "CREATE TABLE Themes (id INTEGER PRIMARY KEY, primary_color INTEGER, accent_color INTEGER, brightness TEXT, accent_color_brightness TEXT, user_id INTEGER)", + ); var primary = Colors.primaries[temp["primary_color"] as int]; var accent = Colors.accents[temp["accent_color"] as int]; var primaryBrightness = - temp["brightness"].toString().toLowerCase().contains("dark") ? Brightness.dark : Brightness.light; + temp["brightness"].toString().toLowerCase().contains("dark") + ? Brightness.dark + : Brightness.light; saveTheme( - ThemeData( - brightness: primaryBrightness, - primarySwatch: primary, - secondaryHeaderColor: accent, - floatingActionButtonTheme: FloatingActionButtonThemeData(backgroundColor: accent.shade400), - checkboxTheme: CheckboxThemeData( - fillColor: MaterialStateColor.resolveWith( - (s) { - if (s.contains(MaterialState.selected)) { - return accent.shade200; - } - return Colors.black; - }, - ), - ), + ThemeData( + brightness: primaryBrightness, + primarySwatch: primary, + secondaryHeaderColor: accent, + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: accent.shade400, + ), + checkboxTheme: CheckboxThemeData( + fillColor: MaterialStateColor.resolveWith((s) { + if (s.contains(MaterialState.selected)) { + return accent.shade200; + } + return Colors.black; + }), ), - primary, - accent); + ), + primary, + accent, + ); // ThemeData( // primarySwatch: Colors.primaries[temp["primary_color"] as int], // accentColor: Colors.accents[temp["accent_color"] as int], @@ -115,57 +142,65 @@ class Themes with ChangeNotifier { if (t.length == 0) return; for (var t2 in t) { if (lastId == t2["id"]) { - tm = t2["brightness"].toLowerCase().contains("dark") == Brightness.dark ? ThemeMode.dark : ThemeMode.light; + tm = t2["brightness"].toLowerCase().contains("dark") == Brightness.dark + ? ThemeMode.dark + : ThemeMode.light; } if ((t2["brightness"] as String).toLowerCase().contains("dark")) { var primary = Colors.primaries[t2["primary_color"] as int]; var accent = Colors.accents[t2["accent_color"] as int]; var primaryBrightness = - t2["brightness"].toString().toLowerCase().contains("dark") ? Brightness.dark : Brightness.light; + t2["brightness"].toString().toLowerCase().contains("dark") + ? Brightness.dark + : Brightness.light; darkTheme = NSSLThemeData( - ThemeData( - brightness: primaryBrightness, - primarySwatch: primary, - secondaryHeaderColor: accent, - floatingActionButtonTheme: FloatingActionButtonThemeData(backgroundColor: accent.shade400), - checkboxTheme: CheckboxThemeData( - fillColor: MaterialStateColor.resolveWith( - (s) { - if (s.contains(MaterialState.selected)) { - return accent.shade200; - } - return Colors.black; - }, - ), - ), + ThemeData( + brightness: primaryBrightness, + primarySwatch: primary, + secondaryHeaderColor: accent, + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: accent.shade400, + ), + checkboxTheme: CheckboxThemeData( + fillColor: MaterialStateColor.resolveWith((s) { + if (s.contains(MaterialState.selected)) { + return accent.shade200; + } + return Colors.black; + }), ), - t2["primary_color"], - t2["accent_color"]); + ), + t2["primary_color"], + t2["accent_color"], + ); } else { var primary = Colors.primaries[t2["primary_color"] as int]; var accent = Colors.accents[t2["accent_color"] as int]; var primaryBrightness = - t2["brightness"].toString().toLowerCase().contains("dark") ? Brightness.dark : Brightness.light; + t2["brightness"].toString().toLowerCase().contains("dark") + ? Brightness.dark + : Brightness.light; lightTheme = NSSLThemeData( - ThemeData( - brightness: primaryBrightness, - primarySwatch: primary, - secondaryHeaderColor: accent, - floatingActionButtonTheme: FloatingActionButtonThemeData(backgroundColor: accent.shade400), - checkboxTheme: CheckboxThemeData( - fillColor: MaterialStateColor.resolveWith( - (s) { - if (s.contains(MaterialState.selected)) { - return accent.shade200; - } - return Colors.black; - }, - ), - ), + ThemeData( + brightness: primaryBrightness, + primarySwatch: primary, + secondaryHeaderColor: accent, + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: accent.shade400, + ), + checkboxTheme: CheckboxThemeData( + fillColor: MaterialStateColor.resolveWith((s) { + if (s.contains(MaterialState.selected)) { + return accent.shade200; + } + return Colors.black; + }), ), - t2["primary_color"], - t2["accent_color"]); + ), + t2["primary_color"], + t2["accent_color"], + ); } } } diff --git a/lib/pages/about.dart b/lib/pages/about.dart index 0e51b23..f1e40c1 100644 --- a/lib/pages/about.dart +++ b/lib/pages/about.dart @@ -8,15 +8,15 @@ class AboutPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text(NSSLStrings.of(context).about()), - ), + appBar: AppBar(title: Text(NSSLStrings.of(context).about())), body: buildBody(context), ); } Widget buildBody(BuildContext context) { - var iconColor = AdaptiveTheme.of(context).mode == AdaptiveThemeMode.dark ? Colors.white : Colors.black; + var iconColor = AdaptiveTheme.of(context).mode == AdaptiveThemeMode.dark + ? Colors.white + : Colors.black; return ListView( children: [ Container( @@ -30,9 +30,7 @@ class AboutPage extends StatelessWidget { ), ), Container( - margin: EdgeInsets.only( - top: 8.0, - ), + margin: EdgeInsets.only(top: 8.0), child: Center( child: Text( "Non Sucking Shopping List", @@ -65,14 +63,8 @@ class AboutPage extends StatelessWidget { ), ), Divider(), - ListTile( - title: Text( - "Entwickelt von susch19 (Sascha Hering)", - ), - ), - ListTile( - title: Text("Version 0.40.0"), - ), + ListTile(title: Text("Entwickelt von susch19 (Sascha Hering)")), + ListTile(title: Text("Version 0.41.0")), Divider(), ListTile( leading: SvgPicture.asset( @@ -90,10 +82,16 @@ class AboutPage extends StatelessWidget { ), Divider(), ListTile( - leading: SvgPicture.asset("assets/vectors/nssl_icon.svg", alignment: Alignment.center, width: 32), + leading: SvgPicture.asset( + "assets/vectors/nssl_icon.svg", + alignment: Alignment.center, + width: 32, + ), title: Text(NSSLStrings.of(context).iconSource()), onTap: () { - var urlString = Uri.parse("https://www.flaticon.com/free-icon/check-list_306470"); + var urlString = Uri.parse( + "https://www.flaticon.com/free-icon/check-list_306470", + ); canLaunchUrl(urlString).then((value) { if (value) launchUrl(urlString); }); @@ -101,10 +99,16 @@ class AboutPage extends StatelessWidget { ), Divider(), ListTile( - leading: SvgPicture.asset("assets/vectors/google_play.svg", alignment: Alignment.center, width: 32), + leading: SvgPicture.asset( + "assets/vectors/google_play.svg", + alignment: Alignment.center, + width: 32, + ), title: Text(NSSLStrings.of(context).playstoreEntry()), onTap: () { - var urlString = Uri.parse("https://play.google.com/store/apps/details?id=de.susch19.nssl"); + var urlString = Uri.parse( + "https://play.google.com/store/apps/details?id=de.susch19.nssl", + ); canLaunchUrl(urlString).then((value) { if (value) launchUrl(urlString); }); @@ -112,7 +116,12 @@ class AboutPage extends StatelessWidget { ), Divider(), ListTile( - leading: Image.asset("assets/images/scandit.png", alignment: Alignment.center, width: 128, color: iconColor), + leading: Image.asset( + "assets/images/scandit.png", + alignment: Alignment.center, + width: 128, + color: iconColor, + ), title: Text(NSSLStrings.of(context).scanditCredit()), onTap: () { var urlString = Uri.parse("https://scandit.com"); diff --git a/lib/pages/barcode_scanner_page.dart b/lib/pages/barcode_scanner_page.dart index ecd0751..cb4f503 100644 --- a/lib/pages/barcode_scanner_page.dart +++ b/lib/pages/barcode_scanner_page.dart @@ -33,17 +33,19 @@ class _BarcodeScannerScreenState extends State bool _isPermissionMessageVisible = false; _BarcodeScannerScreenState() - : _context = kReleaseMode - ? DataCaptureContext.forLicenseKey(scanditLicenseKey) - : DataCaptureContext.forLicenseKey(scanditLicenseKeyDebug); + : _context = kReleaseMode + ? DataCaptureContext.forLicenseKey(scanditLicenseKey) + : DataCaptureContext.forLicenseKey(scanditLicenseKeyDebug); void _checkPermission() { - Permission.camera.request().isGranted.then((value) => setState(() { - _isPermissionMessageVisible = !value; - if (value) { - _camera?.switchToDesiredState(FrameSourceState.on); - } - })); + Permission.camera.request().isGranted.then( + (value) => setState(() { + _isPermissionMessageVisible = !value; + if (value) { + _camera?.switchToDesiredState(FrameSourceState.on); + } + }), + ); } @override @@ -91,13 +93,23 @@ class _BarcodeScannerScreenState extends State // Add a barcode capture overlay to the data capture view to render the location of captured barcodes on top of // the video preview. This is optional, but recommended for better visual feedback. - var overlay = BarcodeCaptureOverlay.withBarcodeCaptureForView(_barcodeCapture, _captureView) - ..viewfinder = RectangularViewfinder.withStyleAndLineStyle( - RectangularViewfinderStyle.square, RectangularViewfinderLineStyle.light); + var overlay = + BarcodeCaptureOverlay.withBarcodeCaptureForView( + _barcodeCapture, + _captureView, + ) + ..viewfinder = RectangularViewfinder.withStyleAndLineStyle( + RectangularViewfinderStyle.square, + RectangularViewfinderLineStyle.light, + ); // Adjust the overlay's barcode highlighting to match the new viewfinder styles and improve the visibility of feedback. // With 6.10 we will introduce this visual treatment as a new style for the overlay. - overlay.brush = Brush(Color.fromARGB(0, 0, 0, 0), Color.fromARGB(255, 255, 255, 255), 3); + overlay.brush = Brush( + Color.fromARGB(0, 0, 0, 0), + Color.fromARGB(255, 255, 255, 255), + 3, + ); _captureView.addOverlay(overlay); @@ -114,8 +126,14 @@ class _BarcodeScannerScreenState extends State Widget build(BuildContext context) { Widget child; if (_isPermissionMessageVisible) { - child = Text('No permission to access the camera!', - style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: Colors.black)); + child = Text( + 'No permission to access the camera!', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ); } else { child = _captureView; } @@ -132,16 +150,20 @@ class _BarcodeScannerScreenState extends State } @override - void didScan(BarcodeCapture barcodeCapture, BarcodeCaptureSession session) async { + Future didScan( + BarcodeCapture barcodeCapture, + BarcodeCaptureSession session, + Future getFrameData(), + ) async { _barcodeCapture.isEnabled = false; - var code = session.newlyRecognizedBarcodes.first; - var data = (code.data == null || code.data?.isEmpty == true) ? code.rawData : code.data; + var code = session.newlyRecognizedBarcode; + if (code == null) return; + var data = (code.data == null || code.data?.isEmpty == true) + ? code.rawData + : code.data; Navigator.pop(context, data); } - @override - void didUpdateSession(BarcodeCapture barcodeCapture, BarcodeCaptureSession session) {} - @override void dispose() { WidgetsBinding.instance.removeObserver(this); @@ -151,4 +173,11 @@ class _BarcodeScannerScreenState extends State _context.removeAllModes(); super.dispose(); } + + @override + Future didUpdateSession( + BarcodeCapture barcodeCapture, + BarcodeCaptureSession session, + Future Function() getFrameData, + ) async {} } diff --git a/lib/pages/bought_items.dart b/lib/pages/bought_items.dart index cd0e257..bfa2bd8 100644 --- a/lib/pages/bought_items.dart +++ b/lib/pages/bought_items.dart @@ -2,6 +2,7 @@ import 'dart:collection'; import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/legacy.dart'; import 'package:nssl/localization/nssl_strings.dart'; import 'package:nssl/models/model_export.dart'; import 'package:nssl/server_communication//s_c.dart'; @@ -19,16 +20,21 @@ final _searchModeProvider = StateProvider.autoDispose((ref) { return false; }); -final _shoppingItemsGroupedProvider = Provider.family, DateTime>((ref, arg) { - var items = ref.watch(_shoppingItemsProvider); - - var forDate = DateTime.utc(arg.year, arg.month, arg.day); - return items.where((element) { - var changed = element.changed!; - var changedFormat = DateTime.utc(changed.year, changed.month, changed.day); - return changedFormat == forDate; - }); -}); +final _shoppingItemsGroupedProvider = + Provider.family, DateTime>((ref, arg) { + var items = ref.watch(_shoppingItemsProvider); + + var forDate = DateTime.utc(arg.year, arg.month, arg.day); + return items.where((element) { + var changed = element.changed!; + var changedFormat = DateTime.utc( + changed.year, + changed.month, + changed.day, + ); + return changedFormat == forDate; + }); + }); final _filterProvider = StateProvider.autoDispose((ref) { return ""; @@ -37,67 +43,89 @@ final _filterAsLowercaseProvider = Provider.autoDispose((ref) { return ref.watch(_filterProvider).toLowerCase(); }); -final _filteredShoppingItemsGroupedProvider = Provider.family.autoDispose, DateTime>((ref, arg) { - var items = ref.watch(_shoppingItemsGroupedProvider(arg)); +final _filteredShoppingItemsGroupedProvider = Provider.family + .autoDispose, DateTime>((ref, arg) { + var items = ref.watch(_shoppingItemsGroupedProvider(arg)); + var isFiltering = ref.watch(_searchModeProvider); + var filter = ref.watch(_filterAsLowercaseProvider); + return items.where( + (element) => + !isFiltering || element.name.toLowerCase().contains(filter), + ); + }); + +final _filteredDateTimeProvider = Provider.autoDispose>(( + ref, +) { + var dates = ref.watch(_historyDateTimesProvider); var isFiltering = ref.watch(_searchModeProvider); var filter = ref.watch(_filterAsLowercaseProvider); - return items.where((element) => !isFiltering || element.name.toLowerCase().contains(filter)); -}); - -final _filteredDateTimeProvider = Provider.autoDispose>( - (ref) { - var dates = ref.watch(_historyDateTimesProvider); - var isFiltering = ref.watch(_searchModeProvider); - var filter = ref.watch(_filterAsLowercaseProvider); - if (!isFiltering || filter.isEmpty) return dates; + if (!isFiltering || filter.isEmpty) return dates; - return dates.where((element) => ref + return dates.where( + (element) => ref .read(_filteredShoppingItemsGroupedProvider(element)) - .any((element) => element.name.toLowerCase().contains(filter))); - }, -); - -final _tabCountProvider = Provider.autoDispose((ref) => ref.watch(_filteredDateTimeProvider).length); - -final _shoppingItemsFromServerProvider = - FutureProvider.autoDispose.family, int>((ref, listId) async { - var o = await ShoppingListSync.getList(listId, null, bought: true); - - if (o.statusCode == 500) { - return []; - } - - var z = GetBoughtListResult.fromJson(o.body); + .any((element) => element.name.toLowerCase().contains(filter)), + ); +}); - var shoppingItems = []; +final _tabCountProvider = Provider.autoDispose( + (ref) => ref.watch(_filteredDateTimeProvider).length, +); - shoppingItems.addAll(z.products.map((f) => ShoppingItem(f.name, listId, f.sortOrder, - id: f.id, amount: f.amount, changed: f.changed, created: f.created, crossedOut: false))); +final _shoppingItemsFromServerProvider = FutureProvider.autoDispose + .family, int>((ref, listId) async { + var o = await ShoppingListSync.getList(listId, null, bought: true); + + if (o.statusCode == 500) { + return []; + } + + var z = GetBoughtListResult.fromJson(o.body); + + var shoppingItems = []; + + shoppingItems.addAll( + z.products.map( + (f) => ShoppingItem( + f.name, + listId, + f.sortOrder, + id: f.id, + amount: f.amount, + changed: f.changed, + created: f.created, + crossedOut: false, + ), + ), + ); - ref.read(_shoppingItemsProvider.notifier).state = shoppingItems; - HashSet dates = HashSet(); + ref.read(_shoppingItemsProvider.notifier).state = shoppingItems; + HashSet dates = HashSet(); - DateTime dateTimeToDate(DateTime dateTime) { - return DateTime.utc(dateTime.year, dateTime.month, dateTime.day); - } + DateTime dateTimeToDate(DateTime dateTime) { + return DateTime.utc(dateTime.year, dateTime.month, dateTime.day); + } - for (var item in shoppingItems) dates.add(dateTimeToDate(item.changed!)); - var dateList = dates.toList(); - dateList.sort(((a, b) => b.compareTo(a))); - ref.read(_historyDateTimesProvider.notifier).state = dateList; + for (var item in shoppingItems) dates.add(dateTimeToDate(item.changed!)); + var dateList = dates.toList(); + dateList.sort(((a, b) => b.compareTo(a))); + ref.read(_historyDateTimesProvider.notifier).state = dateList; - return shoppingItems; -}); + return shoppingItems; + }); class BoughtItemsPage extends ConsumerStatefulWidget { BoughtItemsPage(this.listId, {Key? key, this.title}) : super(key: key); final String? title; final int listId; @override - _BoughtItemsPagePageState createState() => new _BoughtItemsPagePageState(listId); + _BoughtItemsPagePageState createState() => + new _BoughtItemsPagePageState(listId); } -class _BoughtItemsPagePageState extends ConsumerState with TickerProviderStateMixin { +class _BoughtItemsPagePageState extends ConsumerState + with TickerProviderStateMixin { final GlobalKey _mainScaffoldKey = GlobalKey(); var tec = TextEditingController(); @@ -109,11 +137,7 @@ class _BoughtItemsPagePageState extends ConsumerState with Tick @override void initState() { super.initState(); - _controller = TabController( - length: 0, - initialIndex: 0, - vsync: this, - ); + _controller = TabController(length: 0, initialIndex: 0, vsync: this); tec.addListener(() { ref.read(_filterProvider.notifier).state = tec.text; }); @@ -153,19 +177,24 @@ class _BoughtItemsPagePageState extends ConsumerState with Tick return fromServer.when( loading: () { return Scaffold( - appBar: AppBar( - title: Text(NSSLStrings.of(context).boughtProducts()), - actions: [], - ), - body: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - child: SizedBox(width: 40.0, height: 40.0, child: CircularProgressIndicator()), - padding: const EdgeInsets.only(top: 16.0), - ) - ], - )); + appBar: AppBar( + title: Text(NSSLStrings.of(context).boughtProducts()), + actions: [], + ), + body: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + child: SizedBox( + width: 40.0, + height: 40.0, + child: CircularProgressIndicator(), + ), + padding: const EdgeInsets.only(top: 16.0), + ), + ], + ), + ); }, data: (data) { didUpdateWidget(this.widget); @@ -175,7 +204,9 @@ class _BoughtItemsPagePageState extends ConsumerState with Tick title: !ref.watch(_searchModeProvider) ? Text(NSSLStrings.of(context).boughtProducts()) : TextField( - decoration: InputDecoration(hintText: NSSLStrings.of(context).searchProductHint()), + decoration: InputDecoration( + hintText: NSSLStrings.of(context).searchProductHint(), + ), controller: tec, maxLines: 1, autofocus: true, @@ -192,55 +223,59 @@ class _BoughtItemsPagePageState extends ConsumerState with Tick onPressed: () { ref.read(_searchModeProvider.notifier).state = false; }, - icon: Icon(Icons.search_off)) + icon: Icon(Icons.search_off), + ) : IconButton( onPressed: () { ref.read(_searchModeProvider.notifier).state = true; }, - icon: Icon(Icons.search)) + icon: Icon(Icons.search), + ), ], ), - body: TabBarView( - controller: _controller, - children: createChildren(), - ), + body: TabBarView(controller: _controller, children: createChildren()), ); }, error: (error, stackTrace) { return Scaffold( - appBar: AppBar( - title: Text(NSSLStrings.of(context).boughtProducts()), - actions: [], - ), - body: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [Text("An error occured $error")], - )); + appBar: AppBar( + title: Text(NSSLStrings.of(context).boughtProducts()), + actions: [], + ), + body: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [Text("An error occured $error")], + ), + ); }, ); } Decoration getIndicator() { return ShapeDecoration( - shape: const StadiumBorder( - side: BorderSide( - color: Colors.white24, - width: 2.0, - ), + shape: + const StadiumBorder( + side: BorderSide(color: Colors.white24, width: 2.0), ) + const StadiumBorder( - side: BorderSide( - color: Colors.transparent, - width: 4.0, - ), + side: BorderSide(color: Colors.transparent, width: 4.0), ), ); } - void showInSnackBar(String value, {Duration? duration, SnackBarAction? action}) { + void showInSnackBar( + String value, { + Duration? duration, + SnackBarAction? action, + }) { ScaffoldMessenger.of(context).removeCurrentSnackBar(); - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text(value), duration: duration ?? Duration(seconds: 3), action: action)); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(value), + duration: duration ?? Duration(seconds: 3), + action: action, + ), + ); } List createTabs() { @@ -248,7 +283,11 @@ class _BoughtItemsPagePageState extends ConsumerState with Tick var dates = ref.watch(_filteredDateTimeProvider); for (var item in dates) { tabs.add( - Tab(text: "${item.year}-${item.month.toString().padLeft(2, '0')}-${item.day.toString().padLeft(2, '0')}")); + Tab( + text: + "${item.year}-${item.month.toString().padLeft(2, '0')}-${item.day.toString().padLeft(2, '0')}", + ), + ); } return tabs; @@ -261,52 +300,84 @@ class _BoughtItemsPagePageState extends ConsumerState with Tick var dates = ref.watch(_filteredDateTimeProvider); for (var item in dates) { var items = ref.watch(_filteredShoppingItemsGroupedProvider(item)); - children.add(SafeArea( - top: false, - bottom: false, - child: Container( - key: ObjectKey(item), - padding: const EdgeInsets.all(12.0), - child: Card( - child: Center( - child: ListView( - children: items.map( - (i) { - return ListTile( - title: Text(i.name), - leading: Text(i.amount.toString() + "x"), - onTap: () async { - var shoppingItems = ref.read(currentShoppingItemsProvider); - var existingItem = shoppingItems.firstOrNull((item) => item.name == i.name); - var listsProvider = ref.read(shoppingListsProvider); - if (existingItem != null) { - var answer = await ShoppingListSync.changeProductAmount( - currentList.id, existingItem.id, i.amount, context); - var p = ChangeListItemResult.fromJson((answer).body); - listsProvider.addSingleItem( - currentList, existingItem.cloneWith(newAmount: p.amount, newChanged: p.changed)); - } else { - var p = AddListItemResult.fromJson( - (await ShoppingListSync.addProduct(listId, i.name, null, i.amount, context)).body); - int sortOrder = 0; - if (shoppingItems.length > 0) sortOrder = shoppingItems.last.sortOrder + 1; - var newItem = - ShoppingItem(p.name, currentList.id, sortOrder, amount: i.amount, id: p.productId); - - listsProvider.addSingleItem(currentList, newItem); - } - - showInSnackBar( - "${i.amount}x ${i.name}${NSSLStrings.of(context).newProductAddedToList()}${currentList.name}"); - }, - ); - }, - ).toList(growable: false), + children.add( + SafeArea( + top: false, + bottom: false, + child: Container( + key: ObjectKey(item), + padding: const EdgeInsets.all(12.0), + child: Card( + child: Center( + child: ListView( + children: items + .map((i) { + return ListTile( + title: Text(i.cleanedName), + leading: Text(i.amount.toString() + "x"), + onTap: () async { + var shoppingItems = ref.read( + currentShoppingItemsProvider, + ); + var existingItem = shoppingItems.firstOrNull( + (item) => item.name == i.name, + ); + var listsProvider = ref.read(shoppingListsProvider); + if (existingItem != null) { + var answer = + await ShoppingListSync.changeProductAmount( + currentList.id, + existingItem.id, + i.amount, + context, + ); + var p = ChangeListItemResult.fromJson( + (answer).body, + ); + listsProvider.addSingleItem( + currentList, + existingItem.cloneWith( + newAmount: p.amount, + newChanged: p.changed, + ), + ); + } else { + var p = AddListItemResult.fromJson( + (await ShoppingListSync.addProduct( + listId, + i.name, + null, + i.amount, + context, + )).body, + ); + int sortOrder = 0; + if (shoppingItems.length > 0) + sortOrder = shoppingItems.last.sortOrder + 1; + var newItem = ShoppingItem( + p.name, + currentList.id, + sortOrder, + amount: i.amount, + id: p.productId, + ); + + listsProvider.addSingleItem(currentList, newItem); + } + + showInSnackBar( + "${i.amount}x ${i.name}${NSSLStrings.of(context).newProductAddedToList()}${currentList.name}", + ); + }, + ); + }) + .toList(growable: false), + ), ), ), ), ), - )); + ); } return children; } diff --git a/lib/pages/contributors.dart b/lib/pages/contributors.dart index 9044400..079d9e3 100644 --- a/lib/pages/contributors.dart +++ b/lib/pages/contributors.dart @@ -1,89 +1,90 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:nssl/localization/nssl_strings.dart'; import 'package:nssl/models/model_export.dart'; import 'package:nssl/server_communication//s_c.dart'; import 'dart:async'; import 'package:nssl/server_communication/return_classes.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -class ContributorsPage extends ConsumerStatefulWidget { +class ContributorsPage extends HookConsumerWidget { ContributorsPage(this.listId, {Key? key, this.title}) : super(key: key); final String? title; final int listId; - @override - _ContributorsPagePageState createState() => new _ContributorsPagePageState(listId); -} - -class _ContributorsPagePageState extends ConsumerState { - final GlobalKey _mainScaffoldKey = GlobalKey(); - GlobalKey _iff = GlobalKey(); - GlobalKey _ib = GlobalKey(); - TextEditingController tec = TextEditingController(); - List conList = []; - int k = 1; - late int listId; - - _ContributorsPagePageState(int listId) { - this.listId = listId; - } @override - void initState() { - super.initState(); - ShoppingListSync.getContributors(listId, context).then((o) { - if (o.statusCode == 500) { - showInSnackBar("Internal Server Error"); - return; - } - GetContributorsResult z = GetContributorsResult.fromJson(o.body); - if (!z.success || z.contributors.length <= 0) - showInSnackBar(NSSLStrings.of(context).genericErrorMessageSnackbar() + o.reasonPhrase!, - duration: Duration(seconds: 10)); - else - setState(() => conList.addAll(z.contributors)); - }); - } + Widget build(BuildContext context, WidgetRef ref) { + final tec = useTextEditingController(); + final conList = useState([]); + + useEffect(() { + ShoppingListSync.getContributors(listId, context).then((o) { + if (o.statusCode == 500) { + showInSnackBar(context, "Internal Server Error"); + return; + } + GetContributorsResult z = GetContributorsResult.fromJson(o.body); + if (!z.success || z.contributors.length <= 0) + showInSnackBar( + context, + NSSLStrings.of(context).genericErrorMessageSnackbar() + + o.reasonPhrase!, + duration: Duration(seconds: 10)); + else { + conList.value.addAll(z.contributors); + conList.value = conList.value.toList(); + } + }); + return null; + }, [listId]); - @override - Widget build(BuildContext context) { return Scaffold( - key: _mainScaffoldKey, appBar: AppBar( title: Form( child: TextField( - key: _iff, - decoration: InputDecoration(hintText: NSSLStrings.of(context).nameOfNewContributorHint()), - onSubmitted: (x) => _addContributor(x), + decoration: InputDecoration( + hintText: + NSSLStrings.of(context).nameOfNewContributorHint()), + onSubmitted: (x) => _addContributor(context, conList, x), autofocus: true, controller: tec))), floatingActionButton: FloatingActionButton( onPressed: () => {}, child: IconButton( - key: _ib, icon: Icon(Icons.add), onPressed: () { - _addContributor(tec.text); + _addContributor(context, conList, tec.text); })), - body: buildBody()); + body: buildBody(context, ref, conList)); } - Future _addContributor(String value) async { + Future _addContributor(BuildContext context, + ValueNotifier> contributors, String value) async { var o = await ShoppingListSync.addContributor(listId, value, context); AddContributorResult z = AddContributorResult.fromJson(o.body); if (!z.success) - showInSnackBar(NSSLStrings.of(context).genericErrorMessageSnackbar() + z.error, duration: Duration(seconds: 10)); - else - setState(() => conList.add(ContributorResult() + showInSnackBar(context, + NSSLStrings.of(context).genericErrorMessageSnackbar() + z.error, + duration: Duration(seconds: 10)); + else { + contributors.value.add(ContributorResult() ..name = z.name ..userId = z.id - ..isAdmin = false)); + ..isAdmin = false); + contributors.value = contributors.value.toList(); + } } - Widget buildBody() { + Widget buildBody(BuildContext context, WidgetRef ref, + ValueNotifier> contributorNotifier) { + final conList = contributorNotifier.value; bool? isAdmin = false; if (conList.length > 0) { var user = ref.watch(userProvider); - isAdmin = conList.firstWhere((x) => x.name!.toLowerCase() == user.username.toLowerCase()).isAdmin; + isAdmin = conList + .firstWhere( + (x) => x.name!.toLowerCase() == user.username.toLowerCase()) + .isAdmin; var listView = ListView.builder( itemBuilder: (c, i) { return ListTile( @@ -91,11 +92,15 @@ class _ContributorsPagePageState extends ConsumerState { (conList[i].isAdmin! ? NSSLStrings.of(context).contributorAdmin() : NSSLStrings.of(context).contributorUser())), - trailing: isAdmin! && conList[i].name!.toLowerCase() != user.username.toLowerCase() + trailing: isAdmin! && + conList[i].name!.toLowerCase() != + user.username.toLowerCase() ? PopupMenuButton( padding: EdgeInsets.zero, - onSelected: popupMenuClicked, - itemBuilder: (BuildContext context) => >[ + onSelected: (a) => + popupMenuClicked(context, contributorNotifier, a), + itemBuilder: (BuildContext context) => + >[ PopupMenuItem( value: conList[i].userId.toString() + "\u{1E}ChangeRight", //x.id.toString() + "\u{1E}" + 'Rename', @@ -104,14 +109,18 @@ class _ContributorsPagePageState extends ConsumerState { ? const Icon(Icons.arrow_downward) : const Icon(Icons.arrow_upward)), title: (conList[i].isAdmin! - ? Text(NSSLStrings.of(context).demoteMenu()) - : Text(NSSLStrings.of(context).promoteMenu())))), + ? Text(NSSLStrings.of(context) + .demoteMenu()) + : Text(NSSLStrings.of(context) + .promoteMenu())))), const PopupMenuDivider(), // ignore: list_element_type_not_assignable PopupMenuItem( value: conList[i].userId.toString() + "\u{1E}Remove", //x.id.toString() + "\u{1E}" + 'Remove', child: ListTile( - leading: const Icon(Icons.delete), title: Text(NSSLStrings.of(context).remove()))) + leading: const Icon(Icons.delete), + title: Text( + NSSLStrings.of(context).remove()))) ]) : const Text(""), onTap: () => {}); @@ -123,32 +132,45 @@ class _ContributorsPagePageState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.center, children: [ Container( - child: SizedBox(width: 40.0, height: 40.0, child: CircularProgressIndicator()), + child: SizedBox( + width: 40.0, height: 40.0, child: CircularProgressIndicator()), padding: const EdgeInsets.only(top: 16.0), ) ], ); } - void showInSnackBar(String value, {Duration? duration, SnackBarAction? action}) { + void showInSnackBar(BuildContext context, String value, + {Duration? duration, SnackBarAction? action}) { ScaffoldMessenger.of(context).removeCurrentSnackBar(); - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text(value), duration: duration ?? Duration(seconds: 3), action: action)); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text(value), + duration: duration ?? Duration(seconds: 3), + action: action)); } - Future popupMenuClicked(String value) async { + Future popupMenuClicked( + BuildContext context, + ValueNotifier> contributorNotifier, + String value) async { + final conList = contributorNotifier.value; var splitted = value.split("\u{1E}"); var command = splitted[1]; switch (command) { case "Remove": var userId = int.parse(splitted[0]); - var res = await ShoppingListSync.deleteContributor(listId, userId, context); + var res = + await ShoppingListSync.deleteContributor(listId, userId, context); var enres = Result.fromJson(res.body); if (!enres.success) - showInSnackBar(enres.error); + showInSnackBar(context, enres.error); else { - showInSnackBar(conList.firstWhere((x) => x.userId == userId).name! + " was removed successfully"); - setState(() => conList.removeWhere((x) => x.userId == userId)); + showInSnackBar( + context, + conList.firstWhere((x) => x.userId == userId).name! + + " was removed successfully"); + conList.removeWhere((x) => x.userId == userId); + contributorNotifier.value = conList.toList(); } break; case "ChangeRight": @@ -156,20 +178,24 @@ class _ContributorsPagePageState extends ConsumerState { var res = await ShoppingListSync.changeRight(listId, userId, context); var enres = Result.fromJson(res.body); if (!enres.success) - showInSnackBar(enres.error); + showInSnackBar(context, enres.error); else { ShoppingListSync.getContributors(listId, context).then((o) { if (o.statusCode == 500) { - showInSnackBar("Internal Server Error"); + showInSnackBar(context, "Internal Server Error"); return; } GetContributorsResult z = GetContributorsResult.fromJson(o.body); if (!z.success || z.contributors.length <= 0) - showInSnackBar(NSSLStrings.of(context).genericErrorMessageSnackbar() + z.error, + showInSnackBar( + context, + NSSLStrings.of(context).genericErrorMessageSnackbar() + + z.error, duration: Duration(seconds: 10)); else conList.clear(); - setState(() => conList.addAll(z.contributors)); + conList.addAll(z.contributors); + contributorNotifier.value = conList.toList(); }); } break; diff --git a/lib/pages/custom_theme_page.dart b/lib/pages/custom_theme_page.dart index 462d665..7de206b 100644 --- a/lib/pages/custom_theme_page.dart +++ b/lib/pages/custom_theme_page.dart @@ -26,7 +26,7 @@ class CustomThemePageState extends State { TextEditingController tec = TextEditingController(); MaterialColor primary = Colors.blue; - MaterialAccentColor accent = Colors.tealAccent; + MaterialAccentColor accent = Colors.tealAccent; Brightness? primaryBrightness = Brightness.dark; Brightness? accentBrightness = Brightness.dark; @@ -35,29 +35,33 @@ class CustomThemePageState extends State { double primaryColorSlider = 0.0; double accentColorSlider = 0.0; bool? primaryColorCheckbox = false; + bool? useMaterial3Checkbox = true; bool accentColorCheckbox = true; + bool? elevateAppBar = false; Future _onWillPop() async { if (!_saveNeeded) return true; - final ThemeData theme = Theme.of(context); - final TextStyle dialogTextStyle = theme.textTheme.subtitle1!.copyWith(color: theme.textTheme.caption!.color); + // final ThemeData theme = Theme.of(context); + // final TextStyle dialogTextStyle = theme.textTheme.titleSmall!.copyWith(color: theme.textTheme.!.color); return await (showDialog( context: context, builder: (BuildContext context) => AlertDialog( - content: Text(NSSLStrings.of(context).discardNewTheme(), style: dialogTextStyle), + content: Text(NSSLStrings.of(context).discardNewTheme()), actions: [ TextButton( - child: Text(NSSLStrings.of(context).cancelButton()), - onPressed: () { - Navigator.of(context).pop(false); - }), + child: Text(NSSLStrings.of(context).cancelButton()), + onPressed: () { + Navigator.of(context).pop(false); + }, + ), TextButton( - child: Text(NSSLStrings.of(context).discardButton()), - onPressed: () { - Navigator.of(context).pop(true); - }), + child: Text(NSSLStrings.of(context).discardButton()), + onPressed: () { + Navigator.of(context).pop(true); + }, + ), ], ), )) ?? @@ -68,10 +72,18 @@ class CustomThemePageState extends State { Themes.saveTheme(td!, primary, accent); if (td!.brightness == Brightness.dark) { AdaptiveTheme.of(context).setThemeMode(AdaptiveThemeMode.dark); - Themes.darkTheme = NSSLThemeData(td, primaryColorSlider.round(), accentColorSlider.round()); + Themes.darkTheme = NSSLThemeData( + td, + primaryColorSlider.round(), + accentColorSlider.round(), + ); } else { AdaptiveTheme.of(context).setThemeMode(AdaptiveThemeMode.light); - Themes.lightTheme = NSSLThemeData(td, primaryColorSlider.round(), accentColorSlider.round()); + Themes.lightTheme = NSSLThemeData( + td, + primaryColorSlider.round(), + accentColorSlider.round(), + ); } Navigator.of(context).pop(); } @@ -91,74 +103,108 @@ class CustomThemePageState extends State { td = darkTheme ? Themes.darkTheme.theme : Themes.lightTheme.theme; primaryColorCheckbox = darkTheme; primary = - Colors.primaries[darkTheme ? Themes.darkTheme.primarySwatchIndex! : Themes.lightTheme.primarySwatchIndex!]; - accent = Colors.accents[darkTheme ? Themes.darkTheme.accentSwatchIndex! : Themes.lightTheme.accentSwatchIndex!]; + Colors.primaries[darkTheme + ? Themes.darkTheme.primarySwatchIndex! + : Themes.lightTheme.primarySwatchIndex!]; + accent = + Colors.accents[darkTheme + ? Themes.darkTheme.accentSwatchIndex! + : Themes.lightTheme.accentSwatchIndex!]; primaryBrightness = td!.brightness; primaryColorSlider = Colors.primaries.indexOf(primary).toDouble(); accentColorSlider = Colors.accents.indexOf(accent).toDouble(); + useMaterial3Checkbox = td?.useMaterial3; + elevateAppBar = (td?.appBarTheme.elevation ?? -1) > 0; } // var textColorTheme = TextStyle(color: td.textTheme.headline6.color); return Scaffold( floatingActionButton: FloatingActionButton( - child: Icon( - Icons.save, - // color: td.accentIconTheme.color, - ), - // backgroundColor: td.accentColor, - onPressed: _handleSubmitted), + child: Icon( + Icons.save, + // color: td.accentIconTheme.color, + ), + // backgroundColor: td.accentColor, + onPressed: _handleSubmitted, + ), // backgroundColor: td.scaffoldBackgroundColor, key: _scaffoldKey, appBar: AppBar( - title: Text(NSSLStrings.of(context).changeTheme() - // , style: textColorTheme - ), + title: Text( + NSSLStrings.of(context).changeTheme(), + // , style: textColorTheme + ), // backgroundColor: td.primaryColor, // iconTheme: td.iconTheme, // textTheme: td.textTheme, ), body: Form( - key: _formKey, - onWillPop: _onWillPop, - child: ListView(padding: const EdgeInsets.all(16.0), children: [ - Column(mainAxisSize: MainAxisSize.min, children: [ - Text( - NSSLStrings.of(context).changePrimaryColor(), - // style: td.textTheme.subtitle1, - ), - Slider( - value: primaryColorSlider, - max: (Colors.primaries).length.ceilToDouble() - 1.0, - divisions: Colors.primaries.length - 1, - onChanged: onChangedPrimarySlider, - // activeColor: td.accentColor, - ), - ]), - Column(mainAxisSize: MainAxisSize.min, children: [ - Text( - NSSLStrings.of(context).changeAccentColor(), - // style: td.textTheme.subtitle1, - ), - Slider( - value: accentColorSlider, - max: Colors.accents.length.ceilToDouble() - 1.0, - divisions: Colors.accents.length - 1, - onChanged: onChangedSecondarySlider, - // activeColor: td.accentColor - ), - ]), - Row(children: [ - Text( - NSSLStrings.of(context).changeDarkTheme(), - // style: td.textTheme.subtitle1, - ), - Checkbox( - value: primaryColorCheckbox, - onChanged: primaryBrightnessChange, - // activeColor: td.accentColor, - ), - ]), + key: _formKey, + onWillPop: _onWillPop, + child: ListView( + padding: const EdgeInsets.all(16.0), + children: [ + CheckboxListTile( + title: Text(NSSLStrings.of(context).useMaterial3()), + value: useMaterial3Checkbox, + onChanged: (value) { + useMaterial3Checkbox = value; + setColors(); + }, + ), + !(useMaterial3Checkbox ?? true) + ? Container() + : CheckboxListTile( + title: Text(NSSLStrings.of(context).elevateAppBar()), + value: elevateAppBar, + onChanged: (value) { + elevateAppBar = value; + setColors(); + }, + ), + CheckboxListTile( + title: Text(NSSLStrings.of(context).changeDarkTheme()), + value: primaryColorCheckbox, + onChanged: (value) { + primaryBrightnessChange(value); + }, + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + NSSLStrings.of(context).changePrimaryColor(), + // style: td.textTheme.subtitle1, + ), + Slider( + value: primaryColorSlider, + max: (Colors.primaries).length.ceilToDouble() - 1.0, + divisions: Colors.primaries.length - 1, + onChanged: onChangedPrimarySlider, + // activeColor: td.accentColor, + ), + ], + ), + (useMaterial3Checkbox ?? false) + ? Container() + : Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + NSSLStrings.of(context).changeAccentColor(), + // style: td.textTheme.subtitle1, + ), + Slider( + value: accentColorSlider, + max: Colors.accents.length.ceilToDouble() - 1.0, + divisions: Colors.accents.length - 1, + onChanged: onChangedSecondarySlider, + // activeColor: td.accentColor + ), + ], + ), + // Row(children: [ // Text( // NSSLStrings.of(context).changeAccentTextColor(), @@ -180,7 +226,9 @@ class CustomThemePageState extends State { // enableLabel: true, // pickerAreaHeightPercent: 0.8, // ), - ])), + ], + ), + ), ); } @@ -207,40 +255,46 @@ class CustomThemePageState extends State { // print(accentBrightness); if (primaryBrightness == Brightness.light) td = ThemeData( + useMaterial3: useMaterial3Checkbox, + colorSchemeSeed: primary, brightness: primaryBrightness, - primarySwatch: primary, + // primarySwatch: primary, secondaryHeaderColor: accent, - floatingActionButtonTheme: FloatingActionButtonThemeData(backgroundColor: accent.shade400), - checkboxTheme: CheckboxThemeData( - fillColor: MaterialStateColor.resolveWith( - (s) { - if (s.contains(MaterialState.selected)) { - return accent.shade200; - } - return Colors.black; - }, - ), - ), + appBarTheme: AppBarTheme(elevation: (elevateAppBar ?? false) ? 4 : 0), + // floatingActionButtonTheme: FloatingActionButtonThemeData(backgroundColor: accent.shade400), + // checkboxTheme: CheckboxThemeData( + // fillColor: MaterialStateColor.resolveWith( + // (s) { + // if (s.contains(MaterialState.selected)) { + // return accent.shade200; + // } + // return Colors.black; + // }, + // ), + // ), ); else td = ThemeData( + useMaterial3: useMaterial3Checkbox, + colorSchemeSeed: primary, brightness: primaryBrightness, - primarySwatch: primary, + // primarySwatch: primary, secondaryHeaderColor: accent, - floatingActionButtonTheme: FloatingActionButtonThemeData(backgroundColor: accent.shade100), - checkboxTheme: CheckboxThemeData( - checkColor: MaterialStateColor.resolveWith((states) { - return Colors.black; - }), - fillColor: MaterialStateColor.resolveWith( - (s) { - if (s.contains(MaterialState.selected)) { - return accent.shade200; - } - return Colors.black; - }, - ), - ), + appBarTheme: AppBarTheme(elevation: (elevateAppBar ?? false) ? 4 : 0), + // floatingActionButtonTheme: FloatingActionButtonThemeData(backgroundColor: accent.shade100), + // checkboxTheme: CheckboxThemeData( + // checkColor: MaterialStateColor.resolveWith((states) { + // return Colors.black; + // }), + // fillColor: MaterialStateColor.resolveWith( + // (s) { + // if (s.contains(MaterialState.selected)) { + // return accent.shade200; + // } + // return Colors.black; + // }, + // ), + // ), ); AdaptiveTheme.of(context).setTheme(light: td!, dark: td); diff --git a/lib/pages/login.dart b/lib/pages/login.dart index 8af6dcd..742d1e3 100644 --- a/lib/pages/login.dart +++ b/lib/pages/login.dart @@ -41,7 +41,9 @@ class LoginPageState extends ConsumerState { var validateMode = AutovalidateMode.disabled; void showInSnackBar(String value) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(value), duration: Duration(seconds: 3))); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(value), duration: Duration(seconds: 3)), + ); } Future _handleSubmitted() async { @@ -58,13 +60,21 @@ class LoginPageState extends ConsumerState { if (_validateEmail(nameInput.textEditingController.text) != null) { var res = await UserSync.login(name, password, context); - if (!HelperMethods.reactToRespone(res, context, scaffoldState: _scaffoldKey.currentState)) + if (!HelperMethods.reactToRespone( + res, + context, + scaffoldState: _scaffoldKey.currentState, + )) return; else _handleLoggedIn(LoginResult.fromJson(res.body)); } else { var res = await UserSync.loginEmail(name, password, context); - if (!HelperMethods.reactToRespone(res, context, scaffoldState: _scaffoldKey.currentState)) + if (!HelperMethods.reactToRespone( + res, + context, + scaffoldState: _scaffoldKey.currentState, + )) return; else _handleLoggedIn(LoginResult.fromJson(res.body)); @@ -82,7 +92,8 @@ class LoginPageState extends ConsumerState { User.token = res.token; var user = User(res.id, res.username, res.eMail); - if (!kIsWeb) firebaseMessaging?.subscribeToTopic(res.username + "userTopic"); + if (!kIsWeb) + firebaseMessaging?.subscribeToTopic(res.username + "userTopic"); var listController = ref.read(shoppingListsProvider); await listController.reloadAllLists(context); @@ -90,6 +101,7 @@ class LoginPageState extends ConsumerState { user.save(0); ref.watch(currentListIndexProvider.notifier).state = 0; userState.state = user; + if (Navigator.canPop(context)) Navigator.pop(context); } String? _validateName(String? value) { @@ -102,24 +114,30 @@ class LoginPageState extends ConsumerState { String? _validateEmail(String value) { if (value.isEmpty) return NSSLStrings.of(context).emailRequiredError(); RegExp email = RegExp( - r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'); + r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$', + ); - if (!email.hasMatch(value)) return NSSLStrings.of(context).emailIncorrectFormatError(); + if (!email.hasMatch(value)) + return NSSLStrings.of(context).emailIncorrectFormatError(); return null; } String? _validatePassword(String? value) { - if (pwInput.textEditingController.text.isEmpty) return NSSLStrings.of(context).passwordEmptyError(); + if (pwInput.textEditingController.text.isEmpty) + return NSSLStrings.of(context).passwordEmptyError(); return null; } _resetInput() { nameInput.decoration = InputDecoration( - helperText: NSSLStrings.of(context).usernameOrEmailForLoginHint(), - labelText: NSSLStrings.of(context).usernameOrEmailTitle()); + helperText: NSSLStrings.of(context).usernameOrEmailForLoginHint(), + labelText: NSSLStrings.of(context).usernameOrEmailTitle(), + ); pwInput.decoration = InputDecoration( - helperText: NSSLStrings.of(context).choosenPasswordHint(), labelText: NSSLStrings.of(context).password()); + helperText: NSSLStrings.of(context).choosenPasswordHint(), + labelText: NSSLStrings.of(context).password(), + ); } @override @@ -131,7 +149,7 @@ class LoginPageState extends ConsumerState { @override Widget build(BuildContext context) { _resetInput(); -// return ListView(children: [new (child: Scaffold( + // return ListView(children: [new (child: Scaffold( return Scaffold( key: _scaffoldKey, resizeToAvoidBottomInset: true, @@ -140,75 +158,82 @@ class LoginPageState extends ConsumerState { key: _formKey, autovalidateMode: validateMode, child: ListView( -// physics: const NeverScrollableScrollPhysics(), - padding: const EdgeInsets.symmetric(horizontal: 32.0), - children: [ - ListTile( - title: TextFormField( - key: nameInput.key, - decoration: nameInput.decoration, - //onChanged: (input) => nameInput.errorText = _validateName(input), - controller: nameInput.textEditingController, - keyboardType: TextInputType.emailAddress, - autofillHints: [AutofillHints.username, AutofillHints.email], - autocorrect: false, - autofocus: true, - validator: _validateName, - onSaved: (val) { - FocusScope.of(context).requestFocus(pwInput.focusNode); - })), - ListTile( - title: TextFormField( - key: pwInput.key, - decoration: pwInput.decoration, - focusNode: pwInput.focusNode, - obscureText: true, - autocorrect: false, - autofillHints: [AutofillHints.password], - controller: pwInput.textEditingController, - validator: _validatePassword, - onSaved: (val) { - _handleSubmitted(); - })), - ListTile( - title: Container( - child: ElevatedButton( - key: submit.key, - child: Center(child: Text(NSSLStrings.of(context).loginButton())), - onPressed: _handleSubmitted, - ), - padding: const EdgeInsets.only(top: 16.0)), + // physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.symmetric(horizontal: 32.0), + children: [ + ListTile( + title: TextFormField( + key: nameInput.key, + decoration: nameInput.decoration, + //onChanged: (input) => nameInput.errorText = _validateName(input), + controller: nameInput.textEditingController, + keyboardType: TextInputType.emailAddress, + autofillHints: [AutofillHints.username, AutofillHints.email], + autocorrect: false, + autofocus: true, + validator: _validateName, + onSaved: (val) { + FocusScope.of(context).requestFocus(pwInput.focusNode); + }, ), - ListTile( - title: Container( - padding: const EdgeInsets.only(top: 40.0), - child: TextButton( - onPressed: () { - var userId = ref.read(userIdProvider); - userId == null || userId < 0 - ? Navigator.pushNamed(context, "/registration") - : Navigator.popAndPushNamed(context, "/registration"); - }, - child: Text(NSSLStrings.of(context).registerTextOnLogin()), + ), + ListTile( + title: TextFormField( + key: pwInput.key, + decoration: pwInput.decoration, + focusNode: pwInput.focusNode, + obscureText: true, + autocorrect: false, + autofillHints: [AutofillHints.password], + controller: pwInput.textEditingController, + validator: _validatePassword, + onSaved: (val) { + _handleSubmitted(); + }, + ), + ), + ListTile( + title: Container( + child: ElevatedButton( + key: submit.key, + child: Center( + child: Text(NSSLStrings.of(context).loginButton()), ), + onPressed: _handleSubmitted, ), + padding: const EdgeInsets.only(top: 16.0), ), - ListTile( - title: Container( - child: TextButton( - onPressed: () { - Navigator.pushNamed(context, "/forgot_password"); - }, - child: Text(NSSLStrings.of(context).forgotPassword()), - ), + ), + ListTile( + title: Container( + padding: const EdgeInsets.only(top: 40.0), + child: TextButton( + onPressed: () { + var userId = ref.read(userIdProvider); + userId == null || userId < 0 + ? Navigator.pushNamed(context, "/registration") + : Navigator.popAndPushNamed(context, "/registration"); + }, + child: Text(NSSLStrings.of(context).registerTextOnLogin()), ), ), - //padding: EdgeInsets.only( - // top: MediaQuery.of(context).size.height / 5), - ] - //]), - ), + ListTile( + title: Container( + child: TextButton( + onPressed: () { + Navigator.pushNamed(context, "/forgot_password"); + }, + child: Text(NSSLStrings.of(context).forgotPassword()), + ), + ), + ), + //padding: EdgeInsets.only( + // top: MediaQuery.of(context).size.height / 5), + ], + + //]), + ), ), ); } diff --git a/lib/pages/main_page.dart b/lib/pages/main_page.dart index 5841c56..1079b66 100644 --- a/lib/pages/main_page.dart +++ b/lib/pages/main_page.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:adaptive_theme/adaptive_theme.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter_riverpod/legacy.dart'; import 'package:nssl/helper/choose_dialog.dart'; import 'package:nssl/helper/simple_dialog.dart'; import 'package:nssl/manager/export_manager.dart'; @@ -27,7 +28,8 @@ class MainPage extends ConsumerStatefulWidget { MainPageState createState() => MainPageState(); } -class MainPageState extends ConsumerState with TickerProviderStateMixin, WidgetsBindingObserver { +class MainPageState extends ConsumerState + with TickerProviderStateMixin, WidgetsBindingObserver { final ScrollController _mainController = ScrollController(); final ScrollController _drawerController = ScrollController(); @@ -66,37 +68,49 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi parent: ReverseAnimation(_controller!), curve: Curves.fastOutSlowIn, ); - _drawerDetailsPosition = Tween( - begin: const Offset(0.0, -1.0), - end: Offset.zero, - ).animate(CurvedAnimation( - parent: _controller!, - curve: Curves.fastOutSlowIn, - )); + _drawerDetailsPosition = + Tween(begin: const Offset(0.0, -1.0), end: Offset.zero).animate( + CurvedAnimation(parent: _controller!, curve: Curves.fastOutSlowIn), + ); } @override Widget build(BuildContext context) { var currentList = ref.watch(currentListProvider); return Scaffold( - appBar: AppBar( - title: Text( - currentList?.name ?? NSSLStrings.of(context).noListLoaded(), - ), - actions: _getMainDropdownActions(context)), - body: ShoppingListWidget(this), - floatingActionButton: acceptReordingFAB(), - drawer: _buildDrawer(context), - persistentFooterButtons: ref.watch(_isReorderingProvider) || currentList == null - ? [] - : [ + appBar: AppBar( + title: Text( + currentList?.name ?? NSSLStrings.of(context).noListLoaded(), + ), + actions: _getMainDropdownActions(context), + ), + body: ShoppingListWidget(this), + floatingActionButton: acceptReordingFAB(), + drawer: _buildDrawer(context), + persistentFooterButtons: + ref.watch(_isReorderingProvider) || currentList == null + ? [] + : [ TextButton( - child: Text(NSSLStrings.of(context).addPB()), onPressed: () => _addWithoutSearchDialog(context)) + child: Text(NSSLStrings.of(context).addPB()), + onPressed: () => _addWithoutSearchDialog(context), + ), ] + (!kIsWeb && Platform.isAndroid - ? [TextButton(child: Text(NSSLStrings.of(context).scanPB()), onPressed: () => _getEAN(currentList))] + ? [ + TextButton( + child: Text(NSSLStrings.of(context).scanPB()), + onPressed: () => _getEAN(currentList), + ), + ] : []) + - [TextButton(child: Text(NSSLStrings.of(context).searchPB()), onPressed: search)]); + [ + TextButton( + child: Text(NSSLStrings.of(context).searchPB()), + onPressed: search, + ), + ], + ); } void _onReorderItems(int oldIndex, int newIndex) { @@ -132,14 +146,32 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi shoppingState.state = newState; } - void showInSnackBar(String value, {Duration? duration, SnackBarAction? action}) { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text(value), duration: duration ?? Duration(seconds: 3), action: action)); + void showInSnackBar( + String value, { + Duration? duration, + SnackBarAction? action, + }) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(value), + duration: duration ?? Duration(seconds: 3), + action: action, + ), + ); } - void showInDrawerSnackBar(String value, {Duration? duration, SnackBarAction? action}) { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text(value), duration: duration ?? Duration(seconds: 3), action: action)); + void showInDrawerSnackBar( + String value, { + Duration? duration, + SnackBarAction? action, + }) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(value), + duration: duration ?? Duration(seconds: 3), + action: action, + ), + ); } Future register() => Navigator.pushNamed(context, "/registration"); @@ -156,21 +188,31 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi if (list == null) return; var listProvider = ref.read(shoppingListsProvider); - final String action = - (dir == DismissDirection.endToStart) ? NSSLStrings.of(context).archived() : NSSLStrings.of(context).deleted(); + final String action = (dir == DismissDirection.endToStart) + ? NSSLStrings.of(context).archived() + : NSSLStrings.of(context).deleted(); await listProvider.deleteSingleItem(list, s); ShoppingListSync.deleteProduct(list.id, s.id, context); - showInSnackBar(NSSLStrings.of(context).youHaveActionItemMessage() + "${s.name} $action", - action: SnackBarAction( - label: NSSLStrings.of(context).undo(), - onPressed: () { - listProvider.addSingleItem(list, s); - ShoppingListSync.changeProductAmount(list.id, s.id, s.amount, context); - ScaffoldMessenger.of(context).removeCurrentSnackBar(); - }), - duration: Duration(seconds: 10)); + showInSnackBar( + NSSLStrings.of(context).youHaveActionItemMessage() + + "${s.cleanedName} $action", + action: SnackBarAction( + label: NSSLStrings.of(context).undo(), + onPressed: () { + listProvider.addSingleItem(list, s); + ShoppingListSync.changeProductAmount( + list.id, + s.id, + s.amount, + context, + ); + ScaffoldMessenger.of(context).removeCurrentSnackBar(); + }, + ), + duration: Duration(seconds: 10), + ); } Future selectedOption(String s) async { @@ -180,13 +222,18 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi break; case "options": await Navigator.push( - context, - MaterialPageRoute( - builder: (BuildContext context) => SettingsPage(), - fullscreenDialog: true, - )) - .whenComplete(() => AdaptiveTheme.of(context) - .setTheme(light: Themes.lightTheme.theme!, dark: Themes.darkTheme.theme, notify: true)); + context, + MaterialPageRoute( + builder: (BuildContext context) => SettingsPage(), + fullscreenDialog: true, + ), + ).whenComplete( + () => AdaptiveTheme.of(context).setTheme( + light: Themes.lightTheme.theme!, + dark: Themes.darkTheme.theme, + notify: true, + ), + ); break; case "PerformanceOverlay": setState(() => performanceOverlay = !performanceOverlay); @@ -202,11 +249,12 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi break; case "ChangePassword": Navigator.push( - context, - MaterialPageRoute( - builder: (BuildContext context) => ChangePasswordPage(), - fullscreenDialog: true, - )); + context, + MaterialPageRoute( + builder: (BuildContext context) => ChangePasswordPage(), + fullscreenDialog: true, + ), + ); break; case "reorderItems": var reordering = ref.watch(_isReorderingProvider.notifier); @@ -228,11 +276,12 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi Future _getEAN(ShoppingList currentList) async { ean = await Navigator.push( - context, - MaterialPageRoute( - builder: (BuildContext context) => BarcodeScannerScreen(), - fullscreenDialog: true, - )); + context, + MaterialPageRoute( + builder: (BuildContext context) => BarcodeScannerScreen(), + fullscreenDialog: true, + ), + ); if (ean == null || ean == "" || ean == "Permissions denied") return; @@ -242,23 +291,51 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi if (k.success) { RegExp reg = RegExp("([0-9]+[.,]?[0-9]*(\\s)?[gkmlGKML]{1,2})"); - String? name = reg.hasMatch(k.name!) ? k.name : "${k.name} ${k.quantity}${k.unit}"; - var shoppingItems = ref.read(shoppingItemsPerListProvider.create(currentList.id)); + String? name = reg.hasMatch(k.name!) + ? k.name + : "${k.name} ${k.quantity?.toString() ?? ""}${k.unit ?? ""}"; + var shoppingItems = ref.read( + shoppingItemsPerListProvider(currentList.id), + ); var item = shoppingItems.firstOrNull((x) => x.name == name); if (item != null) { - var answer = await ShoppingListSync.changeProductAmount(currentList.id, item.id, 1, context); + var answer = await ShoppingListSync.changeProductAmount( + currentList.id, + item.id, + 1, + context, + ); var p = ChangeListItemResult.fromJson((answer).body); - var newItem = item.cloneWith(newAmount: p.amount, newChanged: p.changed); + var newItem = item.cloneWith( + newAmount: p.amount, + newChanged: p.changed, + ); item.exchange(newItem, ref); } else { - var p = - AddListItemResult.fromJson((await ShoppingListSync.addProduct(currentList.id, name, '-', 1, context)).body); + var p = AddListItemResult.fromJson( + (await ShoppingListSync.addProduct( + currentList.id, + name, + '-', + 1, + context, + )).body, + ); var items = ref.watch(shoppingItemsProvider.notifier); var newState = items.state.toList(); int sortOrder = 0; - if (shoppingItems.length > 0) sortOrder = shoppingItems.last.sortOrder + 1; - newState.add(ShoppingItem(p.name, currentList.id, sortOrder, amount: 1, id: p.productId)); + if (shoppingItems.length > 0) + sortOrder = shoppingItems.last.sortOrder + 1; + newState.add( + ShoppingItem( + p.name, + currentList.id, + sortOrder, + amount: 1, + id: p.productId, + ), + ); items.state = newState; } var provider = ref.read(shoppingListsProvider); @@ -267,54 +344,76 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi return; } Navigator.push( - context, - MaterialPageRoute( - builder: (BuildContext context) => AddProductToDatabase(ean), fullscreenDialog: true)); + context, + MaterialPageRoute( + builder: (BuildContext context) => AddProductToDatabase(ean), + fullscreenDialog: true, + ), + ); } void chooseListToAddDialog() { var dialog = ChooseDialog.create( - context: context, - title: NSSLStrings.of(context).chooseListToAddTitle(), - titleOption1: NSSLStrings.of(context).chooseAddListDialog(), - onOption1: addListDialog, - titleOption2: NSSLStrings.of(context).chooseAddRecipeDialog(), - onOption2: () => addRecipeDialog(false)); - showDialog(builder: (BuildContext context) => dialog, context: context, barrierDismissible: false); + context: context, + title: NSSLStrings.of(context).chooseListToAddTitle(), + titleOption1: NSSLStrings.of(context).chooseAddListDialog(), + onOption1: addListDialog, + titleOption2: NSSLStrings.of(context).chooseAddRecipeDialog(), + onOption2: () => addRecipeDialog(false), + ); + showDialog( + builder: (BuildContext context) => dialog, + context: context, + barrierDismissible: false, + ); } void addListDialog() { var sd = SimpleDialogSingleInput.create( - hintText: NSSLStrings.of(context).newNameOfListHint(), - labelText: NSSLStrings.of(context).listName(), - onSubmitted: createNewList, - title: NSSLStrings.of(context).addNewListTitle(), - context: context); + hintText: NSSLStrings.of(context).newNameOfListHint(), + labelText: NSSLStrings.of(context).listName(), + onSubmitted: createNewList, + title: NSSLStrings.of(context).addNewListTitle(), + context: context, + ); - showDialog(builder: (BuildContext context) => sd, context: context, barrierDismissible: false); + showDialog( + builder: (BuildContext context) => sd, + context: context, + barrierDismissible: false, + ); } void addRecipeDialog(bool import) { var sd = SimpleDialogSingleInput.create( - hintText: NSSLStrings.of(context).recipeNameHint(), - labelText: NSSLStrings.of(context).recipeName(), - onSubmitted: import ? importNewRecipe : createNewRecipe, - title: import ? NSSLStrings.of(context).importNewRecipeTitle() : NSSLStrings.of(context).addNewRecipeTitle(), - context: context); + hintText: NSSLStrings.of(context).recipeNameHint(), + labelText: NSSLStrings.of(context).recipeName(), + onSubmitted: import ? importNewRecipe : createNewRecipe, + title: import + ? NSSLStrings.of(context).importNewRecipeTitle() + : NSSLStrings.of(context).addNewRecipeTitle(), + context: context, + ); - showDialog(builder: (BuildContext context) => sd, context: context, barrierDismissible: false); + showDialog( + builder: (BuildContext context) => sd, + context: context, + barrierDismissible: false, + ); } Future renameListDialog(int listId) { return showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => SimpleDialogSingleInput.create( + hintText: NSSLStrings.of(context).renameListHint(), + labelText: NSSLStrings.of(context).listName(), + onSubmitted: (s) => renameList(listId, s), + title: NSSLStrings.of(context).renameListTitle(), context: context, - barrierDismissible: false, - builder: (BuildContext context) => SimpleDialogSingleInput.create( - hintText: NSSLStrings.of(context).renameListHint(), - labelText: NSSLStrings.of(context).listName(), - onSubmitted: (s) => renameList(listId, s), - title: NSSLStrings.of(context).renameListTitle(), - context: context)); + ), + ); } Future createNewRecipe(String idOrUrl) async { @@ -322,7 +421,9 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi var indexProvider = ref.watch(currentListIndexProvider.notifier); var res = await ShoppingListSync.addRecipe(idOrUrl, context); if (res.statusCode >= 400) { - showInSnackBar(NSSLStrings.of(context).recipeCreateError() + (res.reasonPhrase ?? "")); + showInSnackBar( + NSSLStrings.of(context).recipeCreateError() + (res.reasonPhrase ?? ""), + ); return; } var newListRes = GetListResult.fromJson(res.body); @@ -331,8 +432,19 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi var items = ref.watch(shoppingItemsProvider.notifier); var newState = items.state.toList(); if (newListRes.products != null) - newState.addAll(newListRes.products!.map((e) => ShoppingItem(e.name, newList.id, e.sortOrder, - amount: e.amount, id: e.id, created: e.created, changed: e.changed))); + newState.addAll( + newListRes.products!.map( + (e) => ShoppingItem( + e.name, + newList.id, + e.sortOrder, + amount: e.amount, + id: e.id, + created: e.created, + changed: e.changed, + ), + ), + ); items.state = newState; @@ -356,7 +468,9 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi var res = await ShoppingListSync.importRecipe(idOrUrl, list.id, context); if (res.statusCode >= 400) { - showInSnackBar(NSSLStrings.of(context).recipeCreateError() + (res.reasonPhrase ?? "")); + showInSnackBar( + NSSLStrings.of(context).recipeCreateError() + (res.reasonPhrase ?? ""), + ); return; } @@ -425,56 +539,82 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi child: FractionallySizedBox( heightFactor: 0.8, child: ListView.builder( - padding: const EdgeInsets.all(8), - itemCount: list.length, - itemBuilder: (BuildContext context, int index) { - var currentSelected = list[index].id == currList?.id; - return Container( - height: 50, - child: ListTile( - onTap: () { - importNewRecipeIntoList(list[index], url); - Navigator.pop(context, ""); - }, - title: Text( - list[index].name, - style: TextStyle( - fontWeight: currentSelected ? FontWeight.bold : FontWeight.normal, - fontStyle: currentSelected ? FontStyle.italic : FontStyle.normal, - ), + padding: const EdgeInsets.all(8), + itemCount: list.length, + itemBuilder: (BuildContext context, int index) { + var currentSelected = list[index].id == currList?.id; + return Container( + height: 50, + child: ListTile( + onTap: () { + importNewRecipeIntoList(list[index], url); + Navigator.pop(context, ""); + }, + title: Text( + list[index].name, + style: TextStyle( + fontWeight: currentSelected + ? FontWeight.bold + : FontWeight.normal, + fontStyle: currentSelected + ? FontStyle.italic + : FontStyle.normal, ), ), - ); - }), + ), + ); + }, + ), ), ), actions: [ - TextButton(child: Text(NSSLStrings.of(context).cancelButton()), onPressed: () => Navigator.pop(context, "")), TextButton( - child: Text(NSSLStrings.of(context).recipeFromShareNew()), - onPressed: () { - createNewRecipe(url); - Navigator.pop(context, ""); - }), + child: Text(NSSLStrings.of(context).cancelButton()), + onPressed: () => Navigator.pop(context, ""), + ), + TextButton( + child: Text(NSSLStrings.of(context).recipeFromShareNew()), + onPressed: () { + createNewRecipe(url); + Navigator.pop(context, ""); + }, + ), ], ); - showDialog(builder: (BuildContext context) => dialog, context: context, barrierDismissible: false); + showDialog( + builder: (BuildContext context) => dialog, + context: context, + barrierDismissible: false, + ); } Widget _buildDrawer(BuildContext context) { var user = ref.watch(userProvider); var isDarkTheme = AdaptiveTheme.of(context).mode == AdaptiveThemeMode.dark; var userheader = UserAccountsDrawerHeader( - accountName: Text(user.username == "" ? NSSLStrings.of(context).notLoggedInYet() : user.username), - accountEmail: Text(user.eMail == "" ? NSSLStrings.of(context).notLoggedInYet() : user.username), + accountName: Text( + user.username == "" + ? NSSLStrings.of(context).notLoggedInYet() + : user.username, + ), + accountEmail: Text( + user.eMail == "" + ? NSSLStrings.of(context).notLoggedInYet() + : user.username, + ), currentAccountPicture: CircleAvatar( - child: Text( - user.username.substring(0, 2).toUpperCase(), - style: TextStyle(color: isDarkTheme ? Colors.black : Colors.white), - ), - backgroundColor: isDarkTheme - ? Themes.darkTheme.theme!.floatingActionButtonTheme.backgroundColor - : Themes.lightTheme.theme!.floatingActionButtonTheme.backgroundColor), + child: Text( + user.username.substring(0, 2).toUpperCase(), + style: TextStyle(color: isDarkTheme ? Colors.black : Colors.white), + ), + backgroundColor: isDarkTheme + ? Themes.darkTheme.theme!.floatingActionButtonTheme.backgroundColor + : Themes + .lightTheme + .theme! + .floatingActionButtonTheme + .backgroundColor, + ), onDetailsPressed: () { _showDrawerContents = !_showDrawerContents; _showDrawerContents ? _controller!.reverse() : _controller!.forward(); @@ -483,111 +623,137 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi var shoppingListsController = ref.watch(shoppingListsProvider); var list = shoppingListsController.shoppingLists.isNotEmpty ? shoppingListsController.shoppingLists - .map((x) => ListTile( + .map( + (x) => ListTile( title: Text(x.name), - onTap: () => changeCurrentList(shoppingListsController.shoppingLists - .indexOf(shoppingListsController.shoppingLists.firstWhere((y) => y.id == x.id))), + onTap: () => changeCurrentList( + shoppingListsController.shoppingLists.indexOf( + shoppingListsController.shoppingLists.firstWhere( + (y) => y.id == x.id, + ), + ), + ), trailing: PopupMenuButton( - padding: EdgeInsets.zero, - onSelected: (v) async => await drawerListItemMenuClicked(v), - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - value: x.id.toString() + "\u{1E}" + "Contributors", - child: ListTile( - leading: const Icon(Icons.person_add), - title: Text(NSSLStrings.of(context).contributors()), - ), - ), - PopupMenuItem( - value: x.id.toString() + "\u{1E}" + "BoughtList", - child: ListTile( - leading: const Icon(Icons.history), - title: Text(NSSLStrings.of(context).boughtProducts()), - // NSSLStrings.of(context)!.contributors()), - ), - ), - //Deactivated, because it's not working at the moment - // PopupMenuItem( - // value: x.id.toString() + "\u{1E}" + 'ExportAsPdf', - // child: ListTile( - // leading: const Icon(Icons.picture_as_pdf), - // title: Text(NSSLStrings.of(context)!.exportAsPdf())), - // ), - PopupMenuItem( - value: x.id.toString() + "\u{1E}" + 'Rename', - child: ListTile( - leading: const Icon(Icons.mode_edit), - title: Text(NSSLStrings.of(context).rename()))), - PopupMenuItem( - value: x.id.toString() + "\u{1E}" + 'Auto-Sync', - child: ListTile( - leading: Icon(x.messagingEnabled ? Icons.check_box : Icons.check_box_outline_blank), - title: Text(NSSLStrings.of(context).autoSync()))), - const PopupMenuDivider(), - PopupMenuItem( - value: x.id.toString() + "\u{1E}" + 'Remove', - child: ListTile( - leading: const Icon(Icons.delete), title: Text(NSSLStrings.of(context).remove()))) - ]), - )) - .toList() + padding: EdgeInsets.zero, + onSelected: (v) async => await drawerListItemMenuClicked(v), + itemBuilder: (BuildContext context) => >[ + PopupMenuItem( + value: x.id.toString() + "\u{1E}" + "Contributors", + child: ListTile( + leading: const Icon(Icons.person_add), + title: Text(NSSLStrings.of(context).contributors()), + ), + ), + PopupMenuItem( + value: x.id.toString() + "\u{1E}" + "BoughtList", + child: ListTile( + leading: const Icon(Icons.history), + title: Text(NSSLStrings.of(context).boughtProducts()), + // NSSLStrings.of(context)!.contributors()), + ), + ), + //Deactivated, because it's not working at the moment + // PopupMenuItem( + // value: x.id.toString() + "\u{1E}" + 'ExportAsPdf', + // child: ListTile( + // leading: const Icon(Icons.picture_as_pdf), + // title: Text(NSSLStrings.of(context)!.exportAsPdf())), + // ), + PopupMenuItem( + value: x.id.toString() + "\u{1E}" + 'Rename', + child: ListTile( + leading: const Icon(Icons.mode_edit), + title: Text(NSSLStrings.of(context).rename()), + ), + ), + PopupMenuItem( + value: x.id.toString() + "\u{1E}" + 'Auto-Sync', + child: ListTile( + leading: Icon( + x.messagingEnabled + ? Icons.check_box + : Icons.check_box_outline_blank, + ), + title: Text(NSSLStrings.of(context).autoSync()), + ), + ), + const PopupMenuDivider(), + PopupMenuItem( + value: x.id.toString() + "\u{1E}" + 'Remove', + child: ListTile( + leading: const Icon(Icons.delete), + title: Text(NSSLStrings.of(context).remove()), + ), + ), + ], + ), + ), + ) + .toList() : [ - ListTile(title: Text(NSSLStrings.of(context).noListsInDrawerMessage())), + ListTile( + title: Text(NSSLStrings.of(context).noListsInDrawerMessage()), + ), ]; var d = Scaffold( - body: RefreshIndicator( - child: ListView( - controller: _drawerController, + body: RefreshIndicator( + child: ListView( + controller: _drawerController, + children: [ + userheader, + Stack( children: [ - userheader, - Stack( - children: [ - FadeTransition( - opacity: _drawerContentsOpacity!, - child: Column(children: list), - ), - SlideTransition( - position: _drawerDetailsPosition!, - child: FadeTransition( - opacity: ReverseAnimation(_drawerContentsOpacity!), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - ListTile( - leading: const Icon(Icons.sync), - title: Text(NSSLStrings.of(context).refresh()), - onTap: () => _handleDrawerRefresh(), - ), - ListTile( - leading: const Icon(Icons.restore_page_outlined), - title: Text( - NSSLStrings.of(context).changePasswordPD(), - ), - onTap: () => selectedOption("ChangePassword"), - ), - ListTile( - leading: const Icon(Icons.exit_to_app), - title: Text(NSSLStrings.of(context).logout()), - onTap: () async { - await _logout(); - }, - ) - ], + FadeTransition( + opacity: _drawerContentsOpacity!, + child: Column(children: list), + ), + SlideTransition( + position: _drawerDetailsPosition!, + child: FadeTransition( + opacity: ReverseAnimation(_drawerContentsOpacity!), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ListTile( + leading: const Icon(Icons.sync), + title: Text(NSSLStrings.of(context).refresh()), + onTap: () => _handleDrawerRefresh(), ), - ), + ListTile( + leading: const Icon(Icons.restore_page_outlined), + title: Text( + NSSLStrings.of(context).changePasswordPD(), + ), + onTap: () => selectedOption("ChangePassword"), + ), + ListTile( + leading: const Icon(Icons.exit_to_app), + title: Text(NSSLStrings.of(context).logout()), + onTap: () async { + await _logout(); + }, + ), + ], ), - ], + ), ), ], - physics: AlwaysScrollableScrollPhysics(), ), - onRefresh: _handleDrawerRefresh, - displacement: 1.0), - persistentFooterButtons: [ - TextButton(child: Text(NSSLStrings.of(context).addListPB()), onPressed: chooseListToAddDialog) - ]); + ], + physics: AlwaysScrollableScrollPhysics(), + ), + onRefresh: _handleDrawerRefresh, + displacement: 1.0, + ), + persistentFooterButtons: [ + TextButton( + child: Text(NSSLStrings.of(context).addListPB()), + onPressed: chooseListToAddDialog, + ), + ], + ); return Drawer(child: d); } @@ -608,48 +774,62 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi int id = int.parse(splitted[0]); switch (splitted[1]) { case "Contributors": - Navigator.maybeOf(context)?.push(MaterialPageRoute( - builder: (BuildContext context) => ContributorsPage(id), - fullscreenDialog: true, - )); + Navigator.maybeOf(context)?.push( + MaterialPageRoute( + builder: (BuildContext context) => ContributorsPage(id), + fullscreenDialog: true, + ), + ); break; case "BoughtList": await Navigator.push( - context, - MaterialPageRoute( - builder: (BuildContext context) => BoughtItemsPage(id), - fullscreenDialog: true, - )); + context, + MaterialPageRoute( + builder: (BuildContext context) => BoughtItemsPage(id), + fullscreenDialog: true, + ), + ); break; case "Rename": renameListDialog(id); break; case "Remove": - var deleteList = ref.read(shoppingListByIdProvider.create(id)); + var deleteList = ref.read(shoppingListByIdProvider(id)); if (deleteList == null) return; var cont = context; showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => SimpleDialogAcceptDeny.create( + title: NSSLStrings.of(context).deleteListTitle() + deleteList.name, + text: NSSLStrings.of(context).deleteListText(), + onSubmitted: (s) async { + var res = Result.fromJson( + (await ShoppingListSync.deleteList(id, context)).body, + ); + if (!(res.success)) + showInDrawerSnackBar(res.error); + else { + var currentList = ref.read(currentListProvider); + var shoppingListController = ref.read(shoppingListsProvider); + if (currentList == null || currentList.id == id) { + var other = shoppingListController.shoppingLists.firstOrNull( + (l) => l.id != id, + ); + if (other != null) + changeCurrentList( + shoppingListController.shoppingLists.indexOf(other), + ); + } + shoppingListController.removeList(deleteList.id); + showInDrawerSnackBar( + deleteList.name + " " + NSSLStrings.of(cont).removed(), + ); + } + }, context: context, - barrierDismissible: false, - builder: (BuildContext context) => SimpleDialogAcceptDeny.create( - title: NSSLStrings.of(context).deleteListTitle() + deleteList.name, - text: NSSLStrings.of(context).deleteListText(), - onSubmitted: (s) async { - var res = Result.fromJson((await ShoppingListSync.deleteList(id, context)).body); - if (!(res.success)) - showInDrawerSnackBar(res.error); - else { - var currentList = ref.read(currentListProvider); - var shoppingListController = ref.read(shoppingListsProvider); - if (currentList == null || currentList.id == id) { - var other = shoppingListController.shoppingLists.firstOrNull((l) => l.id != id); - if (other != null) changeCurrentList(shoppingListController.shoppingLists.indexOf(other)); - } - shoppingListController.removeList(deleteList.id); - showInDrawerSnackBar(deleteList.name + " " + NSSLStrings.of(cont).removed()); - } - }, - context: context)); + ), + ); break; case "Auto-Sync": var shoppingListController = ref.read(shoppingListsProvider); @@ -658,7 +838,10 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi break; case "ExportAsPdf": ExportManager.exportAsPDF( - ref.read(shoppingListByIdProvider.create(id))!, ref.read(shoppingItemsPerListProvider.create(id)), context); + ref.read(shoppingListByIdProvider(id))!, + ref.read(shoppingItemsPerListProvider(id)), + context, + ); break; } } @@ -670,21 +853,34 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi Future _handleMainListRefresh(int id) => _handleListRefresh(id); Future _handleListRefresh(int listId) async { - await ref.read(shoppingListsProvider).refresh(ref.read(shoppingListByIdProvider.create(listId))!); + await ref + .read(shoppingListsProvider) + .refresh(ref.read(shoppingListByIdProvider(listId))!); } Future shoppingItemChange(ShoppingItem s, int change) async { var res = ChangeListItemResult.fromJson( - (await ShoppingListSync.changeProductAmount(s.listId, s.id, change, context)).body); + (await ShoppingListSync.changeProductAmount( + s.listId, + s.id, + change, + context, + )).body, + ); if (!res.success) return; - s.exchange(s.cloneWith(newAmount: res.amount, newChanged: res.changed), ref); + s.exchange( + s.cloneWith(newAmount: res.amount, newChanged: res.changed), + ref, + ); } var amountPopList = >[]; List> buildChangeMenuItems(BuildContext context) { if (amountPopList.length == 0) for (int i = 1; i <= 99; i++) - amountPopList.add(PopupMenuItem(value: i.toString(), child: Text(i.toString()))); + amountPopList.add( + PopupMenuItem(value: i.toString(), child: Text(i.toString())), + ); return amountPopList; } @@ -698,14 +894,16 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi void _addWithoutSearchDialog(BuildContext extContext) { showDialog( - context: extContext, - barrierDismissible: false, - builder: (BuildContext context) => SimpleDialogSingleInput.create( - context: context, - title: NSSLStrings.of(context).addProduct(), - hintText: NSSLStrings.of(context).addProductWithoutSearch(), - labelText: NSSLStrings.of(context).productName(), - onSubmitted: _addWithoutSearch)); + context: extContext, + barrierDismissible: false, + builder: (BuildContext context) => SimpleDialogSingleInput.create( + context: context, + title: NSSLStrings.of(context).addProduct(), + hintText: NSSLStrings.of(context).addProductWithoutSearch(), + labelText: NSSLStrings.of(context).productName(), + onSubmitted: _addWithoutSearch, + ), + ); } Future renameList(int id, String text) async { @@ -718,26 +916,42 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi } Future _addWithoutSearch(String value) async { + if (value.isEmpty) return; var list = ref.read(currentListProvider); if (list == null) return; var shoppingItems = ref.read(currentShoppingItemsProvider); - var same = shoppingItems.firstOrNull((x) => x.name.toLowerCase() == value.toLowerCase()); + var same = shoppingItems.firstOrNull( + (x) => x.name.toLowerCase() == value.toLowerCase(), + ); if (same != null) { - var res = await ShoppingListSync.changeProductAmount(list.id, same.id, 1, context); + var res = await ShoppingListSync.changeProductAmount( + list.id, + same.id, + 1, + context, + ); if (res.statusCode != 200) showInSnackBar(res.reasonPhrase!); var product = ChangeListItemResult.fromJson(res.body); if (!product.success) showInSnackBar(product.error); same.exchange( - same.cloneWith( - newAmount: product.amount, - newChanged: product.changed, - newId: product.id, - newName: product.name, - newListId: product.listId), - ref); + same.cloneWith( + newAmount: product.amount, + newChanged: product.changed, + newId: product.id, + newName: product.name, + newListId: product.listId, + ), + ref, + ); } else { - var res = await ShoppingListSync.addProduct(list.id, value, null, 1, context); + var res = await ShoppingListSync.addProduct( + list.id, + value, + null, + 1, + context, + ); if (res.statusCode != 200) showInSnackBar(res.reasonPhrase!); var product = AddListItemResult.fromJson(res.body); if (!product.success) showInSnackBar(product.error); @@ -746,7 +960,16 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi var order = 0; if (shoppingItems.length > 0) order = shoppingItems.last.sortOrder + 1; - newState.add(ShoppingItem(product.name, list.id, order, id: product.productId, amount: 1, crossedOut: false)); + newState.add( + ShoppingItem( + product.name, + list.id, + order, + id: product.productId, + amount: 1, + crossedOut: false, + ), + ); sips.state = newState; } var listProv = ref.watch(shoppingListsProvider); @@ -759,7 +982,11 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi var shoppingList = ref.read(currentShoppingItemsProvider); var sublist = shoppingList.where((s) => s.crossedOut).toList(); - var res = await ShoppingListSync.deleteProducts(list.id, sublist.map((s) => s.id).toList(), context); + var res = await ShoppingListSync.deleteProducts( + list.id, + sublist.map((s) => s.id).toList(), + context, + ); if (!Result.fromJson(res.body).success) return; var shoppingItemsState = ref.watch(shoppingItemsProvider.notifier); var newState = shoppingItemsState.state.toList(); @@ -769,70 +996,85 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi shoppingItemsState.state = newState; var listProv = ref.watch(shoppingListsProvider); listProv.save(list); - showInSnackBar(NSSLStrings.of(context).messageDeleteAllCrossedOut(), - duration: Duration(seconds: 10), - action: SnackBarAction( - label: NSSLStrings.of(context).undo(), - onPressed: () async { - var res = await ShoppingListSync.changeProducts( - list.id, sublist.map((s) => s.id).toList(), sublist.map((s) => s.amount).toList(), context); - var hashResult = HashResult.fromJson(res.body); - int ownHash = 0; - for (var item in sublist) ownHash += item.id + item.amount; - if (ownHash == hashResult.hash) { - var shoppingItemsState = ref.watch(shoppingItemsProvider.notifier); - var newState = shoppingItemsState.state.toList(); - newState.addAll(sublist); - shoppingItemsState.state = newState; - var listProv = ref.watch(shoppingListsProvider); - listProv.save(list); - } else - _handleListRefresh(list.id); - })); + showInSnackBar( + NSSLStrings.of(context).messageDeleteAllCrossedOut(), + duration: Duration(seconds: 10), + action: SnackBarAction( + label: NSSLStrings.of(context).undo(), + onPressed: () async { + var res = await ShoppingListSync.changeProducts( + list.id, + sublist.map((s) => s.id).toList(), + sublist.map((s) => s.amount).toList(), + context, + ); + var hashResult = HashResult.fromJson(res.body); + int ownHash = 0; + for (var item in sublist) ownHash += item.id + item.amount; + if (ownHash == hashResult.hash) { + var shoppingItemsState = ref.watch(shoppingItemsProvider.notifier); + var newState = shoppingItemsState.state.toList(); + newState.addAll(sublist); + shoppingItemsState.state = newState; + var listProv = ref.watch(shoppingListsProvider); + listProv.save(list); + } else + _handleListRefresh(list.id); + }, + ), + ); } renameListItem(ShoppingItem shoppingItem) { showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => SimpleDialogSingleInput.create( context: context, - barrierDismissible: false, - builder: (BuildContext context) => SimpleDialogSingleInput.create( - context: context, - title: NSSLStrings.of(context).renameListItem(), - hintText: NSSLStrings.of(context).renameListHint(), - labelText: NSSLStrings.of(context).renameListItemLabel(), - defaultText: shoppingItem.name, - maxLines: 2, - onSubmitted: (s) async { - var currentList = ref.read(currentListProvider); - if (currentList == null) return; - - var res = ChangeListItemResult.fromJson( - (await ShoppingListSync.changeProductName(currentList.id, shoppingItem.id, s, context)).body); - - var items = ref.watch(shoppingItemsProvider.notifier); - var newState = items.state.toList(); - var item = newState.firstWhere((x) => x.id == shoppingItem.id); - newState.remove(item); - newState.add( - item.cloneWith(newName: res.name), - ); - items.state = newState; - })); + title: NSSLStrings.of(context).renameListItem(), + hintText: NSSLStrings.of(context).renameListHint(), + labelText: NSSLStrings.of(context).renameListItemLabel(), + defaultText: shoppingItem.name, + maxLines: 2, + onSubmitted: (s) async { + var currentList = ref.read(currentListProvider); + if (currentList == null) return; + + var res = ChangeListItemResult.fromJson( + (await ShoppingListSync.changeProductName( + currentList.id, + shoppingItem.id, + s, + context, + )).body, + ); + + var items = ref.watch(shoppingItemsProvider.notifier); + var newState = items.state.toList(); + var item = newState.firstWhere((x) => x.id == shoppingItem.id); + newState.remove(item); + newState.add(item.cloneWith(newName: res.name)); + items.state = newState; + }, + ), + ); } Widget? acceptReordingFAB() { var isReordering = ref.watch(_isReorderingProvider); if (!isReordering) return null; return FloatingActionButton( - child: Icon( - Icons.check, - ), + child: Icon(Icons.check), onPressed: () async { var reorderingState = ref.watch(_isReorderingProvider.notifier); reorderingState.state = false; var currentList = ref.read(currentListProvider); var ids = ref.read(currentShoppingItemsProvider); - await ShoppingListSync.reorderProducts(currentList!.id, ids.map((e) => e.id).toList(), context); + await ShoppingListSync.reorderProducts( + currentList!.id, + ids.map((e) => e.id).toList(), + context, + ); }, ); } @@ -853,37 +1095,30 @@ class MainPageState extends ConsumerState with TickerProviderStateMixi // }, // icon: Icon(Icons.settings)), PopupMenuButton( - onSelected: selectedOption, - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - value: 'deleteCrossedOut', - child: Text( - NSSLStrings.of(context).deleteCrossedOutPB(), - ), - ), - PopupMenuItem( - value: 'reorderItems', - child: Text( - NSSLStrings.of(context).reorderItems(), - ), - ), - PopupMenuItem( - value: 'recipeImport', - child: Text(NSSLStrings.of(context).importNewRecipe()), - ), - PopupMenuItem( - value: 'options', - child: Text( - NSSLStrings.of(context).options(), - ), - ), - PopupMenuItem( - value: 'logout', - child: Text( - NSSLStrings.of(context).logout(), - ), - ), - ]) + onSelected: selectedOption, + itemBuilder: (BuildContext context) => >[ + PopupMenuItem( + value: 'deleteCrossedOut', + child: Text(NSSLStrings.of(context).deleteCrossedOutPB()), + ), + PopupMenuItem( + value: 'reorderItems', + child: Text(NSSLStrings.of(context).reorderItems()), + ), + PopupMenuItem( + value: 'recipeImport', + child: Text(NSSLStrings.of(context).importNewRecipe()), + ), + PopupMenuItem( + value: 'options', + child: Text(NSSLStrings.of(context).options()), + ), + PopupMenuItem( + value: 'logout', + child: Text(NSSLStrings.of(context).logout()), + ), + ], + ), ]; } } @@ -896,7 +1131,11 @@ class ShoppingListWidget extends ConsumerWidget { final MainPageState mainPageState; const ShoppingListWidget(this.mainPageState, {Key? key}) : super(key: key); - void updateOrderIndiciesAndSave(ShoppingList currentList, List shoppingItems, WidgetRef ref) async { + void updateOrderIndiciesAndSave( + ShoppingList currentList, + List shoppingItems, + WidgetRef ref, + ) async { // var newItems = []; // var curSortOrder = 0; // for (var i = 0; i < shoppingItems.length; i++) { @@ -923,31 +1162,41 @@ class ShoppingListWidget extends ConsumerWidget { var shoppingItems = ref.watch(currentShoppingItemsProvider); if (shoppingItems.isEmpty) return const Text(""); - if (shoppingItems.any((item) => item.sortOrder == -1)) updateOrderIndiciesAndSave(currentList, shoppingItems, ref); + if (shoppingItems.any((item) => item.sortOrder == -1)) + updateOrderIndiciesAndSave(currentList, shoppingItems, ref); shoppingItems.sort((a, b) => a.sortWithOffset.compareTo(b.sortWithOffset)); var lv; if (shoppingItems.length > 0) { final isReorderingItems = ref.watch(_isReorderingProvider); - var mainList = shoppingItems.map((x) { - return getListTileForShoppingItem(x, isReorderingItems, context); - }).toList(growable: true); + var mainList = shoppingItems + .map((x) { + return getListTileForShoppingItem(x, isReorderingItems, context); + }) + .toList(growable: true); if (isReorderingItems) { lv = ReorderableListView( - onReorder: mainPageState._onReorderItems, scrollDirection: Axis.vertical, children: mainList); + onReorder: mainPageState._onReorderItems, + scrollDirection: Axis.vertical, + children: mainList, + ); } else { lv = CustomScrollView( controller: mainPageState._mainController, slivers: [ SliverFixedExtentList( - delegate: SliverChildBuilderDelegate((BuildContext context, int index) { - return Container( - alignment: FractionalOffset.center, - child: mainList[index], - ); - }, childCount: mainList.length), - itemExtent: 50.0) + delegate: SliverChildBuilderDelegate(( + BuildContext context, + int index, + ) { + return Container( + alignment: FractionalOffset.center, + child: mainList[index], + ); + }, childCount: mainList.length), + itemExtent: 50.0, + ), ], physics: AlwaysScrollableScrollPhysics(), ); @@ -963,8 +1212,12 @@ class ShoppingListWidget extends ConsumerWidget { ); } - Widget getListTileForShoppingItem(ShoppingItem? x, bool isReorderingItems, BuildContext context) { - if (x == null || x.name == "") return Text("Null"); + Widget getListTileForShoppingItem( + ShoppingItem? x, + bool isReorderingItems, + BuildContext context, + ) { + if (x == null) return Container(); // return Text(x.name!); var lt = ListTile( @@ -972,28 +1225,39 @@ class ShoppingListWidget extends ConsumerWidget { title: Wrap( children: [ Text( - x.name, + x.cleanedName, maxLines: 2, softWrap: true, - style: TextStyle(decoration: x.crossedOut ? TextDecoration.lineThrough : TextDecoration.none), + style: TextStyle( + decoration: x.crossedOut + ? TextDecoration.lineThrough + : TextDecoration.none, + ), ), ], ), leading: PopupMenuButton( child: FittedBox( - child: Row(children: [ - Text(x.amount.toString() + "x"), - const Icon(Icons.expand_more, size: 16.0), - SizedBox(height: 38.0), //for larger clickable size (2 Lines) - ]), + child: Row( + children: [ + Text(x.amount.toString() + "x"), + const Icon(Icons.expand_more, size: 16.0), + SizedBox(height: 38.0), //for larger clickable size (2 Lines) + ], + ), ), initialValue: x.amount.toString(), - onSelected: (y) => mainPageState.shoppingItemChange(x, int.parse(y) - x.amount), + onSelected: (y) => + mainPageState.shoppingItemChange(x, int.parse(y) - x.amount), itemBuilder: mainPageState.buildChangeMenuItems, ), trailing: isReorderingItems ? Icon(Icons.reorder) : null, - onTap: isReorderingItems ? null : (() => mainPageState.crossOutMainListItem(x)), - onLongPress: isReorderingItems ? null : (() => mainPageState.renameListItem(x)), + onTap: isReorderingItems + ? null + : (() => mainPageState.crossOutMainListItem(x)), + onLongPress: isReorderingItems + ? null + : (() => mainPageState.renameListItem(x)), ); if (isReorderingItems) { @@ -1002,14 +1266,17 @@ class ShoppingListWidget extends ConsumerWidget { return Dismissible( key: ValueKey(x), child: lt, - onDismissed: (DismissDirection d) => mainPageState.handleDismissMain(d, x), + onDismissed: (DismissDirection d) => + mainPageState.handleDismissMain(d, x), direction: DismissDirection.startToEnd, background: Container( decoration: BoxDecoration(color: Theme.of(context).primaryColor), child: ListTile( - leading: Icon(Icons.delete, - // color: Theme.of(context).accentIconTheme.color, - size: 36.0), + leading: Icon( + Icons.delete, + // color: Theme.of(context).accentIconTheme.color, + size: 36.0, + ), ), ), ); diff --git a/lib/pages/pages.dart b/lib/pages/pages.dart index d80328e..ab6941e 100644 --- a/lib/pages/pages.dart +++ b/lib/pages/pages.dart @@ -9,5 +9,4 @@ export 'custom_theme_page.dart'; export 'change_password.dart'; export 'bought_items.dart'; export 'main_page.dart'; -export 'settings.dart'; -export 'about.dart'; \ No newline at end of file +export 'about.dart'; diff --git a/lib/pages/product_add_to_database.dart b/lib/pages/product_add_to_database.dart index c0aa26c..81f0b80 100644 --- a/lib/pages/product_add_to_database.dart +++ b/lib/pages/product_add_to_database.dart @@ -8,11 +8,7 @@ import 'package:nssl/server_communication/return_classes.dart'; import 'package:nssl/server_communication/s_c.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -enum DismissDialogAction { - cancel, - discard, - save, -} +enum DismissDialogAction { cancel, discard, save } class AddProductToDatabase extends ConsumerStatefulWidget { AddProductToDatabase(this.gtin); @@ -43,25 +39,29 @@ class AddProductToDatabaseState extends ConsumerState { Future _onWillPop() async { if (!_saveNeeded) return true; - final ThemeData theme = Theme.of(context); - final TextStyle dialogTextStyle = theme.textTheme.subtitle1!.copyWith(color: theme.textTheme.caption!.color); + // final ThemeData theme = Theme.of(context); return await (showDialog( - context: context, - builder: (BuildContext context) => AlertDialog( - content: Text(NSSLStrings.of(context).discardNewProduct(), style: dialogTextStyle), - actions: [ - TextButton( - child: Text(NSSLStrings.of(context).cancelButton()), - onPressed: () { - Navigator.of(context).pop(false); - }), - TextButton( - child: Text(NSSLStrings.of(context).discardButton()), - onPressed: () { - Navigator.of(context).pop(true); - }) - ])) as FutureOr?) ?? + context: context, + builder: (BuildContext context) => AlertDialog( + content: Text(NSSLStrings.of(context).discardNewProduct()), + actions: [ + TextButton( + child: Text(NSSLStrings.of(context).cancelButton()), + onPressed: () { + Navigator.of(context).pop(false); + }, + ), + TextButton( + child: Text(NSSLStrings.of(context).discardButton()), + onPressed: () { + Navigator.of(context).pop(true); + }, + ), + ], + ), + ) + as FutureOr?) ?? false; } @@ -93,7 +93,13 @@ class AddProductToDatabaseState extends ConsumerState { unit = weight!.substring(match!.start, match.end); } _isSendToServer = true; - var first = (await ProductSync.addNewProduct("$productName $brandName", gtin, realWeight, unit, context)); + var first = (await ProductSync.addNewProduct( + "$productName $brandName", + gtin, + realWeight, + unit, + context, + )); if (first.statusCode != 200) { showInSnackBar(first.reasonPhrase!); _isSendToServer = false; @@ -107,7 +113,14 @@ class AddProductToDatabaseState extends ConsumerState { if (putInList) { var list = ref.read(currentListProvider)!; var pres = AddListItemResult.fromJson( - (await ShoppingListSync.addProduct(list.id, "$productName $brandName $weight", gtin, 1, context)).body); + (await ShoppingListSync.addProduct( + list.id, + "$productName $brandName $weight", + gtin, + 1, + context, + )).body, + ); if (!pres.success) showInSnackBar(pres.error); else { @@ -115,10 +128,19 @@ class AddProductToDatabaseState extends ConsumerState { var shoppingItems = ref.read(currentShoppingItemsProvider); int sortOrder = 0; - if (shoppingItems.length > 0) sortOrder = shoppingItems.last.sortOrder + 1; + if (shoppingItems.length > 0) + sortOrder = shoppingItems.last.sortOrder + 1; listController.addSingleItem( - list, ShoppingItem(pres.name, list.id, sortOrder, amount: 1, id: pres.productId)); + list, + ShoppingItem( + pres.name, + list.id, + sortOrder, + amount: 1, + id: pres.productId, + ), + ); } _isSendToServer = false; Navigator.of(context).pop(); @@ -135,69 +157,93 @@ class AddProductToDatabaseState extends ConsumerState { return Scaffold( key: _scaffoldKey, - appBar: AppBar(title: Text(NSSLStrings.of(context).newProductTitle()), actions: [ - TextButton( - child: Text(NSSLStrings.of(context).saveButton(), - style: theme.textTheme.bodyText2!.copyWith(color: Colors.white)), - onPressed: () => _handleSubmitted()) - ]), + appBar: AppBar( + title: Text(NSSLStrings.of(context).newProductTitle()), + actions: [ + TextButton( + child: Text(NSSLStrings.of(context).saveButton()), + onPressed: () => _handleSubmitted(), + ), + ], + ), body: Form( - key: _formKey, - onWillPop: _onWillPop, - autovalidateMode: validateMode, - child: ListView(padding: const EdgeInsets.all(16.0), children: [ + key: _formKey, + onWillPop: _onWillPop, + autovalidateMode: validateMode, + child: ListView( + padding: const EdgeInsets.all(16.0), + children: [ Container( - child: TextFormField( - decoration: InputDecoration( - labelText: NSSLStrings.of(context).newProductName(), - hintText: NSSLStrings.of(context).newProductNameHint(), - ), - autofocus: true, - controller: tecProductName, - onSaved: (s) => productName = s, - validator: _validateName)), + child: TextFormField( + decoration: InputDecoration( + labelText: NSSLStrings.of(context).newProductName(), + hintText: NSSLStrings.of(context).newProductNameHint(), + ), + autofocus: true, + controller: tecProductName, + onSaved: (s) => productName = s, + validator: _validateName, + ), + ), Container( - child: TextFormField( - decoration: InputDecoration( - labelText: NSSLStrings.of(context).newProductBrandName(), - hintText: NSSLStrings.of(context).newProductBrandNameHint()), - autofocus: false, - controller: tecBrandName, - onSaved: (s) => brandName = s, - validator: _validateName)), + child: TextFormField( + decoration: InputDecoration( + labelText: NSSLStrings.of(context).newProductBrandName(), + hintText: NSSLStrings.of(context).newProductBrandNameHint(), + ), + autofocus: false, + controller: tecBrandName, + onSaved: (s) => brandName = s, + validator: _validateName, + ), + ), Container( - child: TextFormField( - decoration: InputDecoration( - labelText: NSSLStrings.of(context).newProductWeight(), - hintText: NSSLStrings.of(context).newProductWeightHint()), - autofocus: false, - onSaved: (s) => weight = s, - controller: tecPackagingSize)), + child: TextFormField( + decoration: InputDecoration( + labelText: NSSLStrings.of(context).newProductWeight(), + hintText: NSSLStrings.of(context).newProductWeightHint(), + ), + autofocus: false, + onSaved: (s) => weight = s, + controller: tecPackagingSize, + ), + ), Container( - padding: const EdgeInsets.symmetric(vertical: 8.0), - decoration: BoxDecoration(border: Border(bottom: BorderSide(color: theme.dividerColor))), - alignment: FractionalOffset.bottomLeft, - child: Text(NSSLStrings.of(context).codeText() + gtin!)), + padding: const EdgeInsets.symmetric(vertical: 8.0), + decoration: BoxDecoration( + border: Border(bottom: BorderSide(color: theme.dividerColor)), + ), + alignment: FractionalOffset.bottomLeft, + child: Text(NSSLStrings.of(context).codeText() + gtin!), + ), Container( - padding: const EdgeInsets.symmetric(vertical: 8.0), - alignment: FractionalOffset.bottomLeft, - child: Row(children: [ + padding: const EdgeInsets.symmetric(vertical: 8.0), + alignment: FractionalOffset.bottomLeft, + child: Row( + children: [ Text(NSSLStrings.of(context).newProductAddToList()), - Checkbox(value: putInList, onChanged: (b) => setState(() => putInList = !putInList)) - ])), + Checkbox( + value: putInList, + onChanged: (b) => setState(() => putInList = !putInList), + ), + ], + ), + ), Container( padding: const EdgeInsets.symmetric(vertical: 8.0), - child: - Text(NSSLStrings.of(context).newProductStarExplanation(), style: Theme.of(context).textTheme.caption), + child: Text(NSSLStrings.of(context).newProductStarExplanation()), ), - ])), + ], + ), + ), ); } String? _validateName(String? value) { _saveNeeded = true; if (value!.isEmpty) return NSSLStrings.of(context).fieldRequiredError(); - if (value.length < 3) return NSSLStrings.of(context).newProductNameToShort(); + if (value.length < 3) + return NSSLStrings.of(context).newProductNameToShort(); return null; } diff --git a/lib/pages/registration.dart b/lib/pages/registration.dart index 0a5e463..6a8fc7a 100644 --- a/lib/pages/registration.dart +++ b/lib/pages/registration.dart @@ -95,8 +95,8 @@ class RegistrationState extends ConsumerState { String? _validatePassword(String? value) { var errorCode = PasswordService.checkNewPassword(value ?? ""); + String errorText = ""; if (errorCode != PasswordErrorCode.none) { - String errorText = ""; switch (errorCode) { case PasswordErrorCode.empty: return NSSLStrings.of(context).passwordEmptyError(); @@ -108,6 +108,7 @@ class RegistrationState extends ConsumerState { return NSSLStrings.of(context).passwordMissingCharactersError(); } } + return errorText; } String? _validatePassword2(String? value) { diff --git a/lib/server_communication/helper_methods.dart b/lib/server_communication/helper_methods.dart index 4638603..2f70953 100644 --- a/lib/server_communication/helper_methods.dart +++ b/lib/server_communication/helper_methods.dart @@ -6,6 +6,7 @@ import 'dart:convert'; import 'dart:async'; import 'package:nssl/models/model_export.dart'; import 'package:nssl/server_communication/jwt.dart'; +import 'package:uuid/uuid.dart'; import 'user_sync.dart'; class HelperMethods { @@ -14,41 +15,78 @@ class HelperMethods { static const int port = 443; // static const String scheme = "http"; // static const String host = "192.168.49.22"; + // static const int port = 4344; // static const String url = "http://192.168.49.22:4344"; + static final String deviceToken = Uuid().v7(); - static Future post(String path, BuildContext? context, - [Object? body, skipTokenRefresh = false, Map? query]) async { + static Future post( + String path, + BuildContext? context, [ + Object? body, + skipTokenRefresh = false, + Map? query, + ]) async { if (!skipTokenRefresh) await handleTokenRefresh(context); var res = await http.post( - Uri(host: host, scheme: scheme, path: path, port: port, queryParameters: query /*, port: 4344*/), - body: jsonEncode(body), - headers: {"Content-Type": "application/json", User.token == "" ? "X-foo" : "X-Token": User.token}); + Uri( + host: host, + scheme: scheme, + path: path, + port: port, + queryParameters: query /*, port: 4344*/, + ), + body: jsonEncode(body), + headers: _getHeaders(), + ); reactToRespone(res, context); return res; } - static Future get(String path, BuildContext? context, [String query = ""]) async { + static Future get( + String path, + BuildContext? context, [ + String query = "", + ]) async { await handleTokenRefresh(context); - var res = await http.get(Uri(host: host, scheme: scheme, path: path, query: query, port: port /*, port: 4344*/), - headers: {"Content-Type": "application/json", User.token == "" ? "X-foo" : "X-Token": User.token}); + var res = await http.get( + Uri( + host: host, + scheme: scheme, + path: path, + query: query, + port: port /*, port: 4344*/, + ), + headers: _getHeaders(), + ); reactToRespone(res, context); return res; } - static Future put(String path, BuildContext? context, - [Object? body, bool skipTokenRefresh = false]) async { + static Future put( + String path, + BuildContext? context, [ + Object? body, + bool skipTokenRefresh = false, + ]) async { if (!skipTokenRefresh) await handleTokenRefresh(context); - var res = await http.put(Uri(host: host, scheme: scheme, path: path, port: port /*, port: 4344*/), - body: jsonEncode(body), - headers: {"Content-Type": "application/json", User.token == "" ? "X-foo" : "X-Token": User.token}); + var res = await http.put( + Uri(host: host, scheme: scheme, path: path, port: port /*, port: 4344*/), + body: jsonEncode(body), + headers: _getHeaders(), + ); reactToRespone(res, context); return res; } - static Future delete(String path, BuildContext? context) async { + static Future delete( + String path, + BuildContext? context, + ) async { await handleTokenRefresh(context); - var res = await http.delete(Uri(host: host, scheme: scheme, path: path, port: port /*, port: 4344*/), - headers: {"Content-Type": "application/json", User.token == "" ? "X-foo" : "X-Token": User.token}); + var res = await http.delete( + Uri(host: host, scheme: scheme, path: path, port: port /*, port: 4344*/), + headers: _getHeaders(), + ); reactToRespone(res, context); return res; @@ -59,27 +97,40 @@ class HelperMethods { print(jsonString); } - static bool reactToRespone(http.Response respone, BuildContext? context, {ScaffoldState? scaffoldState}) { + static Map _getHeaders() { + return { + "DeviceToken": deviceToken, + "Content-Type": "application/json", + User.token == "" ? "X-foo" : "X-Token": User.token, + }; + } + + static bool reactToRespone( + http.Response respone, + BuildContext? context, { + ScaffoldState? scaffoldState, + }) { if (context == null) return false; if (respone.statusCode == 500) { throw Exception(); } else if (respone.statusCode == 401) { showDialog( - builder: (BuildContext context) { - return AlertDialog( - title: Text(NSSLStrings.of(context).tokenExpired()), - content: Text(NSSLStrings.of(context).tokenExpiredExplanation()), - actions: [ - MaterialButton( - onPressed: () async { - Navigator.pushReplacementNamed(context, "/login"); - }, - child: const Text("OK"), - ) - ], - ); - }, - context: context); + builder: (BuildContext context) { + return AlertDialog( + title: Text(NSSLStrings.of(context).tokenExpired()), + content: Text(NSSLStrings.of(context).tokenExpiredExplanation()), + actions: [ + MaterialButton( + onPressed: () async { + Navigator.pushReplacementNamed(context, "/login"); + }, + child: const Text("OK"), + ), + ], + ); + }, + context: context, + ); } return true; } diff --git a/lib/server_communication/s_c.dart b/lib/server_communication/s_c.dart index d8cb77f..8c43121 100644 --- a/lib/server_communication/s_c.dart +++ b/lib/server_communication/s_c.dart @@ -1,6 +1,5 @@ export 'helper_methods.dart'; export 'request_classes.dart'; -export 'request_classes.dart'; export 'user_sync.dart'; export 'product_sync.dart'; export 'shopping_list_sync.dart'; \ No newline at end of file diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index f0bed44..d77a3c2 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,8 +8,8 @@ import Foundation import firebase_core import firebase_messaging import flutter_local_notifications -import path_provider_macos -import shared_preferences_macos +import path_provider_foundation +import shared_preferences_foundation import sqlite3_flutter_libs import url_launcher_macos diff --git a/pubspec.yaml b/pubspec.yaml index 947e625..80ce4b6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,10 +1,10 @@ name: nssl description: An app for handling shopping lists -version: 0.40.0+0 +version: 0.41.0+0 environment: - sdk: '>=2.12.0' + sdk: '>=3.8.0 <4.0.0' dependencies: flutter: @@ -15,10 +15,13 @@ dependencies: crypto: file: firebase_core: - firebase_messaging: + firebase_messaging: ^15.2.7 flutter_colorpicker: + flutter_hooks: flutter_local_notifications: + flutter_riverpod: ^3.0.0-dev.16 flutter_svg: + hooks_riverpod: ^3.0.0-dev.16 http: intl: path_provider: @@ -26,9 +29,14 @@ dependencies: pdf: permission_handler: process_run: - scandit_flutter_datacapture_barcode: 6.14.1 + riverpod_annotation: ^3.0.0-dev.16 + scandit_flutter_datacapture_barcode: ^7.4.0 + scandit_flutter_datacapture_core: ^7.4.0 + share_handler: ^0.0.8 shared_preferences: sqlite3_flutter_libs: + url_launcher: + uuid: # scandit_flutter_datacapture_barcode: ^6.7.0 # scandit_flutter_datacapture_core: ^6.7.0 # flutter_scandit: ^0.1.0 @@ -36,19 +44,17 @@ dependencies: # jwt: # git: git://github.com/susch19/dart-json_web_token.git #jaguar_jwt: "^1.1.5" - url_launcher: - share_handler: ^0.0.8 + riverpod: any + sqflite_common: any + sqflite_common_ffi: any dev_dependencies: - build_runner: ^2.0.6 - flutter_riverpod: 2.0.0-dev.8 - flutter_lints: ^2.0.1 + build_runner: + riverpod_lint: + riverpod_generator: ^3.0.0-dev.16 + flutter_lints: ^6.0.0 json_serializable: ^6.1.3 - sqflite_common_ffi: - git: - url: https://github.com/muhleder/sqflite.git - path: sqflite_common_ffi - ref: web + custom_lint: ^0.7.5 #git: https://github.com/tekartik/sqflite.git diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt index 744f08a..0a91777 100644 --- a/windows/flutter/CMakeLists.txt +++ b/windows/flutter/CMakeLists.txt @@ -9,6 +9,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -90,7 +95,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc index 82af8a6..6c07679 100644 --- a/windows/runner/Runner.rc +++ b/windows/runner/Runner.rc @@ -60,14 +60,14 @@ IDI_APP_ICON ICON "resources\\app_icon.ico" // Version // -#ifdef FLUTTER_BUILD_NUMBER -#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#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 +#define VERSION_AS_NUMBER 1,0,0,0 #endif -#ifdef FLUTTER_BUILD_NAME -#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION #else #define VERSION_AS_STRING "1.0.0" #endif