Improve inventory selection logic

This commit is contained in:
Nutcake 2023-06-17 19:28:23 +02:00
parent 5c61a89805
commit f202ccdd75
3 changed files with 99 additions and 53 deletions

View file

@ -82,7 +82,9 @@ class InventoryClient extends ChangeNotifier {
childDir.children.addAll(records.map((record) => NeosDirectory.fromRecord(record: record, parent: childDir))); childDir.children.addAll(records.map((record) => NeosDirectory.fromRecord(record: record, parent: childDir)));
return childDir; return childDir;
}, },
); ).onError((error, stackTrace) {
return dir;
});
} }
notifyListeners(); notifyListeners();
} }

View file

@ -132,48 +132,25 @@ class _InventoryBrowserState extends State<InventoryBrowser> with AutomaticKeepA
mainAxisSpacing: 8), mainAxisSpacing: 8),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final record = paths[index]; final record = paths[index];
return PathInventoryTile( return Padding(
record: record, padding: const EdgeInsets.symmetric(horizontal: 3.0),
onPressed: () { child: PathInventoryTile(
iClient.navigateTo(record);
},
);
},
),
const SizedBox(
height: 8,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: GridView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: objects.length,
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 256,
childAspectRatio: 1,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
),
itemBuilder: (context, index) {
final record = objects[index];
return ObjectInventoryTile(
record: record, record: record,
selected: _selectedIds.contains(record.id), selected: _selectedIds.contains(record.id),
onTap: () async { onTap: _selectedIds.isEmpty
await Navigator.push( ? () {
context, iClient.navigateTo(record);
MaterialPageRoute( }
builder: (context) => PhotoView( : () {
minScale: PhotoViewComputedScale.contained, setState(() {
imageProvider: if (_selectedIds.contains(record.id)) {
CachedNetworkImageProvider(Aux.neosDbToHttp(record.thumbnailUri)), _selectedIds.remove(record.id);
heroAttributes: PhotoViewHeroAttributes(tag: record.id), } else {
), _selectedIds.add(record.id);
), }
); });
}, },
onLongPress: () async { onLongPress: () {
setState(() { setState(() {
if (_selectedIds.contains(record.id)) { if (_selectedIds.contains(record.id)) {
_selectedIds.remove(record.id); _selectedIds.remove(record.id);
@ -182,9 +159,63 @@ class _InventoryBrowserState extends State<InventoryBrowser> with AutomaticKeepA
} }
}); });
}, },
); ),
}, );
},
),
const SizedBox(
height: 8,
),
GridView.builder(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: objects.length,
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 256,
childAspectRatio: 1,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
), ),
itemBuilder: (context, index) {
final record = objects[index];
return ObjectInventoryTile(
record: record,
selected: _selectedIds.contains(record.id),
onTap: _selectedIds.isEmpty
? () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PhotoView(
minScale: PhotoViewComputedScale.contained,
imageProvider: CachedNetworkImageProvider(
Aux.neosDbToHttp(record.thumbnailUri)),
heroAttributes: PhotoViewHeroAttributes(tag: record.id),
),
),
);
}
: () async {
setState(() {
if (_selectedIds.contains(record.id)) {
_selectedIds.remove(record.id);
} else {
_selectedIds.add(record.id);
}
});
},
onLongPress: () async {
setState(() {
if (_selectedIds.contains(record.id)) {
_selectedIds.remove(record.id);
} else {
_selectedIds.add(record.id);
}
});
},
);
},
), ),
], ],
), ),
@ -192,18 +223,22 @@ class _InventoryBrowserState extends State<InventoryBrowser> with AutomaticKeepA
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: AnimatedSwitcher( child: AnimatedSwitcher(
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
child: snapshot.connectionState == ConnectionState.waiting ? const LinearProgressIndicator() : null, child: snapshot.connectionState == ConnectionState.waiting
? const LinearProgressIndicator()
: null,
), ),
), ),
Align( Align(
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: AnimatedSwitcher( child: AnimatedSwitcher(
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
child: snapshot.connectionState == ConnectionState.waiting ? Container( child: snapshot.connectionState == ConnectionState.waiting
width: double.infinity, ? Container(
height: double.infinity, width: double.infinity,
color: Colors.black38, height: double.infinity,
) : null, color: Colors.black38,
)
: null,
), ),
) )
], ],

View file

@ -3,20 +3,29 @@ import 'package:contacts_plus_plus/widgets/formatted_text.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class PathInventoryTile extends StatelessWidget { class PathInventoryTile extends StatelessWidget {
const PathInventoryTile({required this.record, required this.onPressed, super.key}); const PathInventoryTile({required this.record, this.selected = false, this.onTap, this.onLongPress, super.key});
final Record record; final Record record;
final Function() onPressed; final Function()? onTap;
final Function()? onLongPress;
final bool selected;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return OutlinedButton.icon( return OutlinedButton.icon(
style: TextButton.styleFrom( style: TextButton.styleFrom(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
side: BorderSide(
color: selected ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.outline,
width: 1,
),
foregroundColor: Theme.of(context).colorScheme.onSecondaryContainer, foregroundColor: Theme.of(context).colorScheme.onSecondaryContainer,
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
), ),
onPressed: onPressed, onLongPress: onLongPress,
onPressed: onTap,
icon: record.recordType == RecordType.directory ? const Icon(Icons.folder) : const Icon(Icons.link), icon: record.recordType == RecordType.directory ? const Icon(Icons.folder) : const Icon(Icons.link),
label: FormattedText( label: FormattedText(
record.formattedName, record.formattedName,