From 3338e699c4748cf3cf767b5869ece59fb7ac12b8 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Thu, 20 Feb 2025 22:09:05 +0800 Subject: [PATCH] :lipstick: Memorable realm view style --- lib/providers/config.dart | 8 ++ lib/screens/album.dart | 3 - lib/screens/realm.dart | 146 ++++++------------------- lib/screens/realm/realm_discovery.dart | 84 ++++---------- lib/widgets/realm/realm_item.dart | 123 +++++++++++++++++++++ 5 files changed, 186 insertions(+), 178 deletions(-) create mode 100644 lib/widgets/realm/realm_item.dart diff --git a/lib/providers/config.dart b/lib/providers/config.dart index f3f4d92..87c6f22 100644 --- a/lib/providers/config.dart +++ b/lib/providers/config.dart @@ -17,6 +17,7 @@ const kAppDrawerPreferCollapse = 'app_drawer_prefer_collapse'; const kAppNotifyWithHaptic = 'app_notify_with_haptic'; const kAppExpandPostLink = 'app_expand_post_link'; const kAppExpandChatLink = 'app_expand_chat_link'; +const kAppRealmCompactView = 'app_realm_compact_view'; const Map kImageQualityLevel = { 'settingsImageQualityLowest': FilterQuality.none, @@ -72,6 +73,13 @@ class ConfigProvider extends ChangeNotifier { return prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault; } + bool get realmCompactView { + return prefs.getBool(kAppRealmCompactView) ?? false; + } + set realmCompactView(bool value) { + prefs.setBool(kAppRealmCompactView, value); + } + set serverUrl(String url) { prefs.setString(kNetworkServerStoreKey, url); _home.saveWidgetData("nex_server_url", url); diff --git a/lib/screens/album.dart b/lib/screens/album.dart index e7bcd36..d519a59 100644 --- a/lib/screens/album.dart +++ b/lib/screens/album.dart @@ -1,6 +1,3 @@ -import 'dart:convert'; -import 'dart:developer'; - import 'package:dismissible_page/dismissible_page.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; diff --git a/lib/screens/realm.dart b/lib/screens/realm.dart index 59a1fa9..2a63f5c 100644 --- a/lib/screens/realm.dart +++ b/lib/screens/realm.dart @@ -4,17 +4,16 @@ import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:provider/provider.dart'; -import 'package:styled_widget/styled_widget.dart'; +import 'package:surface/providers/config.dart'; import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/userinfo.dart'; import 'package:surface/types/realm.dart'; -import 'package:surface/widgets/account/account_image.dart'; import 'package:surface/widgets/app_bar_leading.dart'; import 'package:surface/widgets/dialog.dart'; import 'package:surface/widgets/loading_indicator.dart'; import 'package:surface/widgets/navigation/app_scaffold.dart'; +import 'package:surface/widgets/realm/realm_item.dart'; import 'package:surface/widgets/unauthorized_hint.dart'; -import 'package:surface/widgets/universal_image.dart'; class RealmScreen extends StatefulWidget { const RealmScreen({super.key}); @@ -75,12 +74,12 @@ class _RealmScreenState extends State { @override void initState() { super.initState(); + _isCompactView = context.read().realmCompactView; _fetchRealms(); } @override Widget build(BuildContext context) { - final sn = context.read(); final ua = context.read(); if (!ua.isAuthorized) { @@ -110,6 +109,7 @@ class _RealmScreenState extends State { icon: !_isCompactView ? const Icon(Symbols.view_list) : const Icon(Symbols.view_module), onPressed: () { setState(() => _isCompactView = !_isCompactView); + context.read().realmCompactView = _isCompactView; }, ), const Gap(8), @@ -134,129 +134,45 @@ class _RealmScreenState extends State { itemCount: _realms?.length ?? 0, itemBuilder: (context, idx) { final realm = _realms![idx]; - if (_isCompactView) { - return ListTile( - contentPadding: const EdgeInsets.symmetric(horizontal: 16), - leading: AccountImage( - content: realm.avatar, - fallbackWidget: const Icon(Symbols.group, size: 20), - ), - title: Text(realm.name), - subtitle: Text( - realm.description, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - trailing: PopupMenuButton( - itemBuilder: (BuildContext context) => [ - PopupMenuItem( - child: Row( - children: [ - const Icon(Symbols.edit), - const Gap(16), - Text('edit').tr(), - ], - ), - onTap: () { - GoRouter.of(context).pushNamed( - 'realmManage', - queryParameters: {'editing': realm.alias}, - ).then((value) { - if (value != null) { - _fetchRealms(); - } - }); - }, - ), - PopupMenuItem( - child: Row( - children: [ - const Icon(Symbols.delete), - const Gap(16), - Text('delete').tr(), - ], - ), - onTap: () { - _deleteRealm(realm); - }, - ), - ], - ), - onTap: () { - GoRouter.of(context).pushNamed( - 'realmDetail', - pathParameters: {'alias': realm.alias}, - ).then((value) { - if (value == true) { - _fetchRealms(); - } - }); - }, - ); - } - return Container( - constraints: BoxConstraints(maxWidth: 640), - child: Card( - margin: const EdgeInsets.all(12), - child: InkWell( - borderRadius: const BorderRadius.all(Radius.circular(8)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + return RealmItemWidget( + item: realm, + isListView: _isCompactView, + actionListView: [ + PopupMenuItem( + child: Row( children: [ - AspectRatio( - aspectRatio: 16 / 7, - child: Stack( - clipBehavior: Clip.none, - fit: StackFit.expand, - children: [ - ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(8)), - child: Container( - color: Theme.of(context).colorScheme.surfaceContainer, - child: (realm.banner?.isEmpty ?? true) - ? const SizedBox.shrink() - : AutoResizeUniversalImage( - sn.getAttachmentUrl(realm.banner!), - fit: BoxFit.cover, - ), - ), - ), - Positioned( - bottom: -30, - left: 18, - child: AccountImage( - content: realm.avatar, - radius: 24, - fallbackWidget: const Icon(Symbols.group, size: 24), - ), - ), - ], - ), - ), - const Gap(20 + 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(realm.name).textStyle(Theme.of(context).textTheme.titleMedium!), - Text(realm.description).textStyle(Theme.of(context).textTheme.bodySmall!), - ], - ).padding(horizontal: 24, bottom: 14), + const Icon(Symbols.edit), + const Gap(16), + Text('edit').tr(), ], ), onTap: () { GoRouter.of(context).pushNamed( - 'realmDetail', - pathParameters: {'alias': realm.alias}, + 'realmManage', + queryParameters: {'editing': realm.alias}, ).then((value) { - if (value == true) { + if (value != null) { _fetchRealms(); } }); }, ), - ), - ).center(); + PopupMenuItem( + child: Row( + children: [ + const Icon(Symbols.delete), + const Gap(16), + Text('delete').tr(), + ], + ), + onTap: () { + _deleteRealm(realm); + }, + ), + ], + onUpdate: _fetchRealms, + ); }, ), ), diff --git a/lib/screens/realm/realm_discovery.dart b/lib/screens/realm/realm_discovery.dart index 5e22d85..7e1b083 100644 --- a/lib/screens/realm/realm_discovery.dart +++ b/lib/screens/realm/realm_discovery.dart @@ -4,6 +4,7 @@ import 'package:gap/gap.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:provider/provider.dart'; import 'package:styled_widget/styled_widget.dart'; +import 'package:surface/providers/config.dart'; import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/userinfo.dart'; import 'package:surface/types/chat.dart'; @@ -12,6 +13,7 @@ import 'package:surface/widgets/account/account_image.dart'; import 'package:surface/widgets/dialog.dart'; import 'package:surface/widgets/loading_indicator.dart'; import 'package:surface/widgets/navigation/app_scaffold.dart'; +import 'package:surface/widgets/realm/realm_item.dart'; import 'package:surface/widgets/universal_image.dart'; class RealmDiscoveryScreen extends StatefulWidget { @@ -24,6 +26,7 @@ class RealmDiscoveryScreen extends StatefulWidget { class _RealmDiscoveryScreenState extends State { List? _realms; bool _isBusy = false; + bool _isCompactView = false; Future _fetchRealms() async { try { @@ -44,16 +47,25 @@ class _RealmDiscoveryScreenState extends State { @override void initState() { super.initState(); + _isCompactView = context.read().realmCompactView; _fetchRealms(); } @override Widget build(BuildContext context) { - final sn = context.read(); - return AppScaffold( appBar: AppBar( title: Text('screenRealmDiscovery').tr(), + actions: [ + IconButton( + icon: _isCompactView ? const Icon(Symbols.view_list) : const Icon(Symbols.view_module), + onPressed: () { + setState(() => _isCompactView = !_isCompactView); + context.read().realmCompactView = _isCompactView; + }, + ), + const Gap(8), + ], ), body: Column( children: [ @@ -66,64 +78,16 @@ class _RealmDiscoveryScreenState extends State { itemCount: _realms?.length ?? 0, itemBuilder: (context, idx) { final realm = _realms![idx]; - return Container( - constraints: BoxConstraints(maxWidth: 640), - child: Card( - margin: const EdgeInsets.all(12), - child: InkWell( - borderRadius: const BorderRadius.all(Radius.circular(8)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AspectRatio( - aspectRatio: 16 / 7, - child: Stack( - clipBehavior: Clip.none, - fit: StackFit.expand, - children: [ - ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(8)), - child: Container( - color: Theme.of(context).colorScheme.surfaceContainer, - child: (realm.banner?.isEmpty ?? true) - ? const SizedBox.shrink() - : AutoResizeUniversalImage( - sn.getAttachmentUrl(realm.banner!), - fit: BoxFit.cover, - ), - ), - ), - Positioned( - bottom: -30, - left: 18, - child: AccountImage( - content: realm.avatar, - radius: 24, - fallbackWidget: const Icon(Symbols.group, size: 24), - ), - ), - ], - ), - ), - const Gap(20 + 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(realm.name).textStyle(Theme.of(context).textTheme.titleMedium!), - Text(realm.description).textStyle(Theme.of(context).textTheme.bodySmall!), - ], - ).padding(horizontal: 24, bottom: 14), - ], - ), - onTap: () { - showModalBottomSheet( - context: context, - builder: (context) => _RealmJoinPopup(realm: realm), - ); - }, - ), - ), - ).center(); + return RealmItemWidget( + item: realm, + isListView: _isCompactView, + onTap: () { + showModalBottomSheet( + context: context, + builder: (context) => _RealmJoinPopup(realm: realm), + ); + }, + ); }, ), ), diff --git a/lib/widgets/realm/realm_item.dart b/lib/widgets/realm/realm_item.dart new file mode 100644 index 0000000..2c63c80 --- /dev/null +++ b/lib/widgets/realm/realm_item.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:go_router/go_router.dart'; +import 'package:material_symbols_icons/symbols.dart'; +import 'package:provider/provider.dart'; +import 'package:styled_widget/styled_widget.dart'; +import 'package:surface/providers/sn_network.dart'; +import 'package:surface/types/realm.dart'; +import 'package:surface/widgets/account/account_image.dart'; +import 'package:surface/widgets/universal_image.dart'; + +class RealmItemWidget extends StatelessWidget { + final SnRealm item; + final bool isListView; + final List? actionListView; + final Function? onUpdate; + final Function? onTap; + + const RealmItemWidget({ + super.key, + required this.item, + required this.isListView, + this.actionListView, + this.onUpdate, + this.onTap, + }); + + @override + Widget build(BuildContext context) { + if (isListView) { + return ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 16), + leading: AccountImage( + content: item.avatar, + fallbackWidget: const Icon(Symbols.group, size: 20), + ), + title: Text(item.name), + subtitle: Text( + item.description, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + trailing: PopupMenuButton(itemBuilder: (BuildContext context) => actionListView ?? []), + onTap: () { + GoRouter.of(context).pushNamed( + 'realmDetail', + pathParameters: {'alias': item.alias}, + ).then((value) { + if (value == true) { + onUpdate?.call(); + } + }); + }, + ); + } + + final sn = context.read(); + + return Container( + constraints: BoxConstraints(maxWidth: 640), + child: Card( + margin: const EdgeInsets.all(12), + child: InkWell( + borderRadius: const BorderRadius.all(Radius.circular(8)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: 16 / 7, + child: Stack( + clipBehavior: Clip.none, + fit: StackFit.expand, + children: [ + ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(8)), + child: Container( + color: Theme.of(context).colorScheme.surfaceContainer, + child: (item.banner?.isEmpty ?? true) + ? const SizedBox.shrink() + : AutoResizeUniversalImage( + sn.getAttachmentUrl(item.banner!), + fit: BoxFit.cover, + ), + ), + ), + Positioned( + bottom: -30, + left: 18, + child: AccountImage( + content: item.avatar, + radius: 24, + fallbackWidget: const Icon(Symbols.group, size: 24), + ), + ), + ], + ), + ), + const Gap(20 + 12), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(item.name).textStyle(Theme.of(context).textTheme.titleMedium!), + Text(item.description).textStyle(Theme.of(context).textTheme.bodySmall!), + ], + ).padding(horizontal: 24, bottom: 14), + ], + ), + onTap: () { + if (onTap != null) onTap!(); + GoRouter.of(context).pushNamed( + 'realmDetail', + pathParameters: {'alias': item.alias}, + ).then((value) { + if (value == true) { + onUpdate?.call(); + } + }); + }, + ), + ), + ).center(); + } +}