Redesigned sorting

This commit is contained in:
Anton Stubenbord
2022-11-16 01:18:04 +01:00
parent 67ddf90a41
commit e9019bca9c
6 changed files with 368 additions and 321 deletions

View File

@@ -2,7 +2,7 @@ enum SortField {
archiveSerialNumber("archive_serial_number"), archiveSerialNumber("archive_serial_number"),
correspondentName("correspondent__name"), correspondentName("correspondent__name"),
title("title"), title("title"),
documentType("documentType"), documentType("document_type__name"),
created("created"), created("created"),
added("added"), added("added"),
modified("modified"); modified("modified");

View File

@@ -1,13 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart';
import 'package:paperless_mobile/core/model/error_message.dart'; import 'package:paperless_mobile/core/model/error_message.dart';
import 'package:paperless_mobile/core/service/github_issue_service.dart';
import 'package:paperless_mobile/core/widgets/offline_banner.dart';
import 'package:paperless_mobile/di_initializer.dart';
import 'package:paperless_mobile/features/labels/correspondent/bloc/correspondents_cubit.dart';
import 'package:paperless_mobile/features/labels/document_type/bloc/document_type_cubit.dart';
import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart';
import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_state.dart';
import 'package:paperless_mobile/features/documents/model/document.model.dart'; import 'package:paperless_mobile/features/documents/model/document.model.dart';
@@ -19,14 +14,15 @@ import 'package:paperless_mobile/features/documents/view/widgets/search/document
import 'package:paperless_mobile/features/documents/view/widgets/selection/documents_page_app_bar.dart'; import 'package:paperless_mobile/features/documents/view/widgets/selection/documents_page_app_bar.dart';
import 'package:paperless_mobile/features/documents/view/widgets/sort_documents_button.dart'; import 'package:paperless_mobile/features/documents/view/widgets/sort_documents_button.dart';
import 'package:paperless_mobile/features/home/view/widget/info_drawer.dart'; import 'package:paperless_mobile/features/home/view/widget/info_drawer.dart';
import 'package:paperless_mobile/features/labels/correspondent/bloc/correspondents_cubit.dart';
import 'package:paperless_mobile/features/labels/document_type/bloc/document_type_cubit.dart';
import 'package:paperless_mobile/features/labels/storage_path/bloc/storage_path_cubit.dart'; import 'package:paperless_mobile/features/labels/storage_path/bloc/storage_path_cubit.dart';
import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart';
import 'package:paperless_mobile/features/labels/tags/bloc/tags_cubit.dart'; import 'package:paperless_mobile/features/labels/tags/bloc/tags_cubit.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/bloc/application_settings_cubit.dart';
import 'package:paperless_mobile/features/settings/model/application_settings_state.dart'; import 'package:paperless_mobile/features/settings/model/application_settings_state.dart';
import 'package:paperless_mobile/features/settings/model/view_type.dart'; import 'package:paperless_mobile/features/settings/model/view_type.dart';
import 'package:paperless_mobile/util.dart'; import 'package:paperless_mobile/util.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:sliding_up_panel/sliding_up_panel.dart'; import 'package:sliding_up_panel/sliding_up_panel.dart';
class DocumentsPage extends StatefulWidget { class DocumentsPage extends StatefulWidget {
@@ -42,7 +38,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
firstPageKey: 1, firstPageKey: 1,
); );
final PanelController _panelController = PanelController(); final PanelController _filterPanelController = PanelController();
@override @override
void initState() { void initState() {
@@ -99,9 +95,9 @@ class _DocumentsPageState extends State<DocumentsPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
if (_panelController.isPanelOpen) { if (_filterPanelController.isPanelOpen) {
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
_panelController.close(); _filterPanelController.close();
return false; return false;
} }
final documentsCubit = BlocProvider.of<DocumentsCubit>(context); final documentsCubit = BlocProvider.of<DocumentsCubit>(context);
@@ -129,7 +125,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
backdropEnabled: true, backdropEnabled: true,
parallaxEnabled: true, parallaxEnabled: true,
parallaxOffset: .5, parallaxOffset: .5,
controller: _panelController, controller: _filterPanelController,
defaultPanelState: PanelState.CLOSED, defaultPanelState: PanelState.CLOSED,
minHeight: 48, minHeight: 48,
maxHeight: (MediaQuery.of(context).size.height * 3) / 4, maxHeight: (MediaQuery.of(context).size.height * 3) / 4,
@@ -140,7 +136,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
body: _buildBody(connectivityState), body: _buildBody(connectivityState),
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).scaffoldBackgroundColor,
panelBuilder: (scrollController) => DocumentFilterPanel( panelBuilder: (scrollController) => DocumentFilterPanel(
panelController: _panelController, panelController: _filterPanelController,
scrollController: scrollController, scrollController: scrollController,
), ),
), ),
@@ -194,33 +190,31 @@ class _DocumentsPageState extends State<DocumentsPage> {
return RefreshIndicator( return RefreshIndicator(
onRefresh: _onRefresh, onRefresh: _onRefresh,
child: Container( child: CustomScrollView(
child: CustomScrollView( slivers: [
slivers: [ DocumentsPageAppBar(
DocumentsPageAppBar( actions: [
actions: [ const SortDocumentsButton(),
const SortDocumentsButton(), IconButton(
IconButton( icon: Icon(
icon: Icon( settings.preferredViewType == ViewType.grid
settings.preferredViewType == ViewType.grid ? Icons.list
? Icons.list : Icons.grid_view,
: Icons.grid_view,
),
onPressed: () =>
BlocProvider.of<ApplicationSettingsCubit>(context)
.setViewType(
settings.preferredViewType.toggle()),
), ),
], onPressed: () =>
), BlocProvider.of<ApplicationSettingsCubit>(context)
child, .setViewType(
SliverToBoxAdapter( settings.preferredViewType.toggle()),
child: SizedBox(
height: MediaQuery.of(context).size.height / 4,
), ),
) ],
], ),
), child,
SliverToBoxAdapter(
child: SizedBox(
height: MediaQuery.of(context).size.height / 4,
),
)
],
), ),
); );
}, },

