From 3e98efb81a2ea57e7b30785a98f2920d6cd3b28a Mon Sep 17 00:00:00 2001 From: Abhishek Shroff Date: Fri, 4 Jul 2025 00:44:00 +0530 Subject: [PATCH] [client] Basic resource open --- client/lib/ui/app/router.dart | 5 ++ client/lib/ui/app/routes.dart | 51 +++++++++--- client/lib/ui/open/open_resource_page.dart | 97 ++++++++++++++++++++++ 3 files changed, 141 insertions(+), 12 deletions(-) create mode 100644 client/lib/ui/open/open_resource_page.dart diff --git a/client/lib/ui/app/router.dart b/client/lib/ui/app/router.dart index 6a53ac9e..8684cd4c 100644 --- a/client/lib/ui/app/router.dart +++ b/client/lib/ui/app/router.dart @@ -91,6 +91,11 @@ class PhylumRouteInformationParser extends RouteInformationParser { if (segments[0] == 'home') { return SynchronousFuture(ExplorerRouteHome()); } + if (segments[0] == 'open') { + final resourceId = uri.queryParameters['id']; + return SynchronousFuture( + resourceId == null ? const ExplorerRouteHome() : OpenResourceRoute(resourceId: resourceId)); + } if (segments[0] == 'recents') { return SynchronousFuture(const ExplorerRouteRecents()); } diff --git a/client/lib/ui/app/routes.dart b/client/lib/ui/app/routes.dart index f462adaa..e78ad22e 100644 --- a/client/lib/ui/app/routes.dart +++ b/client/lib/ui/app/routes.dart @@ -13,6 +13,7 @@ import 'package:phylum/ui/layout/explorer_page.dart'; import 'package:phylum/ui/login/login_page.dart'; import 'package:phylum/ui/login/token_login_page.dart'; import 'package:phylum/ui/login/reset_password_page.dart'; +import 'package:phylum/ui/open/open_resource_page.dart'; import 'package:provider/provider.dart'; sealed class PhylumRoute { @@ -59,16 +60,8 @@ class ResetPasswordRoute extends PhylumRoute { ); } -sealed class ExplorerRoute extends PhylumRoute { - String get title; - - const ExplorerRoute(); - - String? folderId(PhylumAccount account) => null; - - Future refresh(PhylumAccount account); - - Stream> items(PhylumAccount account); +sealed class LoggedInRoute extends PhylumRoute { + const LoggedInRoute(); @nonVirtual @override @@ -79,6 +72,40 @@ sealed class ExplorerRoute extends PhylumRoute { if (account == null) { return const LoginPage(); } + return buildAccountPage(account); + } + + @protected + Widget buildAccountPage(PhylumAccount account); +} + +class OpenResourceRoute extends LoggedInRoute { + final String resourceId; + + @override + Uri get uri => Uri(path: '/open/$resourceId'); + + OpenResourceRoute({required this.resourceId}) : super(); + + @override + Widget buildAccountPage(PhylumAccount account) { + return OpenResourcePage(account: account, resourceId: resourceId); + } +} + +sealed class ExplorerRoute extends LoggedInRoute { + String get title; + + const ExplorerRoute(); + + String? folderId(PhylumAccount account) => null; + + Future refresh(PhylumAccount account); + + Stream> items(PhylumAccount account); + + @override + Widget buildAccountPage(PhylumAccount account) { return ExplorerPage.create(account); } } @@ -90,7 +117,7 @@ class ExplorerRouteHome extends ExplorerRouteFolder { @override String get title => 'My Files'; - ExplorerRouteHome() : super(folderId: ''); + const ExplorerRouteHome() : super(folderId: ''); @override String folderId(PhylumAccount account) => account.user.home; @@ -105,7 +132,7 @@ class ExplorerRouteFolder extends ExplorerRoute { final String _folderId; - ExplorerRouteFolder({required String folderId}) : _folderId = folderId; + const ExplorerRouteFolder({required String folderId}) : _folderId = folderId; @override String folderId(PhylumAccount account) => _folderId; diff --git a/client/lib/ui/open/open_resource_page.dart b/client/lib/ui/open/open_resource_page.dart new file mode 100644 index 00000000..35dbaeac --- /dev/null +++ b/client/lib/ui/open/open_resource_page.dart @@ -0,0 +1,97 @@ +import 'package:flutter/material.dart'; +import 'package:offtheline/offtheline.dart'; +import 'package:phylum/libphylum/phylum_account.dart'; +import 'package:phylum/libphylum/responses/responses.dart'; +import 'package:phylum/ui/app/dialog_scaffold.dart'; +import 'package:phylum/ui/app/router.dart'; +import 'package:phylum/ui/app/routes.dart'; +import 'package:phylum/ui/preview/resource_preview.dart'; +import 'package:provider/provider.dart'; + +class OpenResourcePage extends StatefulWidget { + final PhylumAccount account; + final String resourceId; + + const OpenResourcePage({super.key, required this.account, required this.resourceId}); + + @override + State createState() => _OpenResourcePageState(); +} + +class _OpenResourcePageState extends State { + bool _loading = false; + String? _error; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) => _loadResourceDetails()); + } + + void _loadResourceDetails() async { + if (_loading) return; + setState(() { + _loading = true; + _error = null; + }); + + final router = context.read(); + final response = await widget.account.resourceRepository.requestResource(widget.resourceId); + if (response is ResourceInfoResponse) { + if (!mounted) return; + final r = response.root.resource; + if (r.dir) { + router.go(ExplorerRouteFolder(folderId: r.id)); + } else { + if (r.parent != null) { + router.go(ExplorerRouteFolder(folderId: r.parent!)); + } else { + router.go(const ExplorerRouteHome()); + } + ResourcePreview.showResources(context, [r], 0); + } + } else if (response is ApiErrorResponse) { + if (mounted) { + setState(() { + _error = response.description; + }); + } + } + _loading = false; + } + + @override + Widget build(BuildContext context) { + return PhylumDialogScaffold(child: _loading ? _buildLoading(context) : _buildError(context)); + } + + Widget _buildLoading(BuildContext context) { + return const Row( + mainAxisSize: MainAxisSize.min, + spacing: 6.0, + children: [ + CircularProgressIndicator(), + Text('Loading Details'), + ], + ); + } + + Widget _buildError(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + spacing: 6.0, + children: [ + Text('Error Loading Details: $_error'), + TextButton( + onPressed: () { + context.read().go(const ExplorerRouteHome()); + }, + child: Text( + 'Go Home', + style: TextStyle(color: Theme.of(context).colorScheme.error), + )), + ElevatedButton(onPressed: _loadResourceDetails, child: Text('Retry')), + ], + ); + } +}