Skip to content

Commit

Permalink
Added possibility to add products from brought list (#11)
Browse files Browse the repository at this point in the history
* copied the iterable extensions from smarthome (maybe move this into a package in the future)
* added click on already brought items, that currently adds a copy of the selected entry to the list, from which the history is
* removed the nullable int amount, because it should never be null, as the amount always has a value
* removed unused imports
  • Loading branch information
susch19 authored Jan 6, 2022
1 parent e6791ab commit 0eb1c07
Show file tree
Hide file tree
Showing 19 changed files with 933 additions and 457 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ android/app/google-services.json
ios/Flutter/flutter_export_environment.sh
.dart_tool/*
android/app/src/main/java/io/flutter/plugins/*
lib/.license.dart
109 changes: 109 additions & 0 deletions lib/helper/iterable_extensions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
extension Linq<E> on List<E> {
bool removeElements(Iterable<E> elements) {
bool b = true;
for (var e in elements) {
if (!b) return b;
b = this.remove(e);
}
return b;
}

List<E> copy() {
List<E> items = [];
this.forEach((element) {
items.add(element);
});
return items;
}
}

extension MoreMath on double {
double clamp(double lower, double maximum) {
if (this <= lower) return lower;
if (this >= maximum) return maximum;
return this;
}
}

extension Maps<K, E> on Map<K, E> {
List<T> select<T>(T Function(K, E) keyFunction) {
var retList = <T>[];
for (var entry in this.entries) {
retList.add(keyFunction(entry.key, entry.value));
}
return retList;
}

MapEntry<K, E>? elementAt(int index, {MapEntry<K, E>? orElse}) {
int i = 0;
for (var el in this.entries) {
if (index == i) return el;
i++;
}
return orElse;
}
}

extension Iterables<E> on Iterable<E> {
Map<K, List<E>> groupBy<K>(K Function(E) keyFunction) => fold(
<K, List<E>>{},
(Map<K, List<E>> map, E element) =>
map..putIfAbsent(keyFunction(element), () => <E>[]).add(element));

Map<K, List<E>> groupManyBy<K>(List<K> Function(E) keyFunction) =>
fold(<K, List<E>>{}, (Map<K, List<E>> map, E element) {
for (var r in keyFunction(element)) {
map..putIfAbsent(r, () => <E>[]).add(element);
}
return map;
});

E? firstOrNull(bool Function(E element) keyFunction) {
for (var item in [...this]) {
if (keyFunction(item)) return item;
}
return null;
}

Iterable<E> injectForIndex(E? Function(int index) indexFunc) sync* {
int index = 0;
for (var item in [...this]) {
var res = indexFunc(index);
if (res != null) yield res;
yield item;
index++;
}
}

int sum(int Function(E element) keyFunction) {
int sum = 0;
for (var item in [...this]) {
sum += keyFunction(item);
}
return sum;
}

int bitOr(int Function(E element) keyFunction) {
int sum = 0;
for (var item in [...this]) {
sum |= keyFunction(item);
}
return sum;
}

int bitAnd(int Function(E element) keyFunction) {
int sum = 0;
for (var item in [...this]) {
sum &= keyFunction(item);
}
return sum;
}

int bitXor(int Function(E element) keyFunction) {
int sum = 0;
for (var item in [...this]) {
sum ^= keyFunction(item);
}
return sum;
}
}
1 change: 1 addition & 0 deletions lib/localization/nssl_messages_de.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class MessageLookup extends MessageLookupByLibrary {
"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"),
Expand Down
1 change: 1 addition & 0 deletions lib/localization/nssl_messages_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class MessageLookup extends MessageLookupByLibrary {
"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"),
Expand Down
389 changes: 249 additions & 140 deletions lib/localization/nssl_strings.dart

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import 'dart:ui';

import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:nssl/options/themes.dart';
import 'package:nssl/pages/pages.dart';
import 'package:nssl/manager/manager_export.dart';
Expand All @@ -30,7 +29,8 @@ Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// make sure you call `initializeApp` before using other Firebase services.
await Startup.initializeMinFunction();
//Startup.remoteMessages.add(message);
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));
}
Expand All @@ -45,8 +45,9 @@ Future<void> main() async {
else
return Container(color: Colors.green);
},
future: Startup.initialize()
.then((value) => FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler)),
future: Startup.initialize().then((value) =>
FirebaseMessaging.onBackgroundMessage(
_firebaseMessagingBackgroundHandler)),
));
}

Expand Down Expand Up @@ -95,7 +96,8 @@ class _NSSLState extends State<NSSLPage> {
// FirebaseMessaging.onBackgroundMessage((message) => CloudMessaging.onMessage(message, setState));
// firebaseMessaging.configure(
// onMessage: (x) => CloudMessaging.onMessage(x, setState), onLaunch: (x) => Startup.initialize());
for (var list in User.shoppingLists) if (list.messagingEnabled) list.subscribeForFirebaseMessaging();
for (var list in User.shoppingLists)
if (list.messagingEnabled) list.subscribeForFirebaseMessaging();
}

Future subscribeFirebase(BuildContext context) async {
Expand Down Expand Up @@ -145,7 +147,9 @@ class _NSSLState extends State<NSSLPage> {
}

Scaffold mainAppHome() => Scaffold(
key: _mainScaffoldKey, resizeToAvoidBottomInset: false, body: MainPage() //CustomThemePage()//LoginPage(),
key: _mainScaffoldKey,
resizeToAvoidBottomInset: false,
body: MainPage() //CustomThemePage()//LoginPage(),
);

Scaffold mainAppLoginRegister() => Scaffold(
Expand Down
31 changes: 19 additions & 12 deletions lib/models/shopping_item.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class TestClass{
class TestClass {
int test;
String? o;

Expand All @@ -9,13 +9,13 @@ class TestClass{

class ShoppingItem {
//extends JsonDecoder{
int? amount;
int amount = 1;
String? name;
int? id;
DateTime? created;
DateTime? changed;
DateTime? created;
DateTime? changed;
bool crossedOut = false;
int? sortOrder;
int? sortOrder;

ShoppingItem(this.name);

Expand All @@ -24,14 +24,21 @@ class ShoppingItem {
return name! + "\u{1F}" + amount.toString() + "\u{1F}" + id.toString();
}

ShoppingItem clone(){
/// Creates a copy, with only including [amount] and [name]
ShoppingItem copy() {
return ShoppingItem(name)..amount = amount;
}

/// Creates an identical clone, where all fields are the same as
/// the parent item
ShoppingItem clone() {
return ShoppingItem(name)
..amount=amount
..id=id
..created=created
..changed=changed
..crossedOut=crossedOut
..sortOrder=sortOrder;
..amount = amount
..id = id
..created = created
..changed = changed
..crossedOut = crossedOut
..sortOrder = sortOrder;
}

ShoppingItem.fromJson(String s) : name = s;
Expand Down
76 changes: 55 additions & 21 deletions lib/models/shopping_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,24 @@ class ShoppingList {

Future save() 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(?, ?, ?, ?)',
[id, name, messagingEnabled ? 1 : 0, User.ownId]);

await z.rawDelete("DELETE FROM ShoppingItems WHERE res_list_id = ? and id not in (?)", [id, shoppingItems!.map((e) => e!.id).join(",")]);
await z.rawDelete(
"DELETE FROM ShoppingItems WHERE res_list_id = ? and id not in (?)",
[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, id, item.sortOrder]);
[
item!.id,
item.name,
item.amount,
item.crossedOut ? 1 : 0,
id,
item.sortOrder
]);
}
});
}
Expand All @@ -39,18 +49,28 @@ class ShoppingList {
shoppingItems!.insert(index, item);
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, id, item.sortOrder]);
[
item.id,
item.name,
item.amount,
item.crossedOut ? 1 : 0,
id,
item.sortOrder
]);
}

Future deleteSingleItem(ShoppingItem item) async {
shoppingItems!.remove(item);
await DatabaseManager.database.rawDelete("DELETE FROM ShoppingItems WHERE id = ?", [item.id]);
await DatabaseManager.database
.rawDelete("DELETE FROM ShoppingItems WHERE id = ?", [item.id]);
}

static Future<List<ShoppingList>> load() async {
var lists = await DatabaseManager.database.rawQuery("SELECT * FROM ShoppingLists WHERE user_id = ?", [User.ownId]);
var lists = await DatabaseManager.database.rawQuery(
"SELECT * FROM ShoppingLists WHERE user_id = ?", [User.ownId]);

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");

// TODO: if db ordering enough for us, or do we want to order by ourself in code?
// return lists
Expand All @@ -75,7 +95,7 @@ class ShoppingList {
..shoppingItems = items
.where((y) => y["res_list_id"] == x["id"])
.map((y) => ShoppingItem(y["name"] as String?)
..amount = y["amount"] as int?
..amount = y["amount"] as int
..crossedOut = y["crossed"] == 0 ? false : true
..id = y["id"] as int?
..sortOrder = y["sortorder"] as int?)
Expand All @@ -95,8 +115,9 @@ class ShoppingList {
// }
var newList = GetListResult.fromJson(res.body);
List<Map<String, dynamic>> items;
items = (await DatabaseManager.database
.rawQuery("SELECT id, crossed, sortorder FROM ShoppingItems WHERE res_list_id = ?", [id]));
items = (await DatabaseManager.database.rawQuery(
"SELECT id, crossed, sortorder FROM ShoppingItems WHERE res_list_id = ?",
[id]));

shoppingItems!.clear();
for (var item in newList.products!)
Expand All @@ -105,23 +126,29 @@ class ShoppingList {
..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)
..sortOrder = item.sortOrder);

shoppingItems!.sort((a, b) => a!.sortOrder!.compareTo(b!.sortOrder!));
save();
}

static Future<Null> reloadAllLists([BuildContext? cont]) async {
var result = GetListsResult.fromJson((await ShoppingListSync.getLists(cont)).body);
var result =
GetListsResult.fromJson((await ShoppingListSync.getLists(cont)).body);
User.shoppingLists.clear();

await DatabaseManager.database.delete("ShoppingLists", where: "user_id = ?", whereArgs: [User.ownId]);
await DatabaseManager.database
.delete("ShoppingLists", where: "user_id = ?", whereArgs: [User.ownId]);
//await DatabaseManager.database.rawDelete("DELETE FROM ShoppingLists where user_id = ?", [User.ownId]);

List<Map<String, dynamic>> items;
items = (await DatabaseManager.database.rawQuery("SELECT id, crossed, sortorder FROM ShoppingItems"));
items = (await DatabaseManager.database
.rawQuery("SELECT id, crossed, sortorder FROM ShoppingItems"));

for (var res in result.shoppingLists) {
var list = ShoppingList(res.id, res.name);
Expand All @@ -130,14 +157,20 @@ class ShoppingList {
list.shoppingItems!.add(ShoppingItem(item.name)
..id = item.id
..amount = item.amount
..crossedOut =
(items.firstWhere((x) => x["id"] == item.id, orElse: () => {"crossed": 0})["crossed"] == 0 ? false : true)
..sortOrder = (items.firstWhere((x) => x["id"] == item.id, orElse: () => {"sortorder": 0})["sortorder"]));
..crossedOut = (items.firstWhere((x) => x["id"] == item.id,
orElse: () => {"crossed": 0})["crossed"] ==
0
? false
: true)
..sortOrder = (items.firstWhere((x) => x["id"] == item.id,
orElse: () => {"sortorder": 0})["sortorder"]));

if (list.shoppingItems!.any((element) => element!.sortOrder == null))
for (int i = 0; i < list.shoppingItems!.length; i++) list.shoppingItems![i]!.sortOrder = i;
for (int i = 0; i < list.shoppingItems!.length; i++)
list.shoppingItems![i]!.sortOrder = i;

list.shoppingItems!.sort((a, b) => a!.sortOrder!.compareTo(b!.sortOrder!));
list.shoppingItems!
.sort((a, b) => a!.sortOrder!.compareTo(b!.sortOrder!));
User.shoppingLists.add(list);

list.subscribeForFirebaseMessaging();
Expand All @@ -150,6 +183,7 @@ class ShoppingList {
}

void unsubscribeFromFirebaseMessaging() {
firebaseMessaging?.unsubscribeFromTopic(id.toString() + "shoppingListTopic");
firebaseMessaging
?.unsubscribeFromTopic(id.toString() + "shoppingListTopic");
}
}
Loading

0 comments on commit 0eb1c07

Please sign in to comment.