View File

@@ -52,16 +52,6 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
static const fkCreatedAt = DocumentModel.createdKey; static const fkCreatedAt = DocumentModel.createdKey;
static const fkAddedAt = DocumentModel.addedKey; static const fkAddedAt = DocumentModel.addedKey;
static const _sortFields = [
SortField.created,
SortField.added,
SortField.modified,
SortField.title,
SortField.correspondentName,
SortField.documentType,
SortField.archiveSerialNumber
];
final _formKey = GlobalKey<FormBuilderState>(); final _formKey = GlobalKey<FormBuilderState>();
late final DocumentsCubit _documentsCubit; late final DocumentsCubit _documentsCubit;
@@ -137,7 +127,6 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
const SizedBox( const SizedBox(
height: 16.0, height: 16.0,
), ),
_buildSortByChipsList(context, state),
Align( Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text(S.of(context).documentsFilterPageSearchLabel), child: Text(S.of(context).documentsFilterPageSearchLabel),
@@ -448,71 +437,6 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
); );
} }
Widget _buildSortByChipsList(BuildContext context, DocumentsState state) {
return Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
S.of(context).documentsPageOrderByLabel,
),
SizedBox(
height: kToolbarHeight,
child: ListView.separated(
itemCount: _sortFields.length,
scrollDirection: Axis.horizontal,
separatorBuilder: (context, index) => const SizedBox(
width: 8.0,
),
itemBuilder: (context, index) => _buildActionChip(
_sortFields[index], state.filter.sortField, context),
),
),
],
).padded();
}
Widget _buildActionChip(SortField sortField,
SortField? currentlySelectedOrder, BuildContext context) {
String text;
switch (sortField) {
case SortField.archiveSerialNumber:
text = S.of(context).documentArchiveSerialNumberPropertyShortLabel;
break;
case SortField.correspondentName:
text = S.of(context).documentCorrespondentPropertyLabel;
break;
case SortField.title:
text = S.of(context).documentTitlePropertyLabel;
break;
case SortField.documentType:
text = S.of(context).documentDocumentTypePropertyLabel;
break;
case SortField.created:
text = S.of(context).documentCreatedPropertyLabel;
break;
case SortField.added:
text = S.of(context).documentAddedPropertyLabel;
break;
case SortField.modified:
text = S.of(context).documentModifiedPropertyLabel;
break;
}
final docBloc = BlocProvider.of<DocumentsCubit>(context);
return ActionChip(
label: Text(text),
avatar: currentlySelectedOrder == sortField
? const Icon(
Icons.done,
color: Colors.green,
)
: null,
onPressed: () => docBloc.updateFilter(
filter: docBloc.state.filter.copyWith(sortField: sortField)),
);
}
void _onApplyFilter() async { void _onApplyFilter() async {
if (_formKey.currentState?.saveAndValidate() ?? false) { if (_formKey.currentState?.saveAndValidate() ?? false) {
final v = _formKey.currentState!.value; final v = _formKey.currentState!.value;

View File

@@ -0,0 +1,136 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:paperless_mobile/di_initializer.dart';
import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart';
import 'package:paperless_mobile/features/documents/bloc/documents_state.dart';
import 'package:paperless_mobile/features/documents/model/query_parameters/sort_field.dart';
import 'package:paperless_mobile/features/documents/model/query_parameters/sort_order.dart';
import 'package:paperless_mobile/generated/l10n.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
class SortFieldSelectionBottomSheet extends StatefulWidget {
const SortFieldSelectionBottomSheet({super.key});
@override
State<SortFieldSelectionBottomSheet> createState() =>
_SortFieldSelectionBottomSheetState();
}
class _SortFieldSelectionBottomSheetState
extends State<SortFieldSelectionBottomSheet> {
static const _sortFields = [
SortField.created,
SortField.added,
SortField.modified,
SortField.title,
SortField.correspondentName,
SortField.documentType,
SortField.archiveSerialNumber
];
SortField? _selectedFieldLoading;
SortOrder? _selectedOrderLoading;
@override
Widget build(BuildContext context) {
return ClipRRect(
child: BlocBuilder<DocumentsCubit, DocumentsState>(
bloc: getIt<DocumentsCubit>(),
builder: (context, state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
S.of(context).documentsPageOrderByLabel,
style: Theme.of(context).textTheme.titleSmall,
textAlign: TextAlign.start,
).padded(EdgeInsets.symmetric(horizontal: 16, vertical: 16)),
Column(
children: _sortFields
.map(
(e) => _buildSortOption(
e,
state.filter.sortOrder,
state.filter.sortField == e,
_selectedFieldLoading == e,
),
)
.toList(),
),
],
);
},
),
);
}
Widget _buildSortOption(
SortField field,
SortOrder order,
bool isCurrentlySelected,
bool isNextSelected,
) {
return ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 32),
title: Text(
_localizedSortField(field),
style: Theme.of(context).textTheme.bodyText2,
),
trailing: isNextSelected
? (_buildOrderIcon(_selectedOrderLoading!))
: (_selectedOrderLoading == null && isCurrentlySelected
? _buildOrderIcon(order)
: null),
onTap: () async {
setState(() {
_selectedFieldLoading = field;
_selectedOrderLoading =
isCurrentlySelected ? order.toggle() : SortOrder.descending;
});
BlocProvider.of<DocumentsCubit>(context)
.updateCurrentFilter((filter) => filter.copyWith(
sortOrder: isCurrentlySelected
? order.toggle()
: SortOrder.descending,
sortField: field,
))
.whenComplete(() {
if (mounted) {
setState(() {
_selectedFieldLoading = null;
_selectedOrderLoading = null;
});
}
});
},
);
}
Widget _buildOrderIcon(SortOrder order) {
if (order == SortOrder.ascending) {
return Icon(Icons.arrow_upward);
}
return Icon(Icons.arrow_downward);
}
String _localizedSortField(SortField sortField) {
switch (sortField) {
case SortField.archiveSerialNumber:
return S.of(context).documentArchiveSerialNumberPropertyShortLabel;
case SortField.correspondentName:
return S.of(context).documentCorrespondentPropertyLabel;
case SortField.title:
return S.of(context).documentTitlePropertyLabel;
case SortField.documentType:
return S.of(context).documentDocumentTypePropertyLabel;
case SortField.created:
return S.of(context).documentCreatedPropertyLabel;
case SortField.added:
return S.of(context).documentAddedPropertyLabel;
case SortField.modified:
return S.of(context).documentModifiedPropertyLabel;
}
}
}

