diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index d6bd22c..7c90156 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -80,6 +80,9 @@ "deleteChatRoom": "Delete Room", "deleteChatRoomHint": "Are you sure to delete this room? This action cannot be undone.", "chat": "Chat", + "chatTabAll": "All", + "chatTabDirect": "Direct Messages", + "chatTabGroup": "Group Chats", "chatMessageHint": "Message in {}", "chatDirectMessageHint": "Message to {}", "directMessage": "Direct Message", diff --git a/assets/i18n/zh-CN.json b/assets/i18n/zh-CN.json index 9e26dfe..8cc3ede 100644 --- a/assets/i18n/zh-CN.json +++ b/assets/i18n/zh-CN.json @@ -1 +1,8 @@ -{} \ No newline at end of file +{ + "chat": "聊天", + "chatTabAll": "全部", + "chatTabDirect": "私聊", + "chatTabGroup": "群聊", + "chatMessageHint": "在 {} 中发送消息", + "chatDirectMessageHint": "发送消息给 {}" +} \ No newline at end of file diff --git a/lib/database/message_repository.dart b/lib/database/message_repository.dart index 37bdc26..2c202fd 100644 --- a/lib/database/message_repository.dart +++ b/lib/database/message_repository.dart @@ -15,6 +15,7 @@ class MessageRepository { final Map pendingMessages = {}; final Map> fileUploadProgress = {}; + int? _totalCount; MessageRepository(this.room, this.identity, this._apiClient, this._database); @@ -141,12 +142,27 @@ class MessageRepository { int offset = 0, int take = 20, }) async { + // Use cached total count if available, otherwise fetch it + if (_totalCount == null) { + final response = await _apiClient.get( + '/chat/$roomId/messages', + queryParameters: {'offset': 0, 'take': 1}, + ); + _totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0'); + } + + if (offset >= _totalCount!) { + return []; + } + final response = await _apiClient.get( '/chat/$roomId/messages', queryParameters: {'offset': offset, 'take': take}, ); final List data = response.data; + // Update total count from response headers + _totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0'); final messages = data.map((json) { diff --git a/lib/pods/config.dart b/lib/pods/config.dart index 3d5377c..9751a45 100644 --- a/lib/pods/config.dart +++ b/lib/pods/config.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:responsive_framework/responsive_framework.dart'; import 'package:shared_preferences/shared_preferences.dart'; const kTokenPairStoreKey = 'dyn_user_tk'; @@ -147,24 +146,3 @@ class UpdateInfoNotifier extends StateNotifier<(String?, String?)> { state = (newVersion, newChangelog); } } - -final drawerCollapsedProvider = StateProvider((ref) => false); - -void calcDrawerSize( - WidgetRef ref, - BuildContext context, { - bool withMediaQuery = false, -}) { - bool newDrawerIsCollapsed; - if (withMediaQuery) { - newDrawerIsCollapsed = MediaQuery.of(context).size.width < 600; - } else { - final rpb = ResponsiveBreakpoints.of(context); - newDrawerIsCollapsed = rpb.smallerOrEqualTo(MOBILE); - } - - final current = ref.read(drawerCollapsedProvider); - if (newDrawerIsCollapsed != current) { - ref.read(drawerCollapsedProvider.notifier).state = newDrawerIsCollapsed; - } -} diff --git a/lib/screens/account.dart b/lib/screens/account.dart index 06a0843..b9665fc 100644 --- a/lib/screens/account.dart +++ b/lib/screens/account.dart @@ -27,16 +27,19 @@ class AccountShellScreen extends HookConsumerWidget { final isWide = isWideScreen(context); if (isWide) { - return Row( - children: [ - SizedBox(width: 360, child: AccountScreen(isAside: true)), - VerticalDivider(width: 1), - Expanded(child: AutoRouter()), - ], + return AppBackground( + isRoot: true, + child: Row( + children: [ + SizedBox(width: 360, child: AccountScreen(isAside: true)), + VerticalDivider(width: 1), + Expanded(child: AutoRouter()), + ], + ), ); } - return AutoRouter(); + return AppBackground(isRoot: true, child: AutoRouter()); } } @@ -49,7 +52,7 @@ class AccountScreen extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final isWide = isWideScreen(context); if (isWide && !isAside) { - return Container(color: Theme.of(context).scaffoldBackgroundColor); + return const EmptyPageHolder(); } final user = ref.watch(userInfoProvider); @@ -62,6 +65,7 @@ class AccountScreen extends HookConsumerWidget { } return AppScaffold( + noBackground: isWide, appBar: AppBar(title: const Text('account').tr()), body: SingleChildScrollView( child: Column( diff --git a/lib/screens/chat/chat.dart b/lib/screens/chat/chat.dart index 5fd1c71..aa44cba 100644 --- a/lib/screens/chat/chat.dart +++ b/lib/screens/chat/chat.dart @@ -85,9 +85,12 @@ class ChatRoomListTile extends HookConsumerWidget { ), Expanded( child: Text( - data.lastMessage.content ?? 'messageNone'.tr(), + (data.lastMessage.content?.isNotEmpty ?? false) + ? data.lastMessage.content! + : 'messageNone'.tr(), maxLines: 1, overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.bodySmall, ), ), Text( @@ -182,16 +185,19 @@ class ChatShellScreen extends HookConsumerWidget { final isWide = isWideScreen(context); if (isWide) { - return Row( - children: [ - Flexible(flex: 2, child: ChatListScreen(isAside: true)), - VerticalDivider(width: 1), - Flexible(flex: 4, child: AutoRouter()), - ], + return AppBackground( + isRoot: true, + child: Row( + children: [ + Flexible(flex: 2, child: ChatListScreen(isAside: true)), + VerticalDivider(width: 1), + Flexible(flex: 4, child: AutoRouter()), + ], + ), ); } - return AutoRouter(); + return AppBackground(isRoot: true, child: AutoRouter()); } } @@ -204,11 +210,22 @@ class ChatListScreen extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final isWide = isWideScreen(context); if (isWide && !isAside) { - return Container(color: Theme.of(context).scaffoldBackgroundColor); + return const EmptyPageHolder(); } final chats = ref.watch(chatroomsJoinedProvider); final chatInvites = ref.watch(chatroomInvitesProvider); + final tabController = useTabController(initialLength: 3); + final selectedTab = useState( + 0, + ); // 0 for All, 1 for Direct Messages, 2 for Group Chats + + useEffect(() { + tabController.addListener(() { + selectedTab.value = tabController.index; + }); + return null; + }, [tabController]); Future createDirectMessage() async { final result = await showModalBottomSheet( @@ -228,6 +245,14 @@ class ChatListScreen extends HookConsumerWidget { return AppScaffold( appBar: AppBar( title: Text('chat').tr(), + bottom: TabBar( + controller: tabController, + tabs: [ + Tab(text: 'chatTabAll'.tr()), + Tab(text: 'chatTabDirect'.tr()), + Tab(text: 'chatTabGroup'.tr()), + ], + ), actions: [ IconButton( icon: Badge( @@ -301,9 +326,26 @@ class ChatListScreen extends HookConsumerWidget { }), child: ListView.builder( padding: EdgeInsets.zero, - itemCount: items.length, + itemCount: + items + .where( + (item) => + selectedTab.value == 0 || + (selectedTab.value == 1 && item.type == 1) || + (selectedTab.value == 2 && item.type != 1), + ) + .length, itemBuilder: (context, index) { - final item = items[index]; + final filteredItems = + items + .where( + (item) => + selectedTab.value == 0 || + (selectedTab.value == 1 && item.type == 1) || + (selectedTab.value == 2 && item.type != 1), + ) + .toList(); + final item = filteredItems[index]; return ChatRoomListTile( room: item, isDirect: item.type == 1, diff --git a/lib/screens/chat/room.dart b/lib/screens/chat/room.dart index 91d7004..d685fef 100644 --- a/lib/screens/chat/room.dart +++ b/lib/screens/chat/room.dart @@ -25,6 +25,7 @@ import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/response.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart'; import 'package:styled_widget/styled_widget.dart'; +import 'package:super_sliver_list/super_sliver_list.dart'; import 'package:uuid/uuid.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -321,12 +322,16 @@ class ChatRoomScreen extends HookConsumerWidget { ); } + var isLoading = false; + // Add scroll listener for pagination useEffect(() { void onScroll() { if (scrollController.position.pixels >= scrollController.position.maxScrollExtent - 200) { - messagesNotifier.loadMore(); + if (isLoading) return; + isLoading = true; + messagesNotifier.loadMore().then((_) => isLoading = false); } } @@ -338,6 +343,7 @@ class ChatRoomScreen extends HookConsumerWidget { useEffect(() { void onMessage(WebSocketPacket pkt) { if (!pkt.type.startsWith('messages')) return; + if (['messages.read'].contains(pkt.type)) return; final message = SnChatMessage.fromJson(pkt.data!); if (message.chatRoomId != chatRoom.value?.id) return; switch (pkt.type) { @@ -384,19 +390,21 @@ class ChatRoomScreen extends HookConsumerWidget { void sendMessage() { if (messageController.text.trim().isNotEmpty || attachments.value.isNotEmpty) { - messagesNotifier.sendMessage( - messageController.text.trim(), - attachments.value, - editingTo: messageEditingTo.value, - forwardingTo: messageForwardingTo.value, - replyingTo: messageReplyingTo.value, - onProgress: (messageId, progress) { - attachmentProgress.value = { - ...attachmentProgress.value, - messageId: progress, - }; - }, - ); + messagesNotifier + .sendMessage( + messageController.text.trim(), + attachments.value, + editingTo: messageEditingTo.value, + forwardingTo: messageForwardingTo.value, + replyingTo: messageReplyingTo.value, + onProgress: (messageId, progress) { + attachmentProgress.value = { + ...attachmentProgress.value, + messageId: progress, + }; + }, + ) + .then((_) => sendReadReceipt()); messageController.clear(); messageEditingTo.value = null; messageReplyingTo.value = null; @@ -407,7 +415,7 @@ class ChatRoomScreen extends HookConsumerWidget { final compactHeader = isWideScreen(context); - return Scaffold( + return AppScaffold( appBar: AppBar( leading: !compactHeader ? const Center(child: PageBackButton()) : null, automaticallyImplyLeading: false, @@ -526,7 +534,7 @@ class ChatRoomScreen extends HookConsumerWidget { (messageList) => messageList.isEmpty ? Center(child: Text('No messages yet'.tr())) - : ListView.builder( + : SuperListView.builder( padding: EdgeInsets.symmetric(vertical: 16), controller: scrollController, reverse: true, // Show newest messages at the bottom @@ -539,7 +547,12 @@ class ChatRoomScreen extends HookConsumerWidget { : null; final isLastInGroup = nextMessage == null || - nextMessage.senderId != message.senderId; + nextMessage.senderId != message.senderId || + nextMessage.createdAt + .difference(message.createdAt) + .inMinutes + .abs() > + 3; return chatIdentity.when( skipError: true, diff --git a/lib/screens/notification.dart b/lib/screens/notification.dart index 88930d9..d10299b 100644 --- a/lib/screens/notification.dart +++ b/lib/screens/notification.dart @@ -8,6 +8,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:island/models/user.dart'; import 'package:island/pods/network.dart'; import 'package:island/widgets/alert.dart'; +import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/content/markdown.dart'; import 'package:relative_time/relative_time.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -85,7 +86,7 @@ class NotificationScreen extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - return Scaffold( + return AppScaffold( appBar: AppBar(title: const Text('notifications').tr()), body: PagingHelperView( provider: notificationListNotifierProvider, diff --git a/lib/screens/realm/detail.dart b/lib/screens/realm/detail.dart index 4b147f0..349a296 100644 --- a/lib/screens/realm/detail.dart +++ b/lib/screens/realm/detail.dart @@ -165,8 +165,9 @@ class _RealmActionMenu extends HookConsumerWidget { final client = ref.watch(apiClientProvider); client.delete('/realms/$realmSlug'); ref.invalidate(realmsJoinedProvider); - if (context.mounted) + if (context.mounted) { context.router.maybePop(true); + } } }); }, diff --git a/lib/screens/realm/realms.dart b/lib/screens/realm/realms.dart index a1cc4dd..2a03db2 100644 --- a/lib/screens/realm/realms.dart +++ b/lib/screens/realm/realms.dart @@ -40,6 +40,7 @@ class RealmListScreen extends HookConsumerWidget { final realmInvites = ref.watch(realmInvitesProvider); return AppScaffold( + noBackground: false, appBar: AppBar( title: const Text('realms').tr(), actions: [ diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index 6b15d4b..6b55517 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -37,6 +37,7 @@ class SettingsScreen extends HookConsumerWidget { }, []); return AppScaffold( + noBackground: false, appBar: AppBar(title: const Text('Settings')), body: SingleChildScrollView( child: Column( diff --git a/lib/widgets/app_scaffold.dart b/lib/widgets/app_scaffold.dart index d76ffae..bf21831 100644 --- a/lib/widgets/app_scaffold.dart +++ b/lib/widgets/app_scaffold.dart @@ -9,9 +9,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:island/pods/userinfo.dart'; import 'package:island/pods/websocket.dart'; import 'package:island/route.dart'; +import 'package:island/services/responsive.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:responsive_framework/responsive_framework.dart'; import 'package:styled_widget/styled_widget.dart'; class WindowScaffold extends HookConsumerWidget { @@ -109,7 +109,7 @@ class AppScaffold extends StatelessWidget { final AppBar? appBar; final DrawerCallback? onDrawerChanged; final DrawerCallback? onEndDrawerChanged; - final bool noBackground; + final bool? noBackground; const AppScaffold({ super.key, @@ -124,7 +124,7 @@ class AppScaffold extends StatelessWidget { this.endDrawer, this.onDrawerChanged, this.onEndDrawerChanged, - this.noBackground = false, + this.noBackground, }); @override @@ -132,6 +132,8 @@ class AppScaffold extends StatelessWidget { final appBarHeight = appBar?.preferredSize.height ?? 0; final safeTop = MediaQuery.of(context).padding.top; + final noBackground = this.noBackground ?? isWideScreen(context); + final content = Column( children: [ IgnorePointer( @@ -208,7 +210,7 @@ class AppBackground extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final imageFileAsync = ref.watch(backgroundImageFileProvider); - if (isRoot || ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE)) { + if (isRoot || !isWideScreen(context)) { return imageFileAsync.when( data: (file) { if (file != null) { @@ -254,6 +256,20 @@ class AppBackground extends ConsumerWidget { } } +class EmptyPageHolder extends HookConsumerWidget { + const EmptyPageHolder({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final hasBackground = + ref.watch(backgroundImageFileProvider).valueOrNull != null; + if (hasBackground) { + return const SizedBox.shrink(); + } + return Container(color: Theme.of(context).scaffoldBackgroundColor); + } +} + class _WebSocketIndicator extends HookConsumerWidget { const _WebSocketIndicator(); diff --git a/lib/widgets/chat/message_item.dart b/lib/widgets/chat/message_item.dart index f32690a..6e32352 100644 --- a/lib/widgets/chat/message_item.dart +++ b/lib/widgets/chat/message_item.dart @@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:island/database/message.dart'; import 'package:island/models/chat.dart'; import 'package:island/screens/chat/room.dart'; +import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/content/cloud_file_collection.dart'; import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/markdown.dart'; @@ -50,6 +51,9 @@ class MessageItem extends HookConsumerWidget { containerColor, ); + final hasBackground = + ref.watch(backgroundImageFileProvider).valueOrNull != null; + final remoteMessage = message.toRemoteMessage(); final sender = remoteMessage.sender; @@ -93,7 +97,10 @@ class MessageItem extends HookConsumerWidget { ); }, child: Material( - color: Theme.of(context).colorScheme.surface, + color: + hasBackground + ? Colors.transparent + : Theme.of(context).colorScheme.surface, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), child: Column( @@ -115,7 +122,21 @@ class MessageItem extends HookConsumerWidget { spacing: 2, children: [ Text( - DateFormat.Hm().format(message.createdAt.toLocal()), + DateTime.now().difference(message.createdAt).inDays > + 365 + ? DateFormat( + 'yyyy/MM/dd HH:mm', + ).format(message.createdAt.toLocal()) + : DateTime.now() + .difference(message.createdAt) + .inDays > + 0 + ? DateFormat( + 'MM/dd HH:mm', + ).format(message.createdAt.toLocal()) + : DateFormat( + 'HH:mm', + ).format(message.createdAt.toLocal()), style: TextStyle(fontSize: 10, color: textColor), ), Row( @@ -151,77 +172,96 @@ class MessageItem extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.end, children: [ Flexible( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (remoteMessage.repliedMessageId != null) - MessageQuoteWidget( - message: message, - textColor: textColor, - isReply: true, - ), - if (remoteMessage.forwardedMessageId != null) - MessageQuoteWidget( - message: message, - textColor: textColor, - isReply: false, - ), - if (remoteMessage.content?.isNotEmpty ?? false) - MarkdownTextContent( - content: remoteMessage.content!, - isSelectable: true, - linkStyle: TextStyle(color: linkColor), - textStyle: TextStyle( - color: textColor, - fontSize: 14, + child: Container( + decoration: BoxDecoration( + color: containerColor, + borderRadius: BorderRadius.circular(16), + ), + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (remoteMessage.repliedMessageId != null) + MessageQuoteWidget( + message: message, + textColor: textColor, + isReply: true, + ).padding(vertical: 4), + if (remoteMessage.forwardedMessageId != null) + MessageQuoteWidget( + message: message, + textColor: textColor, + isReply: false, + ).padding(vertical: 4), + if (remoteMessage.content?.isNotEmpty ?? false) + MarkdownTextContent( + content: remoteMessage.content!, + isSelectable: true, + linkStyle: TextStyle(color: linkColor), + textStyle: TextStyle( + color: textColor, + fontSize: 14, + ), ), - ), - if (remoteMessage.attachments.isNotEmpty) - CloudFileList( - files: remoteMessage.attachments, - maxWidth: MediaQuery.of(context).size.width * 0.8, - ).padding(top: 4), - if (progress != null && progress!.isNotEmpty) - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - spacing: 8, - children: [ - if ((remoteMessage.content?.isNotEmpty ?? false)) + if (remoteMessage.attachments.isNotEmpty) + LayoutBuilder( + builder: (context, constraints) { + return CloudFileList( + files: remoteMessage.attachments, + maxWidth: constraints.maxWidth, + ).padding(vertical: 4); + }, + ), + if (progress != null && progress!.isNotEmpty) + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + spacing: 8, + children: [ + if ((remoteMessage.content?.isNotEmpty ?? + false)) + const Gap(0), + for (var entry in progress!.entries) + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + 'fileUploadingProgress'.tr( + args: [ + (entry.key + 1).toString(), + entry.value.toStringAsFixed(1), + ], + ), + style: TextStyle( + fontSize: 12, + color: textColor.withOpacity(0.8), + ), + ), + const Gap(4), + LinearProgressIndicator( + value: entry.value / 100, + backgroundColor: + Theme.of( + context, + ).colorScheme.surfaceVariant, + valueColor: + AlwaysStoppedAnimation( + Theme.of( + context, + ).colorScheme.primary, + ), + ), + ], + ), const Gap(0), - for (var entry in progress!.entries) - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'fileUploadingProgress'.tr( - args: [ - (entry.key + 1).toString(), - entry.value.toStringAsFixed(1), - ], - ), - style: TextStyle( - fontSize: 12, - color: textColor.withOpacity(0.8), - ), - ), - const Gap(4), - LinearProgressIndicator( - value: entry.value / 100, - backgroundColor: - Theme.of( - context, - ).colorScheme.surfaceVariant, - valueColor: AlwaysStoppedAnimation( - Theme.of(context).colorScheme.primary, - ), - ), - ], - ), - const Gap(0), - ], - ), - ], - ).padding(left: 40), + ], + ), + ], + ), + ), ), _buildMessageIndicators( context, @@ -333,6 +373,7 @@ class MessageQuoteWidget extends HookConsumerWidget { children: [ if (isReply) Row( + mainAxisSize: MainAxisSize.min, spacing: 4, children: [ Icon(Symbols.reply, size: 16, color: textColor), @@ -340,9 +381,10 @@ class MessageQuoteWidget extends HookConsumerWidget { 'Replying to ${snapshot.data!.toRemoteMessage().sender.account.nick}', ).textColor(textColor).bold(), ], - ) + ).padding(right: 8) else Row( + mainAxisSize: MainAxisSize.min, spacing: 4, children: [ Icon(Symbols.forward, size: 16, color: textColor), @@ -350,7 +392,7 @@ class MessageQuoteWidget extends HookConsumerWidget { 'Forwarded from ${snapshot.data!.toRemoteMessage().sender.account.nick}', ).textColor(textColor).bold(), ], - ), + ).padding(right: 8), if (snapshot.data!.toRemoteMessage().content?.isNotEmpty ?? false) Text( diff --git a/lib/widgets/post/post_item.dart b/lib/widgets/post/post_item.dart index 08da12c..986d6dc 100644 --- a/lib/widgets/post/post_item.dart +++ b/lib/widgets/post/post_item.dart @@ -12,6 +12,7 @@ import 'package:island/pods/userinfo.dart'; import 'package:island/route.gr.dart'; import 'package:island/services/responsive.dart'; import 'package:island/widgets/alert.dart'; +import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/content/cloud_file_collection.dart'; import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/markdown.dart'; @@ -47,6 +48,9 @@ class PostItem extends HookConsumerWidget { [user], ); + final hasBackground = + ref.watch(backgroundImageFileProvider).valueOrNull != null; + return ContextMenuWidget( menuProvider: (_) { return Menu( @@ -101,7 +105,7 @@ class PostItem extends HookConsumerWidget { ); }, child: Material( - color: backgroundColor, + color: hasBackground ? Colors.transparent : backgroundColor, child: Padding( padding: renderingPadding, child: Column( diff --git a/pubspec.lock b/pubspec.lock index a46fd14..28b1be2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1477,14 +1477,6 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.0" - responsive_framework: - dependency: "direct main" - description: - name: responsive_framework - sha256: a8e1c13d4ba980c60cbf6fa1e9907cd60662bf2585184d7c96ca46c43de91552 - url: "https://pub.dev" - source: hosted - version: "1.5.1" riverpod: dependency: transitive description: @@ -1826,6 +1818,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.0-dev.6" + super_sliver_list: + dependency: "direct main" + description: + name: super_sliver_list + sha256: b1e1e64d08ce40e459b9bb5d9f8e361617c26b8c9f3bb967760b0f436b6e3f56 + url: "https://pub.dev" + source: hosted + version: "0.4.1" sync: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7fc67ff..c828152 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,7 +40,6 @@ dependencies: auto_route: ^10.0.1 styled_widget: ^0.4.1 shared_preferences: ^2.5.3 - responsive_framework: ^1.5.1 flutter_riverpod: ^2.6.1 path_provider: ^2.1.5 dio: ^5.8.0+1 @@ -100,6 +99,7 @@ dependencies: flutter_native_splash: ^2.4.6 photo_view: ^0.15.0 dismissible_page: ^1.0.2 + super_sliver_list: ^0.4.1 dev_dependencies: flutter_test: