diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 15815d13..0b0b714f 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -2383,5 +2383,6 @@ "publicSpaces": "Public spaces", "addChatOrSubSpace": "Add chat or sub space", "subspace": "Subspace", - "decline": "Decline" + "decline": "Decline", + "thisDevice": "This device:" } \ No newline at end of file diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index e73b85b8..dd8f34f1 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -216,7 +216,7 @@ class ChatController extends State { EmojiPickerType emojiPickerType = EmojiPickerType.keyboard; - void requestHistory() async { + void requestHistory([_]) async { if (!timeline!.canRequestHistory) return; Logs().v('Requesting history...'); try { @@ -269,11 +269,6 @@ class ChatController extends State { if (scrollController.position.pixels == 0 || scrollController.position.pixels == 64) { requestFuture(); - } else if (scrollController.position.pixels == - scrollController.position.maxScrollExtent || - scrollController.position.pixels + 64 == - scrollController.position.maxScrollExtent) { - requestHistory(); } } diff --git a/lib/pages/chat/chat_event_list.dart b/lib/pages/chat/chat_event_list.dart index c5fef033..51f481ae 100644 --- a/lib/pages/chat/chat_event_list.dart +++ b/lib/pages/chat/chat_event_list.dart @@ -82,11 +82,17 @@ class ChatEventList extends StatelessWidget { ); } if (controller.timeline!.canRequestHistory) { - return Center( - child: IconButton( - onPressed: controller.requestHistory, - icon: const Icon(Icons.refresh_outlined), - ), + return Builder( + builder: (context) { + WidgetsBinding.instance + .addPostFrameCallback(controller.requestHistory); + return Center( + child: IconButton( + onPressed: controller.requestHistory, + icon: const Icon(Icons.refresh_outlined), + ), + ); + }, ); } return const SizedBox.shrink(); diff --git a/lib/pages/device_settings/device_settings_view.dart b/lib/pages/device_settings/device_settings_view.dart index 4094c022..5493836f 100644 --- a/lib/pages/device_settings/device_settings_view.dart +++ b/lib/pages/device_settings/device_settings_view.dart @@ -47,7 +47,22 @@ class DevicesSettingsView extends StatelessWidget { return Column( mainAxisSize: MainAxisSize.min, children: [ - if (controller.thisDevice != null) + if (controller.thisDevice != null) ...[ + Container( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + alignment: Alignment.centerLeft, + child: Text( + L10n.of(context)!.thisDevice, + style: TextStyle( + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary, + ), + textAlign: TextAlign.left, + ), + ), UserDeviceListItem( controller.thisDevice!, rename: controller.renameDeviceAction, @@ -56,24 +71,44 @@ class DevicesSettingsView extends StatelessWidget { block: controller.blockDeviceAction, unblock: controller.unblockDeviceAction, ), - const Divider(height: 1), + const Divider( + height: 16.0, + indent: 16, + endIndent: 16, + ), + ], if (controller.notThisDevice.isNotEmpty) - ListTile( - title: Text( - controller.errorDeletingDevices ?? - L10n.of(context)!.removeAllOtherDevices, - style: const TextStyle(color: Colors.red), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + child: SizedBox( + width: double.infinity, + child: OutlinedButton.icon( + label: Text( + controller.errorDeletingDevices ?? + L10n.of(context)!.removeAllOtherDevices, + ), + style: OutlinedButton.styleFrom( + foregroundColor: + Theme.of(context).colorScheme.error, + side: BorderSide( + color: Theme.of(context).colorScheme.error, + ), + ), + icon: controller.loadingDeletingDevices + ? const CircularProgressIndicator.adaptive( + strokeWidth: 2, + ) + : const Icon(Icons.delete_outline), + onPressed: controller.loadingDeletingDevices + ? null + : () => controller.removeDevicesAction( + controller.notThisDevice, + ), + ), ), - trailing: controller.loadingDeletingDevices - ? const CircularProgressIndicator.adaptive( - strokeWidth: 2, - ) - : const Icon(Icons.delete_outline), - onTap: controller.loadingDeletingDevices - ? null - : () => controller.removeDevicesAction( - controller.notThisDevice, - ), ) else Center( @@ -82,7 +117,6 @@ class DevicesSettingsView extends StatelessWidget { child: Text(L10n.of(context)!.noOtherDevicesFound), ), ), - const Divider(height: 1), ], ); } diff --git a/lib/pages/device_settings/user_device_list_item.dart b/lib/pages/device_settings/user_device_list_item.dart index db793ac3..cf3acd6c 100644 --- a/lib/pages/device_settings/user_device_list_item.dart +++ b/lib/pages/device_settings/user_device_list_item.dart @@ -4,6 +4,7 @@ import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart'; +import 'package:fluffychat/config/app_config.dart'; import '../../utils/date_time_extension.dart'; import '../../utils/matrix_sdk_extensions/device_extension.dart'; import '../../widgets/matrix.dart'; @@ -41,104 +42,106 @@ class UserDeviceListItem extends StatelessWidget { ?.deviceKeys[userDevice.deviceId]; final isOwnDevice = userDevice.deviceId == client.deviceID; - return ListTile( - onTap: () async { - final action = await showModalActionSheet( - context: context, - title: '${userDevice.displayName} (${userDevice.deviceId})', - actions: [ - SheetAction( - key: UserDeviceListItemAction.rename, - label: L10n.of(context)!.changeDeviceName, - ), - if (!isOwnDevice && keys != null) ...{ - SheetAction( - key: UserDeviceListItemAction.verify, - label: L10n.of(context)!.verifyStart, - ), - if (!keys.blocked) + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Material( + borderRadius: BorderRadius.circular(AppConfig.borderRadius), + clipBehavior: Clip.hardEdge, + child: ListTile( + onTap: () async { + final action = await showModalActionSheet( + context: context, + title: '${userDevice.displayName} (${userDevice.deviceId})', + actions: [ SheetAction( - key: UserDeviceListItemAction.block, - label: L10n.of(context)!.blockDevice, - isDestructiveAction: true, + key: UserDeviceListItemAction.rename, + label: L10n.of(context)!.changeDeviceName, ), - if (keys.blocked) - SheetAction( - key: UserDeviceListItemAction.unblock, - label: L10n.of(context)!.unblockDevice, - isDestructiveAction: true, - ), - }, - if (!isOwnDevice) - SheetAction( - key: UserDeviceListItemAction.remove, - label: L10n.of(context)!.delete, - isDestructiveAction: true, - ), - ], - ); - if (action == null) return; - switch (action) { - case UserDeviceListItemAction.rename: - rename(userDevice); - break; - case UserDeviceListItemAction.remove: - remove(userDevice); - break; - case UserDeviceListItemAction.verify: - verify(userDevice); - break; - case UserDeviceListItemAction.block: - block(userDevice); - break; - case UserDeviceListItemAction.unblock: - unblock(userDevice); - break; - } - }, - leading: CircleAvatar( - foregroundColor: Colors.white, - backgroundColor: keys == null - ? Colors.grey[700] - : keys.blocked - ? Colors.red - : keys.verified - ? Colors.green - : Colors.orange, - child: Icon(userDevice.icon), - ), - title: Row( - children: [ - Expanded( - child: Text( - userDevice.displayname, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - if (keys != null) - Text( - keys.blocked - ? L10n.of(context)!.blocked - : keys.verified - ? L10n.of(context)!.verified - : L10n.of(context)!.unverified, - style: TextStyle( - color: keys.blocked + if (!isOwnDevice && keys != null) ...{ + SheetAction( + key: UserDeviceListItemAction.verify, + label: L10n.of(context)!.verifyStart, + ), + if (!keys.blocked) + SheetAction( + key: UserDeviceListItemAction.block, + label: L10n.of(context)!.blockDevice, + isDestructiveAction: true, + ), + if (keys.blocked) + SheetAction( + key: UserDeviceListItemAction.unblock, + label: L10n.of(context)!.unblockDevice, + isDestructiveAction: true, + ), + }, + if (!isOwnDevice) + SheetAction( + key: UserDeviceListItemAction.remove, + label: L10n.of(context)!.delete, + isDestructiveAction: true, + ), + ], + ); + if (action == null) return; + switch (action) { + case UserDeviceListItemAction.rename: + rename(userDevice); + break; + case UserDeviceListItemAction.remove: + remove(userDevice); + break; + case UserDeviceListItemAction.verify: + verify(userDevice); + break; + case UserDeviceListItemAction.block: + block(userDevice); + break; + case UserDeviceListItemAction.unblock: + unblock(userDevice); + break; + } + }, + leading: CircleAvatar( + foregroundColor: Colors.white, + backgroundColor: keys == null + ? Colors.grey[700] + : keys.blocked ? Colors.red : keys.verified ? Colors.green : Colors.orange, - ), + child: Icon(userDevice.icon), + ), + title: Text( + userDevice.displayname, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + subtitle: Text( + L10n.of(context)!.lastActiveAgo( + DateTime.fromMillisecondsSinceEpoch(userDevice.lastSeenTs ?? 0) + .localizedTimeShort(context), ), - ], - ), - subtitle: Text( - L10n.of(context)!.lastActiveAgo( - DateTime.fromMillisecondsSinceEpoch(userDevice.lastSeenTs ?? 0) - .localizedTimeShort(context), + style: const TextStyle(fontWeight: FontWeight.w300), + ), + trailing: keys == null + ? null + : Text( + keys.blocked + ? L10n.of(context)!.blocked + : keys.verified + ? L10n.of(context)!.verified + : L10n.of(context)!.unverified, + style: TextStyle( + color: keys.blocked + ? Colors.red + : keys.verified + ? Colors.green + : Colors.orange, + ), + ), ), - style: const TextStyle(fontWeight: FontWeight.w300), ), ); } diff --git a/lib/pages/settings_notifications/settings_notifications_view.dart b/lib/pages/settings_notifications/settings_notifications_view.dart index 65ddac16..64d356a8 100644 --- a/lib/pages/settings_notifications/settings_notifications_view.dart +++ b/lib/pages/settings_notifications/settings_notifications_view.dart @@ -45,26 +45,20 @@ class SettingsNotificationsView extends StatelessWidget { ), ), ), - if (!Matrix.of(context).client.allPushNotificationsMuted) ...{ - const Divider(thickness: 1), - ListTile( - title: Text( - L10n.of(context)!.pushRules, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), + for (final item in NotificationSettingsItem.items) + SwitchListTile.adaptive( + value: Matrix.of(context).client.allPushNotificationsMuted + ? false + : controller.getNotificationSetting(item) ?? true, + title: Text(item.title(context)), + onChanged: Matrix.of(context) + .client + .allPushNotificationsMuted + ? null + : (bool enabled) => + controller.setNotificationSetting(item, enabled), ), - for (final item in NotificationSettingsItem.items) - SwitchListTile.adaptive( - value: controller.getNotificationSetting(item) ?? true, - title: Text(item.title(context)), - onChanged: (bool enabled) => - controller.setNotificationSetting(item, enabled), - ), - }, - const Divider(thickness: 1), + const Divider(), ListTile( title: Text( L10n.of(context)!.devices,