mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-08 12:07:54 -06:00
Redesigned sorting
This commit is contained in:
@@ -2,7 +2,7 @@ enum SortField {
|
||||
archiveSerialNumber("archive_serial_number"),
|
||||
correspondentName("correspondent__name"),
|
||||
title("title"),
|
||||
documentType("documentType"),
|
||||
documentType("document_type__name"),
|
||||
created("created"),
|
||||
added("added"),
|
||||
modified("modified");
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import 'package:flutter/material.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/logic/error_code_localization_mapper.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_state.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/sort_documents_button.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/login/bloc/authentication_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/model/application_settings_state.dart';
|
||||
import 'package:paperless_mobile/features/settings/model/view_type.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';
|
||||
|
||||
class DocumentsPage extends StatefulWidget {
|
||||
@@ -42,7 +38,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
firstPageKey: 1,
|
||||
);
|
||||
|
||||
final PanelController _panelController = PanelController();
|
||||
final PanelController _filterPanelController = PanelController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -99,9 +95,9 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
Widget build(BuildContext context) {
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
if (_panelController.isPanelOpen) {
|
||||
if (_filterPanelController.isPanelOpen) {
|
||||
FocusScope.of(context).unfocus();
|
||||
_panelController.close();
|
||||
_filterPanelController.close();
|
||||
return false;
|
||||
}
|
||||
final documentsCubit = BlocProvider.of<DocumentsCubit>(context);
|
||||
@@ -129,7 +125,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
backdropEnabled: true,
|
||||
parallaxEnabled: true,
|
||||
parallaxOffset: .5,
|
||||
controller: _panelController,
|
||||
controller: _filterPanelController,
|
||||
defaultPanelState: PanelState.CLOSED,
|
||||
minHeight: 48,
|
||||
maxHeight: (MediaQuery.of(context).size.height * 3) / 4,
|
||||
@@ -140,7 +136,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
body: _buildBody(connectivityState),
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
panelBuilder: (scrollController) => DocumentFilterPanel(
|
||||
panelController: _panelController,
|
||||
panelController: _filterPanelController,
|
||||
scrollController: scrollController,
|
||||
),
|
||||
),
|
||||
@@ -194,33 +190,31 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
|
||||
return RefreshIndicator(
|
||||
onRefresh: _onRefresh,
|
||||
child: Container(
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
DocumentsPageAppBar(
|
||||
actions: [
|
||||
const SortDocumentsButton(),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
settings.preferredViewType == ViewType.grid
|
||||
? Icons.list
|
||||
: Icons.grid_view,
|
||||
),
|
||||
onPressed: () =>
|
||||
BlocProvider.of<ApplicationSettingsCubit>(context)
|
||||
.setViewType(
|
||||
settings.preferredViewType.toggle()),
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
DocumentsPageAppBar(
|
||||
actions: [
|
||||
const SortDocumentsButton(),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
settings.preferredViewType == ViewType.grid
|
||||
? Icons.list
|
||||
: Icons.grid_view,
|
||||
),
|
||||
],
|
||||
),
|
||||
child,
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 4,
|
||||
onPressed: () =>
|
||||
BlocProvider.of<ApplicationSettingsCubit>(context)
|
||||
.setViewType(
|
||||
settings.preferredViewType.toggle()),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
child,
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 4,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -52,16 +52,6 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
static const fkCreatedAt = DocumentModel.createdKey;
|
||||
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>();
|
||||
|
||||
late final DocumentsCubit _documentsCubit;
|
||||
@@ -137,7 +127,6 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
_buildSortByChipsList(context, state),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
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 {
|
||||
if (_formKey.currentState?.saveAndValidate() ?? false) {
|
||||
final v = _formKey.currentState!.value;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.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/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: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';
|
||||
|
||||
class SortDocumentsButton extends StatefulWidget {
|
||||
@@ -18,52 +24,32 @@ class SortDocumentsButton extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SortDocumentsButtonState extends State<SortDocumentsButton> {
|
||||
bool _isLoading = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<DocumentsCubit, DocumentsState>(
|
||||
builder: (context, state) {
|
||||
Widget child;
|
||||
if (_isLoading) {
|
||||
child = const FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: RefreshProgressIndicator(
|
||||
strokeWidth: 4.0,
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
final bool isAscending =
|
||||
state.filter.sortOrder == SortOrder.ascending;
|
||||
child = IconButton(
|
||||
icon: FaIcon(
|
||||
isAscending
|
||||
? FontAwesomeIcons.arrowDownAZ
|
||||
: FontAwesomeIcons.arrowUpZA,
|
||||
),
|
||||
onPressed: () async {
|
||||
setState(() => _isLoading = true);
|
||||
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,
|
||||
);
|
||||
},
|
||||
return IconButton(
|
||||
icon: Icon(Icons.sort),
|
||||
onPressed: _onOpenSortBottomSheet,
|
||||
);
|
||||
}
|
||||
|
||||
void _onOpenSortBottomSheet() {
|
||||
showModalBottomSheet(
|
||||
elevation: 2,
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16),
|
||||
),
|
||||
),
|
||||
builder: (context) => BlocProvider.value(
|
||||
value: getIt<DocumentsCubit>(),
|
||||
child: FractionallySizedBox(
|
||||
heightFactor: .6,
|
||||
child: const SortFieldSelectionBottomSheet(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,175 +22,182 @@ class InfoDrawer extends StatelessWidget {
|
||||
const InfoDrawer({Key? key}) : super(key: key);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Drawer(
|
||||
child: ListView(
|
||||
children: [
|
||||
DrawerHeader(
|
||||
padding: 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,
|
||||
).padded(const EdgeInsets.only(right: 8.0)),
|
||||
Text(
|
||||
S.of(context).appTitleText,
|
||||
style: Theme.of(context).textTheme.headline5!.copyWith(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimaryContainer,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Align(
|
||||
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,
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(16.0),
|
||||
bottomRight: Radius.circular(16.0),
|
||||
),
|
||||
child: Drawer(
|
||||
child: ListView(
|
||||
children: [
|
||||
DrawerHeader(
|
||||
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,
|
||||
).padded(const EdgeInsets.only(right: 8.0)),
|
||||
Text(
|
||||
S.of(context).appTitleText,
|
||||
style: Theme.of(context).textTheme.headline5!.copyWith(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimaryContainer,
|
||||
),
|
||||
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(
|
||||
),
|
||||
],
|
||||
),
|
||||
Align(
|
||||
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(
|
||||
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(
|
||||
// children: [
|
||||
// TextSpan(
|
||||
// text:
|
||||
// style:
|
||||
// Theme.of(context).textTheme.bodyText2,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
isThreeLine: true,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
// text: TextSpan(
|
||||
// children: [
|
||||
// TextSpan(
|
||||
// text:
|
||||
// style:
|
||||
// Theme.of(context).textTheme.bodyText2,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
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(
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
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);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
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(),
|
||||
],
|
||||
const Divider(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user