View File

@@ -1,11 +1,17 @@
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart'; import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart';
import 'package:paperless_mobile/core/model/error_message.dart'; import 'package:paperless_mobile/core/model/error_message.dart';
import 'package:paperless_mobile/di_initializer.dart';
import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart';
import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_state.dart';
import 'package:paperless_mobile/features/documents/model/query_parameters/sort_field.dart';
import 'package:paperless_mobile/features/documents/model/query_parameters/sort_order.dart'; import 'package:paperless_mobile/features/documents/model/query_parameters/sort_order.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:paperless_mobile/features/documents/view/widgets/search/sort_field_selection_bottom_sheet.dart';
import 'package:paperless_mobile/generated/l10n.dart';
import 'package:paperless_mobile/util.dart'; import 'package:paperless_mobile/util.dart';
class SortDocumentsButton extends StatefulWidget { class SortDocumentsButton extends StatefulWidget {
@@ -18,52 +24,32 @@ class SortDocumentsButton extends StatefulWidget {
} }
class _SortDocumentsButtonState extends State<SortDocumentsButton> { class _SortDocumentsButtonState extends State<SortDocumentsButton> {
bool _isLoading = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<DocumentsCubit, DocumentsState>( return IconButton(
builder: (context, state) { icon: Icon(Icons.sort),
Widget child; onPressed: _onOpenSortBottomSheet,
if (_isLoading) { );
child = const FittedBox( }
fit: BoxFit.scaleDown,
child: RefreshProgressIndicator( void _onOpenSortBottomSheet() {
strokeWidth: 4.0, showModalBottomSheet(
backgroundColor: Colors.transparent, elevation: 2,
), context: context,
); isScrollControlled: true,
} else { shape: const RoundedRectangleBorder(
final bool isAscending = borderRadius: BorderRadius.only(
state.filter.sortOrder == SortOrder.ascending; topLeft: Radius.circular(16),
child = IconButton( topRight: Radius.circular(16),
icon: FaIcon( ),
isAscending ),
? FontAwesomeIcons.arrowDownAZ builder: (context) => BlocProvider.value(
: FontAwesomeIcons.arrowUpZA, value: getIt<DocumentsCubit>(),
), child: FractionallySizedBox(
onPressed: () async { heightFactor: .6,
setState(() => _isLoading = true); child: const SortFieldSelectionBottomSheet(),
try { ),
await BlocProvider.of<DocumentsCubit>(context) ),
.updateCurrentFilter(
(filter) => filter.copyWith(
sortOrder: state.filter.sortOrder.toggle(),
),
);
} on ErrorMessage catch (error, stackTrace) {
showError(context, error, stackTrace);
} finally {
setState(() => _isLoading = false);
}
},
);
}
return SizedBox(
height: Theme.of(context).iconTheme.size,
width: Theme.of(context).iconTheme.size,
child: child,
);
},
); );
} }
} }

