diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index c1c50b3a..380db405 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -1080,5 +1080,10 @@ "deleteRecycledFiles": "Delete Recycled Files", "recycledFilesDeleted": "Recycled files deleted successfully", "failedToDeleteRecycledFiles": "Failed to delete recycled files", - "upload": "Upload" + "upload": "Upload", + "updateAvailable": "Update available", + "noChangelogProvided": "No changelog provided.", + "useSecondarySourceForDownload": "Use secondary source for download", + "installUpdate": "Install update", + "openReleasePage": "Open release page" } diff --git a/lib/screens/chat/room.dart b/lib/screens/chat/room.dart index b9efef02..2cb2127a 100644 --- a/lib/screens/chat/room.dart +++ b/lib/screens/chat/room.dart @@ -9,6 +9,7 @@ import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:island/database/message.dart"; import "package:island/models/chat.dart"; import "package:island/models/file.dart"; +import "package:island/pods/chat/chat_rooms.dart"; import "package:island/pods/chat/chat_subscribe.dart"; import "package:island/pods/config.dart"; import "package:island/pods/chat/messages_notifier.dart"; @@ -33,8 +34,6 @@ import "package:island/widgets/chat/call_button.dart"; import "package:island/widgets/chat/chat_input.dart"; import "package:island/widgets/chat/public_room_preview.dart"; -final isSyncingProvider = StateProvider.autoDispose((ref) => false); - final flashingMessagesProvider = StateProvider>((ref) => {}); class ChatRoomScreen extends HookConsumerWidget { @@ -48,6 +47,8 @@ class ChatRoomScreen extends HookConsumerWidget { final isSyncing = ref.watch(isSyncingProvider); final onlineCount = ref.watch(chatOnlineCountNotifierProvider(id)); + final hasOnlineCount = onlineCount.hasValue; + if (chatIdentity.isLoading || chatRoom.isLoading) { return AppScaffold( appBar: AppBar(leading: const PageBackButton()), @@ -231,6 +232,32 @@ class ChatRoomScreen extends HookConsumerWidget { final compactHeader = isWideScreen(context); + Widget onlineIndicator() => Row( + spacing: 8, + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + width: 8, + height: 8, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: (onlineCount as AsyncData).value > 1 ? Colors.green : null, + border: + (onlineCount as AsyncData).value <= 1 + ? Border.all(color: Colors.grey) + : null, + ), + ), + Text( + '${(onlineCount as AsyncData).value} online', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Theme.of(context).appBarTheme.foregroundColor!, + ), + ), + ], + ); + Widget comfortHeaderWidget(SnChatRoom? room) => Column( spacing: 4, mainAxisAlignment: MainAxisAlignment.center, @@ -264,16 +291,18 @@ class ChatRoomScreen extends HookConsumerWidget { ? room.members!.map((e) => e.account.nick).join(', ') : room.name!, ).fontSize(15), + if (hasOnlineCount) onlineIndicator(), ], ); Widget compactHeaderWidget(SnChatRoom? room) => Row( spacing: 8, crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox( - height: 26, - width: 26, + height: 28, + width: 28, child: (room!.type == 1 && room.picture?.id == null) ? SplitAvatarWidget( @@ -299,6 +328,8 @@ class ChatRoomScreen extends HookConsumerWidget { ? room.members!.map((e) => e.account.nick).join(', ') : room.name!, ).fontSize(19), + if (hasOnlineCount) + onlineIndicator().padding(left: 6), ], ); @@ -488,7 +519,7 @@ class ChatRoomScreen extends HookConsumerWidget { appBar: AppBar( leading: !compactHeader ? const Center(child: PageBackButton()) : null, automaticallyImplyLeading: false, - toolbarHeight: compactHeader ? null : 64, + toolbarHeight: compactHeader ? null : 80, title: chatRoom.when( data: (room) => @@ -556,33 +587,6 @@ class ChatRoomScreen extends HookConsumerWidget { ), const Gap(8), ], - bottom: () { - final hasProgress = isSyncing; - final hasOnlineCount = onlineCount.hasValue; - if (!hasProgress && !hasOnlineCount) return null; - return PreferredSize( - preferredSize: Size.fromHeight( - (hasProgress ? 2 : 0) + (hasOnlineCount ? 24 : 0), - ), - child: Column( - children: [ - if (hasProgress) - const LinearProgressIndicator( - borderRadius: BorderRadius.zero, - ), - if (hasOnlineCount) - Container( - height: 24, - alignment: Alignment.center, - child: Text( - '${(onlineCount as AsyncData).value} online', - style: Theme.of(context).textTheme.bodySmall, - ), - ), - ], - ), - ); - }(), ), body: Stack( children: [ @@ -678,12 +682,14 @@ class ChatRoomScreen extends HookConsumerWidget { ), if (isSyncing) Positioned( - top: 16, + top: 8, right: 16, child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor.withOpacity(0.8), + color: Theme.of( + context, + ).scaffoldBackgroundColor.withOpacity(0.8), borderRadius: BorderRadius.circular(8), ), child: Row( @@ -695,7 +701,10 @@ class ChatRoomScreen extends HookConsumerWidget { child: CircularProgressIndicator(strokeWidth: 2), ), const SizedBox(width: 8), - Text('Syncing...', style: Theme.of(context).textTheme.bodySmall), + Text( + 'Syncing...', + style: Theme.of(context).textTheme.bodySmall, + ), ], ), ), diff --git a/lib/services/update_service.dart b/lib/services/update_service.dart index 45725caa..d2055ec4 100644 --- a/lib/services/update_service.dart +++ b/lib/services/update_service.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:archive/archive.dart'; import 'package:dio/dio.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_app_update/azhon_app_update.dart'; @@ -596,7 +597,7 @@ class _UpdateSheetState extends State<_UpdateSheet> { Widget build(BuildContext context) { final theme = Theme.of(context); return SheetScaffold( - titleText: 'Update available', + titleText: 'updateAvailable'.tr(), child: Padding( padding: EdgeInsets.only( bottom: 16 + MediaQuery.of(context).padding.bottom, @@ -624,14 +625,14 @@ class _UpdateSheetState extends State<_UpdateSheet> { child: MarkdownTextContent( content: widget.release.body.isEmpty - ? 'No changelog provided.' + ? 'noChangelogProvided'.tr() : widget.release.body, ), ), ), if (!kIsWeb && Platform.isAndroid) SwitchListTile( - title: const Text('Use secondary source for download'), + title: Text('useSecondarySourceForDownload'.tr()), value: _useProxy, onChanged: (value) { setState(() { @@ -654,7 +655,7 @@ class _UpdateSheetState extends State<_UpdateSheet> { _installUpdate(widget.androidUpdateUrl!); }, icon: const Icon(Symbols.update), - label: const Text('Install update'), + label: Text('installUpdate'.tr()), ), ), if (!kIsWeb && @@ -673,14 +674,14 @@ class _UpdateSheetState extends State<_UpdateSheet> { ); }, icon: const Icon(Symbols.update), - label: const Text('Install update'), + label: Text('installUpdate'.tr()), ), ), Expanded( child: FilledButton.icon( onPressed: widget.onOpen, icon: const Icon(Icons.open_in_new), - label: const Text('Open release page'), + label: Text('openReleasePage'.tr()), ), ), ],