Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Reorder list items #16

Merged
merged 28 commits into from Aug 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2dbeb9f
Selected Store is now saved in state, added cupertinoActionSheet to l…
manderly Jul 11, 2020
ccb5f26
Safety checkin, working on restoring cross off/add to list functionality
manderly Jul 12, 2020
8094b2a
Progress on restoring cross off/make active feature
manderly Jul 12, 2020
d7ced72
Progress on restoring cross off functionality, had to stop using item…
manderly Jul 13, 2020
7569fcf
More work on moving items between the two lists
manderly Jul 15, 2020
671ff90
Work on restoring item streams for grocery items, changed itemCount t…
manderly Jul 16, 2020
8e30ded
Soft-removing _future and _sort attempts, working on restoring 'sort …
manderly Jul 16, 2020
e195398
Refactor for how 'Add new XYZ' is displayed to simplify it and make i…
manderly Jul 18, 2020
e64b62c
Minor cleanup
manderly Jul 18, 2020
8dc8fc0
Now storing date as a timestamp instead of a string on items, split g…
manderly Jul 18, 2020
808e2ea
List positions are now saved on item update
manderly Jul 18, 2020
28292a4
Fix for dates on new items, new database method for copying store IDs…
manderly Jul 18, 2020
bc98be0
Saving store sort choice to SharedPreferences and updating the saved …
manderly Jul 18, 2020
73b59bd
Now waits for store sort order to be retrieved from preferences befor…
manderly Jul 20, 2020
c7800aa
Moved settings drawer to its own method
manderly Jul 20, 2020
5a1c6f4
newly created shopping lists now get a position, added users collecti…
manderly Jul 20, 2020
f503a61
Reorder list experiment progress
manderly Jul 21, 2020
8f5c22e
Actual progress on reordering things. Works for shopping lists and st…
manderly Jul 28, 2020
57bede5
Progress towards sorting items
manderly Jul 28, 2020
225199d
listPosition is now a map on all entities, working on saving differen…
manderly Jul 29, 2020
d76b285
Progress on loading the saved/selected list's item order when enterin…
manderly Jul 29, 2020
64aa277
OrderBy storeID is causing trouble for store sorting, need to find an…
manderly Jul 30, 2020
672a72f
Newly created items are now given locations for every store associate…
manderly Jul 30, 2020
92cac26
Compacted the added by soandso on date text below each item name
manderly Jul 30, 2020
a9f04b0
Using async await to await the pop and refresh the state of the linke…
manderly Aug 11, 2020
290c3a7
Crossed Off section now hides when there's nothing crossed off yet
manderly Aug 11, 2020
d3166eb
New shopping list is now created with a default list location oof 100…
manderly Aug 12, 2020
ebf086f
Removing unused approaches
manderly Aug 27, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 1 addition & 13 deletions ios/Runner.xcodeproj/project.pbxproj
Expand Up @@ -10,11 +10,7 @@
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
39349FF5249D5936000395C6 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 39349FF4249D5936000395C6 /* GoogleService-Info.plist */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
Expand All @@ -28,8 +24,6 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -42,14 +36,12 @@
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
39349FF4249D5936000395C6 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
731D2264BADCA665B185C196 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
Expand All @@ -64,8 +56,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
E96888D942353715BF1C6FDC /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -76,9 +66,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
Expand Down Expand Up @@ -234,7 +222,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
6047C19B977F1153DFA1D9AA /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
Expand Down
2 changes: 1 addition & 1 deletion lib/components/add_new.dart
Expand Up @@ -15,7 +15,7 @@ class AddNew extends StatelessWidget {
} else if (listType == 'store') {
Navigator.pushNamed(context, '/newStore');
} else if (listType == 'item') {
final result = await Navigator.pushNamed(context, '/newItem', arguments: NewItemArguments(parentList.id, parentList.name));
await Navigator.pushNamed(context, '/newItem', arguments: NewItemArguments(parentList));
} else {
print('Error, unhandled listType in goToAddNew in item_list.dart');
}
Expand Down
57 changes: 25 additions & 32 deletions lib/components/item_list.dart
Expand Up @@ -3,62 +3,55 @@ import 'package:grocery_go/models/item.dart';
import 'package:grocery_go/models/shopping_list.dart';
import 'package:grocery_go/models/store.dart';