View File

@@ -22,175 +22,182 @@ class InfoDrawer extends StatelessWidget {
const InfoDrawer({Key? key}) : super(key: key); const InfoDrawer({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Drawer( return ClipRRect(
child: ListView( borderRadius: BorderRadius.only(
children: [ topRight: Radius.circular(16.0),
DrawerHeader( bottomRight: Radius.circular(16.0),
padding: EdgeInsets.only( ),
top: 8, child: Drawer(
left: 8, child: ListView(
bottom: 0, children: [
right: 8, DrawerHeader(
), padding: const EdgeInsets.only(
child: Column( top: 8,
mainAxisAlignment: MainAxisAlignment.spaceBetween, left: 8,
crossAxisAlignment: CrossAxisAlignment.start, bottom: 0,
children: [ right: 8,
Row( ),
children: [ child: Column(
Image.asset( mainAxisAlignment: MainAxisAlignment.spaceBetween,
"assets/logos/paperless_logo_white.png", crossAxisAlignment: CrossAxisAlignment.start,
height: 32, children: [
width: 32, Row(
color: Theme.of(context).colorScheme.onPrimaryContainer, children: [
).padded(const EdgeInsets.only(right: 8.0)), Image.asset(
Text( "assets/logos/paperless_logo_white.png",
S.of(context).appTitleText, height: 32,
style: Theme.of(context).textTheme.headline5!.copyWith( width: 32,
color: Theme.of(context) color: Theme.of(context).colorScheme.onPrimaryContainer,
.colorScheme ).padded(const EdgeInsets.only(right: 8.0)),
.onPrimaryContainer, Text(
), S.of(context).appTitleText,
), style: Theme.of(context).textTheme.headline5!.copyWith(
], color: Theme.of(context)
), .colorScheme
Align( .onPrimaryContainer,
alignment: Alignment.bottomRight,
child: BlocBuilder<PaperlessServerInformationCubit,
PaperlessServerInformation>(
builder: (context, state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
ListTile(
contentPadding: EdgeInsets.zero,
dense: true,
title: Text(
S.of(context).appDrawerHeaderLoggedInAsText +
(state.username ?? '?'),
style: Theme.of(context).textTheme.bodyText2,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.end,
maxLines: 1,
), ),
subtitle: Column( ),
crossAxisAlignment: CrossAxisAlignment.end, ],
children: [ ),
Text( Align(
state.host ?? '', alignment: Alignment.bottomRight,
style: Theme.of(context).textTheme.bodyText2, child: BlocBuilder<PaperlessServerInformationCubit,
overflow: TextOverflow.ellipsis, PaperlessServerInformation>(
textAlign: TextAlign.end, builder: (context, state) {
maxLines: 1, return Column(
), crossAxisAlignment: CrossAxisAlignment.end,
Text( children: [
'${S.of(context).serverInformationPaperlessVersionText} ${state.version} (API v${state.apiVersion})', ListTile(
style: Theme.of(context).textTheme.caption, contentPadding: EdgeInsets.zero,
overflow: TextOverflow.ellipsis, dense: true,
textAlign: TextAlign.end, title: Text(
maxLines: 1, S.of(context).appDrawerHeaderLoggedInAsText +
), (state.username ?? '?'),
], style: Theme.of(context).textTheme.bodyText2,
), overflow: TextOverflow.ellipsis,
// title: RichText( textAlign: TextAlign.end,
maxLines: 1,
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
state.host ?? '',
style:
Theme.of(context).textTheme.bodyText2,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.end,
maxLines: 1,
),
Text(
'${S.of(context).serverInformationPaperlessVersionText} ${state.version} (API v${state.apiVersion})',
style: Theme.of(context).textTheme.caption,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.end,
maxLines: 1,
),
],
),
// title: RichText(
// text: TextSpan( // text: TextSpan(
// children: [ // children: [
// TextSpan( // TextSpan(
// text: // text:
// style: // style:
// Theme.of(context).textTheme.bodyText2, // Theme.of(context).textTheme.bodyText2,
// ), // ),
// ], // ],
// ), // ),
// ), // ),
isThreeLine: true, isThreeLine: true,
), ),
], ],
); );
}, },
),
),
],
),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
),
),
ListTile(
leading: const Icon(Icons.settings),
title: Text(
S.of(context).appDrawerSettingsLabel,
),
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: getIt<ApplicationSettingsCubit>(),
child: const SettingsPage(),
), ),
), ),
),
),
const Divider(),
ListTile(
leading: const Icon(Icons.bug_report),
title: Text(S.of(context).appDrawerReportBugLabel),
onTap: () {
launchUrlString(
"https://github.com/astubenbord/paperless-mobile/issues/new");
},
),
const Divider(),
AboutListTile(
icon: const Icon(Icons.info),
applicationIcon: const ImageIcon(
AssetImage("assets/logos/paperless_logo_green.png")),
applicationName: "Paperless Mobile",
applicationVersion:
kPackageInfo.version + "+" + kPackageInfo.buildNumber,
aboutBoxChildren: [
Text(
'${S.of(context).aboutDialogDevelopedByText} Anton Stubenbord'),
Link(
uri: Uri.parse(
"https://github.com/astubenbord/paperless-mobile"),
builder: (context, followLink) => GestureDetector(
onTap: followLink,
child: Text(
"https://github.com/astubenbord/paperless-mobile",
style: TextStyle(
color: Theme.of(context).colorScheme.tertiary),
),
),
),
const SizedBox(height: 16),
Text(
"Credits",
style: Theme.of(context).textTheme.titleMedium,
),
_buildOnboardingImageCredits(),
], ],
child: Text(S.of(context).appDrawerAboutLabel),
), ),
decoration: BoxDecoration( const Divider(),
color: Theme.of(context).colorScheme.primaryContainer, ListTile(
leading: const Icon(Icons.logout),
title: Text(S.of(context).appDrawerLogoutLabel),
onTap: () {
try {
BlocProvider.of<AuthenticationCubit>(context).logout();
getIt<DocumentsCubit>().reset();
getIt<CorrespondentCubit>().reset();
getIt<DocumentTypeCubit>().reset();
getIt<TagCubit>().reset();
getIt<DocumentScannerCubit>().reset();
} on ErrorMessage catch (error, stackTrace) {
showError(context, error, stackTrace);
}
},
), ),
), const Divider(),
ListTile( ],
leading: const Icon(Icons.settings), ),
title: Text(
S.of(context).appDrawerSettingsLabel,
),
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: getIt<ApplicationSettingsCubit>(),
child: const SettingsPage(),
),
),
),
),
const Divider(),
ListTile(
leading: const Icon(Icons.bug_report),
title: Text(S.of(context).appDrawerReportBugLabel),
onTap: () {
launchUrlString(
"https://github.com/astubenbord/paperless-mobile/issues/new");
},
),
const Divider(),
AboutListTile(
icon: const Icon(Icons.info),
applicationIcon: const ImageIcon(
AssetImage("assets/logos/paperless_logo_green.png")),
applicationName: "Paperless Mobile",
applicationVersion:
kPackageInfo.version + "+" + kPackageInfo.buildNumber,
aboutBoxChildren: [
Text(
'${S.of(context).aboutDialogDevelopedByText} Anton Stubenbord'),
Link(
uri: Uri.parse(
"https://github.com/astubenbord/paperless-mobile"),
builder: (context, followLink) => GestureDetector(
onTap: followLink,
child: Text(
"https://github.com/astubenbord/paperless-mobile",
style: TextStyle(
color: Theme.of(context).colorScheme.tertiary),
),
),
),
const SizedBox(height: 16),
Text(
"Credits",
style: Theme.of(context).textTheme.titleMedium,
),
_buildOnboardingImageCredits(),
],
child: Text(S.of(context).appDrawerAboutLabel),
),
const Divider(),
ListTile(
leading: const Icon(Icons.logout),
title: Text(S.of(context).appDrawerLogoutLabel),
onTap: () {
try {
BlocProvider.of<AuthenticationCubit>(context).logout();
getIt<DocumentsCubit>().reset();
getIt<CorrespondentCubit>().reset();
getIt<DocumentTypeCubit>().reset();
getIt<TagCubit>().reset();
getIt<DocumentScannerCubit>().reset();
} on ErrorMessage catch (error, stackTrace) {
showError(context, error, stackTrace);
}
},
),
const Divider(),
],
), ),
); );
} }