diff --git a/lib/features/home/view/home_page.dart b/lib/features/home/view/home_page.dart index b0288b5..b09a647 100644 --- a/lib/features/home/view/home_page.dart +++ b/lib/features/home/view/home_page.dart @@ -20,7 +20,7 @@ import 'package:paperless_mobile/features/document_upload/view/document_upload_p import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/view/pages/documents_page.dart'; import 'package:paperless_mobile/features/home/view/route_description.dart'; -import 'package:paperless_mobile/features/home/view/widget/app_drawer.dart'; +import 'package:paperless_mobile/features/home/view/widget/_app_drawer.dart'; import 'package:paperless_mobile/features/inbox/bloc/inbox_cubit.dart'; import 'package:paperless_mobile/features/inbox/view/pages/inbox_page.dart'; import 'package:paperless_mobile/features/labels/view/pages/labels_page.dart'; @@ -59,6 +59,7 @@ class _HomePageState extends State { context.read(), context.read(), context.read(), + context.read(), ); context.read().reload(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { @@ -271,7 +272,6 @@ class _HomePageState extends State { destinations: destinations.map((e) => e.toNavigationDestination()).toList(), ), - drawer: const AppDrawer(), body: routes[_currentIndex], ); }, diff --git a/lib/features/home/view/widget/_app_drawer.dart b/lib/features/home/view/widget/_app_drawer.dart new file mode 100644 index 0000000..8f2001b --- /dev/null +++ b/lib/features/home/view/widget/_app_drawer.dart @@ -0,0 +1,320 @@ +// import 'package:flutter/material.dart'; +// import 'package:flutter_bloc/flutter_bloc.dart'; +// import 'package:hydrated_bloc/hydrated_bloc.dart'; +// import 'package:package_info_plus/package_info_plus.dart'; +// import 'package:paperless_api/paperless_api.dart'; +// import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart'; +// import 'package:paperless_mobile/core/bloc/paperless_server_information_state.dart'; +// import 'package:paperless_mobile/core/repository/label_repository.dart'; +// import 'package:paperless_mobile/core/repository/provider/label_repositories_provider.dart'; +// import 'package:paperless_mobile/core/repository/saved_view_repository.dart'; +// import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart'; +// import 'package:paperless_mobile/core/repository/state/impl/document_type_repository_state.dart'; +// import 'package:paperless_mobile/core/repository/state/impl/storage_path_repository_state.dart'; +// import 'package:paperless_mobile/core/repository/state/impl/tag_repository_state.dart'; +// import 'package:paperless_mobile/extensions/flutter_extensions.dart'; +// import 'package:paperless_mobile/features/inbox/bloc/inbox_cubit.dart'; +// import 'package:paperless_mobile/features/inbox/view/pages/inbox_page.dart'; +// import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart'; +// import 'package:paperless_mobile/features/settings/bloc/application_settings_cubit.dart'; +// import 'package:paperless_mobile/features/settings/view/settings_page.dart'; +// import 'package:paperless_mobile/generated/l10n.dart'; +// import 'package:paperless_mobile/helpers/message_helpers.dart'; +// import 'package:paperless_mobile/constants.dart'; +// import 'package:url_launcher/link.dart'; +// import 'package:url_launcher/url_launcher_string.dart'; + +// class AppDrawer extends StatefulWidget { +// final VoidCallback? afterInboxClosed; + +// const AppDrawer({Key? key, this.afterInboxClosed}) : super(key: key); + +// @override +// State createState() => _AppDrawerState(); +// } + +// // enum NavigationDestinations { +// // inbox, +// // settings, +// // reportBug, +// // about, +// // logout; +// // } + +// class _AppDrawerState extends State { +// @override +// void initState() { +// super.initState(); +// } + +// @override +// Widget build(BuildContext context) { +// final listtTileShape = RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(32), +// ); +// // return NavigationDrawer( +// // selectedIndex: -1, +// // children: [ +// // Text( +// // "", +// // style: Theme.of(context).textTheme.titleSmall, +// // ).padded(16), +// // NavigationDrawerDestination( +// // icon: const Icon(Icons.inbox), +// // label: Text(S.of(context).bottomNavInboxPageLabel), +// // ), +// // NavigationDrawerDestination( +// // icon: const Icon(Icons.settings), +// // label: Text(S.of(context).appDrawerSettingsLabel), +// // ), +// // const Divider( +// // indent: 16, +// // ), +// // NavigationDrawerDestination( +// // icon: const Icon(Icons.bug_report), +// // label: Text(S.of(context).appDrawerReportBugLabel), +// // ), +// // NavigationDrawerDestination( +// // icon: const Icon(Icons.info_outline), +// // label: Text(S.of(context).appDrawerAboutLabel), +// // ), +// // ], +// // onDestinationSelected: (idx) { +// // final val = NavigationDestinations.values[idx - 1]; +// // switch (val) { +// // case NavigationDestinations.inbox: +// // _onOpenInbox(); +// // break; +// // case NavigationDestinations.settings: +// // _onOpenSettings(); +// // break; +// // case NavigationDestinations.reportBug: +// // launchUrlString( +// // 'https://github.com/astubenbord/paperless-mobile/issues/new', +// // ); +// // break; +// // case NavigationDestinations.about: +// // _onShowAboutDialog(); +// // break; +// // case NavigationDestinations.logout: +// // _onLogout(); +// // break; +// // } +// // }, +// // ); +// return SafeArea( +// top: true, +// child: ClipRRect( +// borderRadius: const BorderRadius.only( +// topRight: Radius.circular(16.0), +// bottomRight: Radius.circular(16.0), +// ), +// child: Drawer( +// shape: const RoundedRectangleBorder( +// borderRadius: BorderRadius.only( +// topRight: Radius.circular(16.0), +// bottomRight: Radius.circular(16.0), +// ), +// ), +// child: ListView( +// children: [ +// DrawerHeader( +// decoration: BoxDecoration( +// color: Theme.of(context).colorScheme.secondaryContainer, +// ), +// padding: const EdgeInsets.only( +// top: 8, +// left: 8, +// bottom: 0, +// right: 8, +// ), +// child: Column( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Row( +// children: [ +// Image.asset( +// 'assets/logos/paperless_logo_white.png', +// height: 32, +// width: 32, +// color: +// Theme.of(context).colorScheme.onPrimaryContainer, +// ).paddedOnly(right: 8.0), +// Text( +// S.of(context).appTitleText, +// style: Theme.of(context) +// .textTheme +// .headlineSmall +// ?.copyWith( +// color: Theme.of(context) +// .colorScheme +// .onPrimaryContainer, +// ), +// ), +// ], +// ), +// Align( +// alignment: Alignment.bottomRight, +// child: BlocBuilder( +// builder: (context, state) { +// if (!state.isLoaded) { +// return Container(); +// } +// final info = state.information!; +// return Column( +// crossAxisAlignment: CrossAxisAlignment.end, +// children: [ +// ListTile( +// contentPadding: EdgeInsets.zero, +// dense: true, +// title: Text( +// S.of(context).appDrawerHeaderLoggedInAsText + +// (info.username ?? '?'), +// style: Theme.of(context).textTheme.bodyMedium, +// overflow: TextOverflow.ellipsis, +// textAlign: TextAlign.end, +// maxLines: 1, +// ), +// subtitle: Column( +// crossAxisAlignment: CrossAxisAlignment.end, +// children: [ +// Text( +// state.information!.host ?? '', +// style: Theme.of(context) +// .textTheme +// .bodyMedium, +// overflow: TextOverflow.ellipsis, +// textAlign: TextAlign.end, +// maxLines: 1, +// ), +// Text( +// '${S.of(context).serverInformationPaperlessVersionText} ${info.version} (API v${info.apiVersion})', +// style: +// Theme.of(context).textTheme.bodySmall, +// overflow: TextOverflow.ellipsis, +// textAlign: TextAlign.end, +// maxLines: 1, +// ), +// ], +// ), +// isThreeLine: true, +// ), +// ], +// ); +// }, +// ), +// ), +// ], +// ), +// ), +// ...[ +// ListTile( +// title: Text(S.of(context).bottomNavInboxPageLabel), +// leading: const Icon(Icons.inbox), +// onTap: () => _onOpenInbox(), +// shape: listtTileShape, +// ), +// ListTile( +// leading: const Icon(Icons.settings), +// shape: listtTileShape, +// title: Text( +// S.of(context).appDrawerSettingsLabel, +// ), +// onTap: () => Navigator.of(context).push( +// MaterialPageRoute( +// builder: (context) => BlocProvider.value( +// value: context.read(), +// child: const SettingsPage(), +// ), +// ), +// ), +// ), +// const Divider( +// indent: 16, +// endIndent: 16, +// ), +// ListTile( +// leading: const Icon(Icons.bug_report), +// title: Text(S.of(context).appDrawerReportBugLabel), +// onTap: () { +// launchUrlString( +// 'https://github.com/astubenbord/paperless-mobile/issues/new'); +// }, +// shape: listtTileShape, +// ), +// ListTile( +// title: Text(S.of(context).appDrawerAboutLabel), +// leading: Icon(Icons.info_outline_rounded), +// onTap: _onShowAboutDialog, +// shape: listtTileShape, +// ), +// ListTile( +// leading: const Icon(Icons.logout), +// title: Text(S.of(context).appDrawerLogoutLabel), +// shape: listtTileShape, +// onTap: () { +// _onLogout(); +// }, +// ) +// ], +// ], +// ), +// ), +// ), +// ); +// } + +// void _onLogout() async { +// try { +// await context.read().logout(); +// await context.read().clear(); +// await context.read>().clear(); +// await context +// .read>() +// .clear(); +// await context +// .read>() +// .clear(); +// await context +// .read>() +// .clear(); +// await context.read().clear(); +// await HydratedBloc.storage.clear(); +// } on PaperlessServerException catch (error, stackTrace) { +// showErrorMessage(context, error, stackTrace); +// } +// } + +// Future _onOpenInbox() async { +// await Navigator.of(context).push( +// MaterialPageRoute( +// builder: (_) => LabelRepositoriesProvider( +// child: BlocProvider( +// create: (context) => InboxCubit( +// context.read(), +// context.read(), +// context.read(), +// context.read(), +// )..initializeInbox(), +// child: const InboxPage(), +// ), +// ), +// ), +// ); +// widget.afterInboxClosed?.call(); +// } + +// void _onOpenSettings() { +// Navigator.of(context).push( +// MaterialPageRoute( +// builder: (context) => BlocProvider.value( +// value: context.read(), +// child: const SettingsPage(), +// ), +// ), +// ); +// } +// void _onShowAboutDialog() {} +// } diff --git a/lib/features/home/view/widget/app_drawer.dart b/lib/features/home/view/widget/app_drawer.dart deleted file mode 100644 index 344a928..0000000 --- a/lib/features/home/view/widget/app_drawer.dart +++ /dev/null @@ -1,321 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:hydrated_bloc/hydrated_bloc.dart'; -import 'package:package_info_plus/package_info_plus.dart'; -import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart'; -import 'package:paperless_mobile/core/bloc/paperless_server_information_state.dart'; -import 'package:paperless_mobile/core/repository/label_repository.dart'; -import 'package:paperless_mobile/core/repository/provider/label_repositories_provider.dart'; -import 'package:paperless_mobile/core/repository/saved_view_repository.dart'; -import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart'; -import 'package:paperless_mobile/core/repository/state/impl/document_type_repository_state.dart'; -import 'package:paperless_mobile/core/repository/state/impl/storage_path_repository_state.dart'; -import 'package:paperless_mobile/core/repository/state/impl/tag_repository_state.dart'; -import 'package:paperless_mobile/extensions/flutter_extensions.dart'; -import 'package:paperless_mobile/features/inbox/bloc/inbox_cubit.dart'; -import 'package:paperless_mobile/features/inbox/view/pages/inbox_page.dart'; -import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart'; -import 'package:paperless_mobile/features/settings/bloc/application_settings_cubit.dart'; -import 'package:paperless_mobile/features/settings/view/settings_page.dart'; -import 'package:paperless_mobile/generated/l10n.dart'; -import 'package:paperless_mobile/helpers/message_helpers.dart'; -import 'package:paperless_mobile/constants.dart'; -import 'package:url_launcher/link.dart'; -import 'package:url_launcher/url_launcher_string.dart'; - -class AppDrawer extends StatefulWidget { - final VoidCallback? afterInboxClosed; - - const AppDrawer({Key? key, this.afterInboxClosed}) : super(key: key); - - @override - State createState() => _AppDrawerState(); -} - -// enum NavigationDestinations { -// inbox, -// settings, -// reportBug, -// about, -// logout; -// } - -class _AppDrawerState extends State { - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - final listtTileShape = RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), - ); - // return NavigationDrawer( - // selectedIndex: -1, - // children: [ - // Text( - // "", - // style: Theme.of(context).textTheme.titleSmall, - // ).padded(16), - // NavigationDrawerDestination( - // icon: const Icon(Icons.inbox), - // label: Text(S.of(context).bottomNavInboxPageLabel), - // ), - // NavigationDrawerDestination( - // icon: const Icon(Icons.settings), - // label: Text(S.of(context).appDrawerSettingsLabel), - // ), - // const Divider( - // indent: 16, - // ), - // NavigationDrawerDestination( - // icon: const Icon(Icons.bug_report), - // label: Text(S.of(context).appDrawerReportBugLabel), - // ), - // NavigationDrawerDestination( - // icon: const Icon(Icons.info_outline), - // label: Text(S.of(context).appDrawerAboutLabel), - // ), - // ], - // onDestinationSelected: (idx) { - // final val = NavigationDestinations.values[idx - 1]; - // switch (val) { - // case NavigationDestinations.inbox: - // _onOpenInbox(); - // break; - // case NavigationDestinations.settings: - // _onOpenSettings(); - // break; - // case NavigationDestinations.reportBug: - // launchUrlString( - // 'https://github.com/astubenbord/paperless-mobile/issues/new', - // ); - // break; - // case NavigationDestinations.about: - // _onShowAboutDialog(); - // break; - // case NavigationDestinations.logout: - // _onLogout(); - // break; - // } - // }, - // ); - return SafeArea( - top: true, - child: ClipRRect( - borderRadius: const BorderRadius.only( - topRight: Radius.circular(16.0), - bottomRight: Radius.circular(16.0), - ), - child: Drawer( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topRight: Radius.circular(16.0), - bottomRight: Radius.circular(16.0), - ), - ), - child: ListView( - children: [ - DrawerHeader( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.secondaryContainer, - ), - padding: const EdgeInsets.only( - top: 8, - left: 8, - bottom: 0, - right: 8, - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Image.asset( - 'assets/logos/paperless_logo_white.png', - height: 32, - width: 32, - color: - Theme.of(context).colorScheme.onPrimaryContainer, - ).paddedOnly(right: 8.0), - Text( - S.of(context).appTitleText, - style: Theme.of(context) - .textTheme - .headlineSmall - ?.copyWith( - color: Theme.of(context) - .colorScheme - .onPrimaryContainer, - ), - ), - ], - ), - Align( - alignment: Alignment.bottomRight, - child: BlocBuilder( - builder: (context, state) { - if (!state.isLoaded) { - return Container(); - } - final info = state.information!; - return Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - ListTile( - contentPadding: EdgeInsets.zero, - dense: true, - title: Text( - S.of(context).appDrawerHeaderLoggedInAsText + - (info.username ?? '?'), - style: Theme.of(context).textTheme.bodyMedium, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.end, - maxLines: 1, - ), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - state.information!.host ?? '', - style: Theme.of(context) - .textTheme - .bodyMedium, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.end, - maxLines: 1, - ), - Text( - '${S.of(context).serverInformationPaperlessVersionText} ${info.version} (API v${info.apiVersion})', - style: - Theme.of(context).textTheme.bodySmall, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.end, - maxLines: 1, - ), - ], - ), - isThreeLine: true, - ), - ], - ); - }, - ), - ), - ], - ), - ), - ...[ - ListTile( - title: Text(S.of(context).bottomNavInboxPageLabel), - leading: const Icon(Icons.inbox), - onTap: () => _onOpenInbox(), - shape: listtTileShape, - ), - ListTile( - leading: const Icon(Icons.settings), - shape: listtTileShape, - title: Text( - S.of(context).appDrawerSettingsLabel, - ), - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => BlocProvider.value( - value: context.read(), - child: const SettingsPage(), - ), - ), - ), - ), - const Divider( - indent: 16, - endIndent: 16, - ), - ListTile( - leading: const Icon(Icons.bug_report), - title: Text(S.of(context).appDrawerReportBugLabel), - onTap: () { - launchUrlString( - 'https://github.com/astubenbord/paperless-mobile/issues/new'); - }, - shape: listtTileShape, - ), - ListTile( - title: Text(S.of(context).appDrawerAboutLabel), - leading: Icon(Icons.info_outline_rounded), - onTap: _onShowAboutDialog, - shape: listtTileShape, - ), - ListTile( - leading: const Icon(Icons.logout), - title: Text(S.of(context).appDrawerLogoutLabel), - shape: listtTileShape, - onTap: () { - _onLogout(); - }, - ) - ], - ], - ), - ), - ), - ); - } - - void _onLogout() async { - try { - await context.read().logout(); - await context.read().clear(); - await context.read>().clear(); - await context - .read>() - .clear(); - await context - .read>() - .clear(); - await context - .read>() - .clear(); - await context.read().clear(); - await HydratedBloc.storage.clear(); - } on PaperlessServerException catch (error, stackTrace) { - showErrorMessage(context, error, stackTrace); - } - } - - Future _onOpenInbox() async { - await Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => LabelRepositoriesProvider( - child: BlocProvider( - create: (context) => InboxCubit( - context.read(), - context.read(), - context.read(), - context.read(), - )..initializeInbox(), - child: const InboxPage(), - ), - ), - ), - ); - widget.afterInboxClosed?.call(); - } - - void _onOpenSettings() { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => BlocProvider.value( - value: context.read(), - child: const SettingsPage(), - ), - ), - ); - } - - void _onShowAboutDialog() {} -} diff --git a/lib/features/inbox/bloc/inbox_cubit.dart b/lib/features/inbox/bloc/inbox_cubit.dart index 2d2651a..cef27e1 100644 --- a/lib/features/inbox/bloc/inbox_cubit.dart +++ b/lib/features/inbox/bloc/inbox_cubit.dart @@ -18,16 +18,20 @@ class InboxCubit extends HydratedCubit with PagedDocumentsMixin { final PaperlessDocumentsApi _documentsApi; + final PaperlessServerStatsApi _statsApi; + final List _subscriptions = []; @override PaperlessDocumentsApi get api => _documentsApi; + Timer? _taskTimer; InboxCubit( this._tagsRepository, this._documentsApi, this._correspondentRepository, this._documentTypeRepository, + this._statsApi, ) : super( InboxState( availableCorrespondents: @@ -60,6 +64,15 @@ class InboxCubit extends HydratedCubit with PagedDocumentsMixin { } }), ); + //TODO: Do this properly in a background task. + _taskTimer = Timer.periodic(const Duration(seconds: 5), (timer) { + refreshItemsInInboxCount(); + }); + } + + void refreshItemsInInboxCount() async { + final stats = await _statsApi.getServerStatistics(); + emit(state.copyWith(itemsInInboxCount: stats.documentsInInbox)); } /// @@ -175,9 +188,10 @@ class InboxCubit extends HydratedCubit with PagedDocumentsMixin { @override Future close() { - _subscriptions.forEach((element) { - element.cancel(); - }); + _taskTimer?.cancel(); + for (var sub in _subscriptions) { + sub.cancel(); + } return super.close(); } } diff --git a/lib/features/inbox/bloc/state/inbox_state.dart b/lib/features/inbox/bloc/state/inbox_state.dart index be2aafc..a2a5814 100644 --- a/lib/features/inbox/bloc/state/inbox_state.dart +++ b/lib/features/inbox/bloc/state/inbox_state.dart @@ -16,6 +16,8 @@ class InboxState extends PagedDocumentsState { final Map availableCorrespondents; + final int itemsInInboxCount; + @JsonKey() final bool isHintAcknowledged; @@ -29,6 +31,7 @@ class InboxState extends PagedDocumentsState { this.availableTags = const {}, this.availableDocumentTypes = const {}, this.availableCorrespondents = const {}, + this.itemsInInboxCount = 0, }); @override @@ -43,6 +46,7 @@ class InboxState extends PagedDocumentsState { availableTags, availableDocumentTypes, availableCorrespondents, + itemsInInboxCount, ]; InboxState copyWith({ @@ -56,6 +60,7 @@ class InboxState extends PagedDocumentsState { Map? availableCorrespondents, Map? availableDocumentTypes, Map? suggestions, + int? itemsInInboxCount, }) { return InboxState( hasLoaded: hasLoaded ?? super.hasLoaded, @@ -69,6 +74,7 @@ class InboxState extends PagedDocumentsState { availableDocumentTypes ?? this.availableDocumentTypes, availableTags: availableTags ?? this.availableTags, filter: filter ?? super.filter, + itemsInInboxCount: itemsInInboxCount ?? this.itemsInInboxCount, ); } diff --git a/lib/features/inbox/view/pages/inbox_page.dart b/lib/features/inbox/view/pages/inbox_page.dart index b607538..301ac97 100644 --- a/lib/features/inbox/view/pages/inbox_page.dart +++ b/lib/features/inbox/view/pages/inbox_page.dart @@ -79,9 +79,8 @@ class _InboxPageState extends State { body: NestedScrollView( headerSliverBuilder: (context, innerBoxIsScrolled) => [ SearchAppBar( - hintText: "Search documents", - onOpenSearch: showDocumentSearchPage, - ), + hintText: "Search documents", + onOpenSearch: showDocumentSearchPage), ], body: BlocBuilder( builder: (context, state) {