import 'add_new.dart';
import 'delete_all.dart';
import 'list_item.dart';

class ItemList extends StatelessWidget {
class ItemList extends StatefulWidget {

final List list;
final String listType;
final onItemTap;
final onInfoTap;
final ShoppingList parentList;

ItemList({Key key, @required this.list, @required this.listType, @required this.onItemTap, @required this.onInfoTap, this.parentList});
ItemList(
{Key key, @required this.list, @required this.listType, @required this.onItemTap, @required this.onInfoTap, this.parentList});

@override
State createState() => _ItemListState();
}

class _ItemListState extends State<ItemList> {

@override
Widget build(BuildContext context) {

int getCount(item) {
if (listType == 'shopping list') {
return item.itemCount;
if (widget.listType == 'shopping list') {
return item.activeItems;
} else {
return list.length;
return widget?.list?.length;
}
}

return ListView.builder(
key: widget.key,
shrinkWrap: true, // gives it a size
primary: false, // so the shopping and store lists don't scroll independently
itemCount: list.length + 1,
itemCount: widget?.list?.length ?? 0 + 1,
itemBuilder: (BuildContext context, int index) {
if (index == list.length) {
if (listType == 'crossedOff') {
return DeleteAll();
} else if (listType == 'store' || listType == 'shopping list') {
return AddNew(listType: listType);
} else if (listType == 'item') {
return AddNew(listType: listType, parentList: parentList);
} else {
return Text("Invalid list type");
}
var listItem;

if (widget.listType == 'shopping list') {
listItem = ShoppingList(widget.list[index]);
} else if (widget.listType == 'store') {
listItem = Store(widget.list[index]);
} else if (widget.listType == 'item' || widget.listType == 'crossedOff') {
listItem = Item(widget.list[index]);
} else {

var listItem;

if (listType == 'shopping list') {
listItem = ShoppingList(list[index]);
} else if (listType == 'store') {
listItem = Store(list[index]);
} else if (listType == 'item' || listType == 'crossedOff') {
listItem = Item(list[index]);
} else {
print("Unhandled list item type");
}

return ListItem(item: listItem, listType: listType, count: getCount(listItem), onTap: onItemTap, onInfoTap: onInfoTap);
print("Unhandled list item type:" + widget.listType.toString());
}

return ListItem(item: listItem, index: index, listType: widget.listType, count: getCount(listItem), onTap: widget.onItemTap, onInfoTap: widget.onInfoTap, parentListID: widget.parentList?.id);
}
);
}
Expand Down
35 changes: 26 additions & 9 deletions lib/components/item_list_header.dart
Expand Up @@ -3,22 +3,39 @@ import 'package:flutter/material.dart';
class ItemListHeader extends StatelessWidget {

final String text;
final String listType;
final onManageListTap;

ItemListHeader({Key key, @required this.text});
ItemListHeader({Key key, @required this.text, @required this.listType, @required this.onManageListTap});

@override
Widget build(BuildContext context) {
return Container(
color: Colors.blue[800],
height: 30.0,
height: 40.0,
child: Center(
child: Text(text,
style: TextStyle(
color: Colors.white,
fontSize: 18,
)
)
)
child: Row(
children: [
Padding(
padding: EdgeInsets.fromLTRB(10.0, 0, 0, 0),
child: Text(text,
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
),
Spacer(),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 15.0, 5.0),
child: IconButton(
icon: Icon(Icons.more_horiz, color: Colors.white),
onPressed: () => onManageListTap(listType),
),
),
],
),
),
);
}
}
26 changes: 19 additions & 7 deletions lib/components/item_list_stream.dart
@@ -1,17 +1,18 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:grocery_go/components/add_new.dart';
import 'package:grocery_go/components/item_list.dart';

import 'package:grocery_go/models/shopping_list.dart';

class ItemListStream extends StatelessWidget {

final dbStream;
final listType;
final sortBy;
final listType; // item, crossedOff
final onTap;
final onInfoTap;
final parentList;
final ShoppingList parentList;

ItemListStream({this.dbStream, this.listType, this.onTap, this.onInfoTap, this.parentList});
ItemListStream({@required this.dbStream, @required this.sortBy, @required this.listType, @required this.onTap, @required this.onInfoTap, this.parentList});

@override
Widget build(BuildContext context) {
Expand All @@ -22,15 +23,26 @@ class ItemListStream extends StatelessWidget {
return Text('Error: ${snapshot.error}');
}
if (snapshot.hasData && !snapshot.data.documents.isEmpty) {
return ItemList(list: snapshot.data.documents, listType: listType, onItemTap: onTap, onInfoTap: onInfoTap, parentList: parentList);
List<DocumentSnapshot> docs = snapshot.data.documents;

if (listType != 'crossedOff') {
docs.sort((a, b) {
return a.data['listPositions'][sortBy].compareTo(b.data['listPositions'][sortBy]);
});
} else {
docs.sort((b, a) {
return a.data['lastUpdated'].toDate().compareTo(b.data['lastUpdated'].toDate());
});
}

return ItemList(list: docs, listType: listType, onItemTap: onTap, onInfoTap: onInfoTap, parentList: parentList);
} else {
return Column(
children: [
Padding(
padding: EdgeInsets.all(8),
child: Text("No items yet!"),
),
AddNew(listType: listType, parentList: parentList),
],
);
}
Expand Down
19 changes: 12 additions & 7 deletions lib/components/list_item.dart
Expand Up @@ -5,23 +5,26 @@ import 'package:timeago/timeago.dart' as timeago;
class ListItem extends StatelessWidget {

final item;
final key;
final index;
final parentListID;
final listType;
final count;
final onTap;
final onInfoTap;

ListItem({Key key, this.item: "Unknown", this.listType, this.count, this.onTap, this.onInfoTap});
ListItem({this.item, this.key, this.index, this.listType, this.count, this.onTap, this.onInfoTap, this.parentListID});

buildDateString(date) {
if (date != null && date.length > 0) {
return DateFormat.yMMMd().format(DateTime.parse(date));
if (date != null) {
return DateFormat.yMd().format(date.toDate());
} else {
return 'unknown date';
}
}

buildCrossedOffDate(date) {
var difference = new DateTime.now().difference(DateTime.parse(date));
var difference = new DateTime.now().difference(date.toDate());
var howLongAgo = DateTime.now().subtract(difference);

return (timeago.format(howLongAgo).toString());
Expand All @@ -41,7 +44,8 @@ class ListItem extends StatelessWidget {
} else if (listType == 'store') {
return item.address;
} else if (listType == 'item') {
return 'Added by ' + (item?.addedBy ?? 'no one') + ' on ' + buildDateString(item.lastUpdated);
// Added 12/31/20 by Name
return 'Added ' + buildDateString(item.lastUpdated) + ' by ' + (item?.addedBy ?? 'no one');
} else if (listType == 'crossedOff') {
return '' + buildCrossedOffDate(item.lastUpdated) + ' at storeName';
} else {
Expand All @@ -52,14 +56,15 @@ class ListItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListTile(
key: key,
title: Text(buildTitleString(), style: (listType == 'crossedOff' ? TextStyle(decoration: TextDecoration.lineThrough) : TextStyle(decoration: TextDecoration.none))),
subtitle: Text(buildSubtitleString()),
leading: FlutterLogo(),
trailing: IconButton(
icon: Icon(Icons.info),
icon: Icon(Icons.more_horiz),
onPressed: () => onInfoTap(item),
),
onTap: () => onTap(item), //handleTap(context),
onTap: () => onTap(item, index),
);
}
}