Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Improve inbox loading animation, fix refresh indicator positions #124

Merged
merged 3 commits into from
Feb 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import 'dart:io';

import 'package:badges/badges.dart' as b;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:open_filex/open_filex.dart';
Expand All @@ -22,12 +19,8 @@ import 'package:paperless_mobile/features/documents/view/widgets/document_previe
import 'package:paperless_mobile/features/similar_documents/cubit/similar_documents_cubit.dart';
import 'package:paperless_mobile/features/similar_documents/view/similar_documents_view.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';

import 'package:paperless_mobile/helpers/message_helpers.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';

//TODO: Refactor this into several widgets
class DocumentDetailsPage extends StatefulWidget {
final bool allowEdit;
final bool isLabelClickable;
Expand Down
62 changes: 31 additions & 31 deletions lib/features/documents/view/pages/documents_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -287,39 +287,39 @@ class _DocumentsPageState extends State<DocumentsPage>
ConnectivityState connectivityState,
BuildContext context,
) {
return RefreshIndicator(
edgeOffset: kTextTabBarHeight,
onRefresh: _onReloadDocuments,
notificationPredicate: (_) => connectivityState.isConnected,
child: NotificationListener<ScrollNotification>(
onNotification: (notification) {
// Listen for scroll notifications to load new data.
// Scroll controller does not work here due to nestedscrollview limitations.
return NotificationListener<ScrollNotification>(
onNotification: (notification) {
// Listen for scroll notifications to load new data.
// Scroll controller does not work here due to nestedscrollview limitations.

final currState = context.read<DocumentsCubit>().state;
final max = notification.metrics.maxScrollExtent;
if (max == 0 ||
_currentTab != 0 ||
currState.isLoading ||
currState.isLastPageLoaded) {
return true;
}
final currState = context.read<DocumentsCubit>().state;
final max = notification.metrics.maxScrollExtent;
if (max == 0 ||
_currentTab != 0 ||
currState.isLoading ||
currState.isLastPageLoaded) {
return true;
}

final offset = notification.metrics.pixels;
if (offset >= max * 0.7) {
context
.read<DocumentsCubit>()
.loadMore()
.onError<PaperlessServerException>(
(error, stackTrace) => showErrorMessage(
context,
error,
stackTrace,
),
);
}
return false;
},
final offset = notification.metrics.pixels;
if (offset >= max * 0.7) {
context
.read<DocumentsCubit>()
.loadMore()
.onError<PaperlessServerException>(
(error, stackTrace) => showErrorMessage(
context,
error,
stackTrace,
),
);
}
return false;
},
child: RefreshIndicator(
edgeOffset: kTextTabBarHeight,
onRefresh: _onReloadDocuments,
notificationPredicate: (_) => connectivityState.isConnected,
child: CustomScrollView(
key: const PageStorageKey<String>("documents"),
slivers: <Widget>[
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';

class TagsPlaceholder extends StatelessWidget {
static const _lengths = [24, 36, 16, 48];
static const _lengths = <double>[90, 70, 130];
final int count;
final bool dense;
const TagsPlaceholder({
Expand All @@ -14,24 +15,23 @@ class TagsPlaceholder extends StatelessWidget {
Widget build(BuildContext context) {
return SizedBox(
height: 32,
child: ListView.separated(
padding: EdgeInsets.zero,
itemCount: count,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => FilterChip(
labelPadding:
dense ? const EdgeInsets.symmetric(horizontal: 2) : null,
padding: dense ? const EdgeInsets.all(4) : null,
visualDensity: const VisualDensity(vertical: -2),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
side: BorderSide.none,
onSelected: (_) {},
selected: false,
label: Text(
List.filled(_lengths[index], " ").join(),
),
physics: const NeverScrollableScrollPhysics(),
child: Row(
children: List.generate(count, (index) => index)
.map(
(index) => Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
width: _lengths[index % _lengths.length],
height: 32,
).paddedOnly(right: 4),
)
.toList(),
),
separatorBuilder: (context, _) => const SizedBox(width: 4),
),
);
}
Expand Down
28 changes: 28 additions & 0 deletions lib/features/inbox/cubit/inbox_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,34 @@ class InboxCubit extends HydratedCubit<InboxState>
);
}

///
/// Fetches inbox tag ids and loads the inbox items (documents).
///
Future<void> reloadInbox() async {
emit(state.copyWith(hasLoaded: false, isLoading: true));
final inboxTags = await _tagsRepository.findAll().then(
(tags) => tags.where((t) => t.isInboxTag ?? false).map((t) => t.id!),
);

if (inboxTags.isEmpty) {
// no inbox tags = no inbox items.
return emit(
state.copyWith(
hasLoaded: true,
value: [],
inboxTags: [],
),
);
}
emit(state.copyWith(inboxTags: inboxTags));
updateFilter(
filter: DocumentFilter(
sortField: SortField.added,
tags: IdsTagsQuery.fromIds(inboxTags),
),
);
}

///
/// Updates the document with all inbox tags removed and removes the document
/// from the inbox.
Expand Down
11 changes: 4 additions & 7 deletions lib/features/inbox/view/pages/inbox_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,18 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart';
import 'package:paperless_mobile/features/document_search/view/document_search_page.dart';
import 'package:paperless_mobile/core/widgets/hint_card.dart';
import 'package:paperless_mobile/extensions/dart_extensions.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart';
import 'package:paperless_mobile/features/document_search/view/sliver_search_bar.dart';
import 'package:paperless_mobile/features/documents/view/widgets/placeholder/documents_list_loading_widget.dart';
import 'package:paperless_mobile/features/inbox/cubit/inbox_cubit.dart';
import 'package:paperless_mobile/features/inbox/view/widgets/inbox_empty_widget.dart';
import 'package:paperless_mobile/features/inbox/view/widgets/inbox_item.dart';
import 'package:paperless_mobile/features/inbox/view/widgets/inbox_list_loading_widget.dart';
import 'package:paperless_mobile/features/paged_document_view/view/document_paging_view_mixin.dart';
import 'package:paperless_mobile/features/search_app_bar/view/search_app_bar.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';

import 'package:paperless_mobile/helpers/message_helpers.dart';

class InboxPage extends StatefulWidget {
Expand All @@ -38,7 +36,7 @@ class _InboxPageState extends State<InboxPage>
@override
void initState() {
super.initState();
context.read<InboxCubit>().loadInbox();
context.read<InboxCubit>().reloadInbox();
}

@override
Expand Down Expand Up @@ -76,7 +74,7 @@ class _InboxPageState extends State<InboxPage>
body: Builder(
builder: (context) {
if (!state.hasLoaded) {
return const DocumentsListLoadingWidget(); //TODO: Implement InboxLoadingWidget...
return const InboxListLoadingWidget();
} else if (state.documents.isEmpty) {
return Center(
child: InboxEmptyWidget(
Expand All @@ -86,7 +84,6 @@ class _InboxPageState extends State<InboxPage>
);
} else {
return RefreshIndicator(
edgeOffset: kToolbarHeight,
onRefresh: context.read<InboxCubit>().reload,
child: CustomScrollView(
slivers: [
Expand Down
4 changes: 2 additions & 2 deletions lib/features/inbox/view/widgets/inbox_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
import 'package:paperless_mobile/routes/document_details_route.dart';

class InboxItem extends StatefulWidget {
static const _a4AspectRatio = 1 / 1.4142;
static const a4AspectRatio = 1 / 1.4142;

final DocumentModel document;
const InboxItem({
Expand Down Expand Up @@ -53,7 +53,7 @@ class _InboxItemState extends State<InboxItem> {
child: Row(
children: [
AspectRatio(
aspectRatio: InboxItem._a4AspectRatio,
aspectRatio: InboxItem.a4AspectRatio,
child: DocumentPreview(
document: widget.document,
fit: BoxFit.cover,
Expand Down
125 changes: 125 additions & 0 deletions lib/features/inbox/view/widgets/inbox_list_loading_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import 'package:flutter/material.dart';
import 'package:paperless_mobile/core/widgets/shimmer_placeholder.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/documents/view/widgets/placeholder/tags_placeholder.dart';
import 'package:paperless_mobile/features/documents/view/widgets/placeholder/text_placeholder.dart';
import 'package:paperless_mobile/features/inbox/view/widgets/inbox_item.dart';

class InboxListLoadingWidget extends StatelessWidget {
const InboxListLoadingWidget({super.key});

@override
Widget build(BuildContext context) {
return ListView.separated(
itemCount: 20,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => _buildInboxItem().padded(),
separatorBuilder: (context, index) => const SizedBox(height: 16),
).paddedOnly(top: 8);
}

Widget _buildInboxItem() {
return ShimmerPlaceholder(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const TextPlaceholder(length: 150, fontSize: 12),
const SizedBox(
height: 16,
),
SizedBox(
height: 200,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 150,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 120,
width: 90,
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: const ColoredBox(
color: Colors.white,
),
),
),
const SizedBox(width: 8),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Spacer(),
TextPlaceholder(length: 200, fontSize: 14),
Spacer(),
TextPlaceholder(length: 120, fontSize: 14),
SizedBox(height: 8),
TextPlaceholder(length: 170, fontSize: 14),
Spacer(),
TagsPlaceholder(count: 3, dense: true),
Spacer(),
],
),
),
],
),
),
SizedBox(
height: 50,
child: IntrinsicHeight(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
physics: const NeverScrollableScrollPhysics(),
child: Row(
children: [
const SizedBox(
width: 50,
height: 40,
child: ColoredBox(
color: Colors.white,
),
).padded(),
const VerticalDivider(
indent: 12,
endIndent: 12,
),
SizedBox(
height: 40,
child: Row(
children: [
Container(
width: 150,
height: 48,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white,
),
),
const SizedBox(width: 4),
Container(
width: 200,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white,
),
),
],
),
),
],
),
),
),
),
],
),
),
],
),
);
}
}
4 changes: 1 addition & 3 deletions lib/features/labels/view/pages/labels_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import 'package:paperless_mobile/core/delegate/customizable_sliver_persistent_he
import 'package:paperless_mobile/core/repository/label_repository.dart';
import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart';
import 'package:paperless_mobile/features/document_details/view/pages/document_details_page.dart';
import 'package:paperless_mobile/features/document_search/view/document_search_page.dart';
import 'package:paperless_mobile/features/document_search/view/sliver_search_bar.dart';
import 'package:paperless_mobile/features/edit_label/view/impl/add_correspondent_page.dart';
import 'package:paperless_mobile/features/edit_label/view/impl/add_document_type_page.dart';
Expand All @@ -18,7 +17,6 @@ import 'package:paperless_mobile/features/edit_label/view/impl/edit_storage_path
import 'package:paperless_mobile/features/edit_label/view/impl/edit_tag_page.dart';
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
import 'package:paperless_mobile/features/labels/view/widgets/label_tab_view.dart';
import 'package:paperless_mobile/features/search_app_bar/view/search_app_bar.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';

class LabelsPage extends StatefulWidget {
Expand Down Expand Up @@ -140,7 +138,7 @@ class _LabelsPageState extends State<LabelsPage>
return true;
},
child: RefreshIndicator(
edgeOffset: kToolbarHeight + kTextTabBarHeight,
edgeOffset: kTextTabBarHeight,
notificationPredicate: (notification) =>
connectedState.isConnected,
onRefresh: () => [
Expand Down
Loading