diff --git a/lib/components/loading.dart b/lib/components/loading.dart index a8deca3..9a0e9a7 100644 --- a/lib/components/loading.dart +++ b/lib/components/loading.dart @@ -13,6 +13,40 @@ abstract class LoadingState extends Widget buildContent(BuildContext context, S data); + Widget buildError() { + return Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(error!), + const SizedBox(height: 12), + Button( + onPressed: () { + setState(() { + isLoading = true; + error = null; + }); + loadData().then((value) { + if(value.success) { + setState(() { + isLoading = false; + data = value.data; + }); + } else { + setState(() { + isLoading = false; + error = value.errorMessage!; + }); + } + }); + }, + child: const Text("Retry"), + ) + ], + ), + ).paddingHorizontal(16); + } + @override @mustCallSuper void initState() { @@ -40,9 +74,7 @@ abstract class LoadingState extends child: ProgressRing(), ); } else if (error != null){ - return Center( - child: Text(error!), - ); + return buildError(); } else { return buildContent(context, data!); } @@ -131,8 +163,20 @@ abstract class MultiPageLoadingState Widget buildError(BuildContext context, String error) { return Center( - child: Text(error), - ); + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(error), + const SizedBox(height: 12), + Button( + onPressed: () { + reset(); + }, + child: const Text("Retry"), + ) + ], + ), + ).paddingHorizontal(16); } @override diff --git a/lib/components/title_bar.dart b/lib/components/title_bar.dart new file mode 100644 index 0000000..05b2de4 --- /dev/null +++ b/lib/components/title_bar.dart @@ -0,0 +1,25 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:pixes/foundation/app.dart'; + +class TitleBar extends StatelessWidget { + const TitleBar({required this.title, this.action, super.key}); + + final String title; + + final Widget? action; + + @override + Widget build(BuildContext context) { + return SizedBox( + child: Row( + children: [ + Text(title, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),), + const Spacer(), + if(action != null) + action! + ], + ).paddingHorizontal(16).paddingVertical(8), + ); + } +} diff --git a/lib/pages/bookmarks.dart b/lib/pages/bookmarks.dart index ba0dda0..09a1ad2 100644 --- a/lib/pages/bookmarks.dart +++ b/lib/pages/bookmarks.dart @@ -1,7 +1,7 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:pixes/components/segmented_button.dart'; -import 'package:pixes/foundation/app.dart'; +import 'package:pixes/components/title_bar.dart'; import 'package:pixes/network/network.dart'; import 'package:pixes/utils/translation.dart'; @@ -31,26 +31,23 @@ class _BookMarkedArtworkPageState extends State{ } Widget buildTab() { - return Row( - children: [ - Text("Following".tl, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20)), - const Spacer(), - SegmentedButton( - options: [ - SegmentedButtonOption("public", "Public".tl), - SegmentedButtonOption("private", "Private".tl), - ], - onPressed: (key) { - if(key != restrict) { - setState(() { - restrict = key; - }); - } - }, - value: restrict, - ) - ], - ).paddingHorizontal(16).paddingVertical(4); + return TitleBar( + title: "Bookmarks".tl, + action: SegmentedButton( + options: [ + SegmentedButtonOption("public", "Public".tl), + SegmentedButtonOption("private", "Private".tl), + ], + onPressed: (key) { + if(key != restrict) { + setState(() { + restrict = key; + }); + } + }, + value: restrict, + ), + ); } } diff --git a/lib/pages/following_artworks.dart b/lib/pages/following_artworks.dart index 36882f5..a23cd8c 100644 --- a/lib/pages/following_artworks.dart +++ b/lib/pages/following_artworks.dart @@ -1,6 +1,6 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; -import 'package:pixes/foundation/app.dart'; +import 'package:pixes/components/title_bar.dart'; import 'package:pixes/utils/translation.dart'; import '../components/illust_widget.dart'; @@ -31,28 +31,24 @@ class _FollowingArtworksPageState extends State { } Widget buildTab() { - return Row( - children: [ - Text("Following".tl, - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),), - const Spacer(), - SegmentedButton( - options: [ - SegmentedButtonOption("all", "All".tl), - SegmentedButtonOption("public", "Public".tl), - SegmentedButtonOption("private", "Private".tl), - ], - onPressed: (key) { - if(key != restrict) { - setState(() { - restrict = key; - }); - } - }, - value: restrict, - ) - ], - ).paddingHorizontal(16).paddingBottom(4); + return TitleBar( + title: "Following".tl, + action: SegmentedButton( + options: [ + SegmentedButtonOption("all", "All".tl), + SegmentedButtonOption("public", "Public".tl), + SegmentedButtonOption("private", "Private".tl), + ], + onPressed: (key) { + if(key != restrict) { + setState(() { + restrict = key; + }); + } + }, + value: restrict, + ), + ); } } diff --git a/lib/pages/recommendation_page.dart b/lib/pages/recommendation_page.dart index 1e70158..6b9de18 100644 --- a/lib/pages/recommendation_page.dart +++ b/lib/pages/recommendation_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:pixes/components/illust_widget.dart'; import 'package:pixes/components/loading.dart'; +import 'package:pixes/components/title_bar.dart'; import 'package:pixes/foundation/app.dart'; import 'package:pixes/network/network.dart'; import 'package:pixes/utils/translation.dart'; @@ -35,28 +36,22 @@ class _RecommendationPageState extends State { } Widget buildTab() { - return SizedBox( - child: Row( - children: [ - Text("Explore".tl, - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),), - const Spacer(), - SegmentedButton( - options: [ - SegmentedButtonOption(0, "Artworks".tl), - SegmentedButtonOption(1, "Users".tl), - ], - onPressed: (key) { - if(key != type) { - setState(() { - type = key; - }); - } - }, - value: type, - ) + return TitleBar( + title: "Explore".tl, + action: SegmentedButton( + options: [ + SegmentedButtonOption(0, "Artworks".tl), + SegmentedButtonOption(1, "Users".tl), ], - ).paddingHorizontal(16).paddingBottom(4), + onPressed: (key) { + if(key != type) { + setState(() { + type = key; + }); + } + }, + value: type, + ), ); } } diff --git a/lib/pages/search_page.dart b/lib/pages/search_page.dart index 750c47e..0c5401e 100644 --- a/lib/pages/search_page.dart +++ b/lib/pages/search_page.dart @@ -58,7 +58,7 @@ class _SearchPageState extends State { @override Widget build(BuildContext context) { return ScaffoldPage( - padding: EdgeInsets.zero, + padding: const EdgeInsets.only(top: 8), content: Column( children: [ buildSearchBar(),