Improve display of current path

This commit is contained in:
Nutcake 2023-06-17 17:36:52 +02:00
parent 83c92a4152
commit 5c61a89805
3 changed files with 77 additions and 45 deletions

View file

@ -6,7 +6,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.2.0' classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }

View file

@ -14,7 +14,10 @@ class InventoryClient extends ChangeNotifier {
InventoryClient({required this.apiClient}); InventoryClient({required this.apiClient});
Future<List<Record>> _getDirectory(Record record) async { Future<List<Record>> _getDirectory(Record record) async {
final dir = await _currentDirectory; NeosDirectory? dir;
try {
dir = await _currentDirectory;
} catch(_) {}
final List<Record> records; final List<Record> records;
if (dir == null || record.isRoot) { if (dir == null || record.isRoot) {
records = await RecordApi.getUserRecordsAt( records = await RecordApi.getUserRecordsAt(
@ -84,8 +87,8 @@ class InventoryClient extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
Future<void> navigateUp() async { Future<void> navigateUp({int times = 1}) async {
final dir = await _currentDirectory; var dir = await _currentDirectory;
if (dir == null) { if (dir == null) {
throw "Failed to navigate up: No directory loaded."; throw "Failed to navigate up: No directory loaded.";
} }
@ -93,7 +96,11 @@ class InventoryClient extends ChangeNotifier {
throw "Failed navigate up: Already at root"; throw "Failed navigate up: Already at root";
} }
_currentDirectory = Future.value(dir.parent); for (int i = 0; i < times; i++) {
dir = dir?.parent;
}
_currentDirectory = Future.value(dir);
notifyListeners(); notifyListeners();
} }
} }

View file

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:collection/collection.dart';
import 'package:contacts_plus_plus/auxiliary.dart'; import 'package:contacts_plus_plus/auxiliary.dart';
import 'package:contacts_plus_plus/clients/inventory_client.dart'; import 'package:contacts_plus_plus/clients/inventory_client.dart';
import 'package:contacts_plus_plus/models/inventory/neos_path.dart'; import 'package:contacts_plus_plus/models/inventory/neos_path.dart';
@ -38,9 +39,8 @@ class _InventoryBrowserState extends State<InventoryBrowser> with AutomaticKeepA
super.build(context); super.build(context);
return ChangeNotifierProvider.value( return ChangeNotifierProvider.value(
value: Provider.of<InventoryClient>(context), value: Provider.of<InventoryClient>(context),
child: Consumer<InventoryClient>( child: Consumer<InventoryClient>(builder: (BuildContext context, InventoryClient iClient, Widget? child) {
builder: (BuildContext context, InventoryClient iClient, Widget? child) { return FutureBuilder<NeosDirectory>(
return FutureBuilder<NeosDirectory>(
future: iClient.directoryFuture, future: iClient.directoryFuture,
builder: (context, snapshot) { builder: (context, snapshot) {
final currentDir = snapshot.data; final currentDir = snapshot.data;
@ -66,12 +66,12 @@ class _InventoryBrowserState extends State<InventoryBrowser> with AutomaticKeepA
child: Builder( child: Builder(
builder: (context) { builder: (context) {
if (snapshot.hasError) { if (snapshot.hasError) {
FlutterError.reportError(FlutterErrorDetails(exception: snapshot.error!, stack: snapshot.stackTrace)); FlutterError.reportError(
FlutterErrorDetails(exception: snapshot.error!, stack: snapshot.stackTrace));
return DefaultErrorWidget( return DefaultErrorWidget(
message: snapshot.error.toString(), message: snapshot.error.toString(),
onRetry: () async { onRetry: () {
iClient.loadInventoryRoot(); iClient.loadInventoryRoot();
await iClient.directoryFuture;
}, },
); );
} }
@ -80,36 +80,56 @@ class _InventoryBrowserState extends State<InventoryBrowser> with AutomaticKeepA
records.sort((a, b) => a.name.compareTo(b.name)); records.sort((a, b) => a.name.compareTo(b.name));
final paths = records final paths = records
.where((element) => element.recordType == RecordType.link || element.recordType == RecordType.directory) .where((element) =>
element.recordType == RecordType.link || element.recordType == RecordType.directory)
.toList(); .toList();
final objects = records final objects = records
.where((element) => element.recordType != RecordType.link && element.recordType != RecordType.directory) .where((element) =>
element.recordType != RecordType.link && element.recordType != RecordType.directory)
.toList(); .toList();
final pathSegments = directory?.absolutePathSegments ?? [];
return Stack( return Stack(
children: [ children: [
ListView( ListView(
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8),
child: Text( child: Wrap(
directory?.absolutePath ?? NeosDirectory.rootName, children: pathSegments
style: Theme .mapIndexed(
.of(context) (idx, segment) => Row(
.textTheme mainAxisSize: MainAxisSize.min,
.labelLarge children: [
?.copyWith(color: Theme if (idx != 0) const Icon(Icons.chevron_right),
.of(context) Padding(
.colorScheme padding: const EdgeInsets.symmetric(horizontal: 4.0),
.primary), child: TextButton(
), style: TextButton.styleFrom(
), foregroundColor: idx == pathSegments.length - 1
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurface,
),
onPressed: () {
iClient.navigateUp(times: pathSegments.length - 1 - idx);
},
child: Text(segment),
),
),
],
),
)
.toList(),
)),
GridView.builder( GridView.builder(
padding: const EdgeInsets.symmetric(horizontal: 8.0), padding: const EdgeInsets.symmetric(horizontal: 8.0),
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,
itemCount: paths.length, itemCount: paths.length,
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 256, childAspectRatio: 4, crossAxisSpacing: 8, mainAxisSpacing: 8), maxCrossAxisExtent: 256,
childAspectRatio: 4,
crossAxisSpacing: 8,
mainAxisSpacing: 8),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final record = paths[index]; final record = paths[index];
return PathInventoryTile( return PathInventoryTile(
@ -144,13 +164,12 @@ class _InventoryBrowserState extends State<InventoryBrowser> with AutomaticKeepA
await Navigator.push( await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => builder: (context) => PhotoView(
PhotoView( minScale: PhotoViewComputedScale.contained,
minScale: PhotoViewComputedScale.contained, imageProvider:
imageProvider: CachedNetworkImageProvider( CachedNetworkImageProvider(Aux.neosDbToHttp(record.thumbnailUri)),
Aux.neosDbToHttp(record.thumbnailUri)), heroAttributes: PhotoViewHeroAttributes(tag: record.id),
heroAttributes: PhotoViewHeroAttributes(tag: record.id), ),
),
), ),
); );
}, },
@ -169,26 +188,32 @@ class _InventoryBrowserState extends State<InventoryBrowser> with AutomaticKeepA
), ),
], ],
), ),
if (snapshot.connectionState == ConnectionState.waiting) Align(
Align( alignment: Alignment.topCenter,
alignment: Alignment.center, child: AnimatedSwitcher(
child: Container( duration: const Duration(milliseconds: 250),
child: snapshot.connectionState == ConnectionState.waiting ? const LinearProgressIndicator() : null,
),
),
Align(
alignment: Alignment.topCenter,
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 250),
child: snapshot.connectionState == ConnectionState.waiting ? Container(
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,
color: Colors.black38, color: Colors.black38,
child: const Center(child: CircularProgressIndicator()), ) : null,
), ),
) )
], ],
); );
}, },
), ),
), ),
); );
} });
); }),
}
),
); );
} }