design: New three column layout for wide screens
This commit is contained in:
parent
5e3c62110b
commit
d9c5cbea26
7 changed files with 287 additions and 251 deletions
|
|
@ -1577,6 +1577,7 @@
|
||||||
"username": {}
|
"username": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"directChat": "Direct chat",
|
||||||
"redactedByBecause": "Redacted by {username} because: \"{reason}\"",
|
"redactedByBecause": "Redacted by {username} because: \"{reason}\"",
|
||||||
"@redactedByBecause": {
|
"@redactedByBecause": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,11 @@ import 'package:scroll_to_index/scroll_to_index.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/config/app_config.dart';
|
import 'package:fluffychat/config/app_config.dart';
|
||||||
|
import 'package:fluffychat/config/themes.dart';
|
||||||
import 'package:fluffychat/pages/chat/chat_view.dart';
|
import 'package:fluffychat/pages/chat/chat_view.dart';
|
||||||
import 'package:fluffychat/pages/chat/event_info_dialog.dart';
|
import 'package:fluffychat/pages/chat/event_info_dialog.dart';
|
||||||
import 'package:fluffychat/pages/chat/recording_dialog.dart';
|
import 'package:fluffychat/pages/chat/recording_dialog.dart';
|
||||||
|
import 'package:fluffychat/pages/chat_details/chat_details.dart';
|
||||||
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
|
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
|
||||||
import 'package:fluffychat/utils/error_reporter.dart';
|
import 'package:fluffychat/utils/error_reporter.dart';
|
||||||
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
|
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
|
||||||
|
|
@ -61,10 +63,31 @@ class ChatPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return ChatPageWithRoom(
|
|
||||||
key: Key('chat_page_$roomId'),
|
return Row(
|
||||||
sideView: sideView,
|
children: [
|
||||||
room: room,
|
Expanded(
|
||||||
|
child: ChatPageWithRoom(
|
||||||
|
key: Key('chat_page_$roomId'),
|
||||||
|
sideView: sideView,
|
||||||
|
room: room,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (FluffyThemes.isThreeColumnMode(context))
|
||||||
|
Container(
|
||||||
|
width: FluffyThemes.columnWidth,
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
left: BorderSide(
|
||||||
|
width: 1,
|
||||||
|
color: Theme.of(context).dividerColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: ChatDetails(roomId: roomId),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/pages/chat/chat.dart';
|
import 'package:fluffychat/pages/chat/chat.dart';
|
||||||
import 'package:fluffychat/pages/user_bottom_sheet/user_bottom_sheet.dart';
|
|
||||||
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
|
|
||||||
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
|
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
|
||||||
import 'package:fluffychat/widgets/avatar.dart';
|
import 'package:fluffychat/widgets/avatar.dart';
|
||||||
|
|
||||||
|
|
@ -19,25 +17,13 @@ class ChatAppBarTitle extends StatelessWidget {
|
||||||
if (controller.selectedEvents.isNotEmpty) {
|
if (controller.selectedEvents.isNotEmpty) {
|
||||||
return Text(controller.selectedEvents.length.toString());
|
return Text(controller.selectedEvents.length.toString());
|
||||||
}
|
}
|
||||||
final directChatMatrixID = room.directChatMatrixID;
|
|
||||||
return InkWell(
|
return InkWell(
|
||||||
hoverColor: Colors.transparent,
|
hoverColor: Colors.transparent,
|
||||||
splashColor: Colors.transparent,
|
splashColor: Colors.transparent,
|
||||||
highlightColor: Colors.transparent,
|
highlightColor: Colors.transparent,
|
||||||
onTap: directChatMatrixID != null
|
onTap: controller.isArchived
|
||||||
? () => showAdaptiveBottomSheet(
|
? null
|
||||||
context: context,
|
: () => context.go(['', 'rooms', room.id, 'details'].join('/')),
|
||||||
builder: (c) => UserBottomSheet(
|
|
||||||
user: room
|
|
||||||
.unsafeGetUserFromMemoryOrFallback(directChatMatrixID),
|
|
||||||
outerContext: context,
|
|
||||||
onMention: () => controller.sendController.text +=
|
|
||||||
'${room.unsafeGetUserFromMemoryOrFallback(directChatMatrixID).mention} ',
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: controller.isArchived
|
|
||||||
? null
|
|
||||||
: () => context.go(['', 'rooms', room.id, 'details'].join('/')),
|
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Hero(
|
Hero(
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ class ChatView extends StatelessWidget {
|
||||||
tooltip: L10n.of(context)!.placeCall,
|
tooltip: L10n.of(context)!.placeCall,
|
||||||
),
|
),
|
||||||
EncryptionButton(controller.room),
|
EncryptionButton(controller.room),
|
||||||
ChatSettingsPopupMenu(controller.room, !controller.room.isDirectChat),
|
ChatSettingsPopupMenu(controller.room, true),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -318,9 +318,9 @@ class ChatDetailsController extends State<ChatDetails> {
|
||||||
if ((room.states['im.ponies.room_emotes'] ?? <String, Event>{})
|
if ((room.states['im.ponies.room_emotes'] ?? <String, Event>{})
|
||||||
.keys
|
.keys
|
||||||
.any((String s) => s.isNotEmpty)) {
|
.any((String s) => s.isNotEmpty)) {
|
||||||
context.go('/rooms/${room.id}/details/multiple_emotes');
|
context.push('/rooms/${room.id}/details/multiple_emotes');
|
||||||
} else {
|
} else {
|
||||||
context.go('/rooms/${room.id}/details/emotes');
|
context.push('/rooms/${room.id}/details/emotes');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ class ChatDetailsView extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final isEmbedded = GoRouterState.of(context).fullPath == '/rooms/:roomid';
|
||||||
|
|
||||||
return StreamBuilder(
|
return StreamBuilder(
|
||||||
stream: room.onUpdate.stream,
|
stream: room.onUpdate.stream,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
|
|
@ -49,24 +51,27 @@ class ChatDetailsView extends StatelessWidget {
|
||||||
MatrixLocals(L10n.of(context)!),
|
MatrixLocals(L10n.of(context)!),
|
||||||
);
|
);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: isEmbedded
|
||||||
leading: const Center(child: BackButton()),
|
? null
|
||||||
elevation: Theme.of(context).appBarTheme.elevation,
|
: AppBar(
|
||||||
actions: <Widget>[
|
leading: const Center(child: BackButton()),
|
||||||
if (room.canonicalAlias.isNotEmpty)
|
elevation: Theme.of(context).appBarTheme.elevation,
|
||||||
IconButton(
|
actions: <Widget>[
|
||||||
tooltip: L10n.of(context)!.share,
|
if (room.canonicalAlias.isNotEmpty)
|
||||||
icon: Icon(Icons.adaptive.share_outlined),
|
IconButton(
|
||||||
onPressed: () => FluffyShare.share(
|
tooltip: L10n.of(context)!.share,
|
||||||
AppConfig.inviteLinkPrefix + room.canonicalAlias,
|
icon: Icon(Icons.adaptive.share_outlined),
|
||||||
context,
|
onPressed: () => FluffyShare.share(
|
||||||
),
|
AppConfig.inviteLinkPrefix + room.canonicalAlias,
|
||||||
|
context,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ChatSettingsPopupMenu(room, false)
|
||||||
|
],
|
||||||
|
title: Text(L10n.of(context)!.chatDetails),
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).appBarTheme.backgroundColor,
|
||||||
),
|
),
|
||||||
ChatSettingsPopupMenu(room, false)
|
|
||||||
],
|
|
||||||
title: Text(L10n.of(context)!.chatDetails),
|
|
||||||
backgroundColor: Theme.of(context).appBarTheme.backgroundColor,
|
|
||||||
),
|
|
||||||
body: MaxWidthBody(
|
body: MaxWidthBody(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
|
@ -99,7 +104,9 @@ class ChatDetailsView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Hero(
|
child: Hero(
|
||||||
tag: 'content_banner',
|
tag: isEmbedded
|
||||||
|
? 'embedded_content_banner'
|
||||||
|
: 'content_banner',
|
||||||
child: Avatar(
|
child: Avatar(
|
||||||
mxContent: room.avatar,
|
mxContent: room.avatar,
|
||||||
name: displayname,
|
name: displayname,
|
||||||
|
|
@ -108,9 +115,10 @@ class ChatDetailsView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (room.canChangeStateEvent(
|
if (!room.isDirectChat &&
|
||||||
EventTypes.RoomAvatar,
|
room.canChangeStateEvent(
|
||||||
))
|
EventTypes.RoomAvatar,
|
||||||
|
))
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
|
|
@ -131,21 +139,25 @@ class ChatDetailsView extends StatelessWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed: () => room.canChangeStateEvent(
|
onPressed: () => room.isDirectChat
|
||||||
EventTypes.RoomName,
|
? null
|
||||||
)
|
: room.canChangeStateEvent(
|
||||||
? controller.setDisplaynameAction()
|
EventTypes.RoomName,
|
||||||
: FluffyShare.share(
|
)
|
||||||
displayname,
|
? controller.setDisplaynameAction()
|
||||||
context,
|
: FluffyShare.share(
|
||||||
copyOnly: true,
|
displayname,
|
||||||
),
|
context,
|
||||||
|
copyOnly: true,
|
||||||
|
),
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
room.canChangeStateEvent(
|
room.isDirectChat
|
||||||
EventTypes.RoomName,
|
? Icons.chat_bubble_outline
|
||||||
)
|
: room.canChangeStateEvent(
|
||||||
? Icons.edit_outlined
|
EventTypes.RoomName,
|
||||||
: Icons.copy_outlined,
|
)
|
||||||
|
? Icons.edit_outlined
|
||||||
|
: Icons.copy_outlined,
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
|
|
@ -154,16 +166,20 @@ class ChatDetailsView extends StatelessWidget {
|
||||||
.onBackground,
|
.onBackground,
|
||||||
),
|
),
|
||||||
label: Text(
|
label: Text(
|
||||||
displayname,
|
room.isDirectChat
|
||||||
|
? L10n.of(context)!.directChat
|
||||||
|
: displayname,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
// style: const TextStyle(fontSize: 18),
|
// style: const TextStyle(fontSize: 18),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed: () => context.go(
|
onPressed: () => room.isDirectChat
|
||||||
'/rooms/${controller.roomId}/details/members',
|
? null
|
||||||
),
|
: context.push(
|
||||||
|
'/rooms/${controller.roomId}/details/members',
|
||||||
|
),
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.group_outlined,
|
Icons.group_outlined,
|
||||||
size: 14,
|
size: 14,
|
||||||
|
|
@ -272,44 +288,46 @@ class ChatDetailsView extends StatelessWidget {
|
||||||
onTap: controller.goToEmoteSettings,
|
onTap: controller.goToEmoteSettings,
|
||||||
trailing: const Icon(Icons.chevron_right_outlined),
|
trailing: const Icon(Icons.chevron_right_outlined),
|
||||||
),
|
),
|
||||||
ListTile(
|
if (!room.isDirectChat)
|
||||||
leading: CircleAvatar(
|
ListTile(
|
||||||
backgroundColor:
|
leading: CircleAvatar(
|
||||||
Theme.of(context).scaffoldBackgroundColor,
|
backgroundColor:
|
||||||
foregroundColor: iconColor,
|
Theme.of(context).scaffoldBackgroundColor,
|
||||||
child: const Icon(Icons.shield_outlined),
|
foregroundColor: iconColor,
|
||||||
|
child: const Icon(Icons.shield_outlined),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
L10n.of(context)!.whoIsAllowedToJoinThisGroup,
|
||||||
|
),
|
||||||
|
trailing: const Icon(Icons.chevron_right_outlined),
|
||||||
|
subtitle: Text(
|
||||||
|
room.joinRules?.getLocalizedString(
|
||||||
|
MatrixLocals(L10n.of(context)!),
|
||||||
|
) ??
|
||||||
|
L10n.of(context)!.none,
|
||||||
|
),
|
||||||
|
onTap: controller.setJoinRules,
|
||||||
),
|
),
|
||||||
title: Text(
|
if (!room.isDirectChat)
|
||||||
L10n.of(context)!.whoIsAllowedToJoinThisGroup,
|
ListTile(
|
||||||
|
leading: CircleAvatar(
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).scaffoldBackgroundColor,
|
||||||
|
foregroundColor: iconColor,
|
||||||
|
child: const Icon(Icons.visibility_outlined),
|
||||||
|
),
|
||||||
|
trailing: const Icon(Icons.chevron_right_outlined),
|
||||||
|
title: Text(
|
||||||
|
L10n.of(context)!.visibilityOfTheChatHistory,
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
room.historyVisibility?.getLocalizedString(
|
||||||
|
MatrixLocals(L10n.of(context)!),
|
||||||
|
) ??
|
||||||
|
L10n.of(context)!.none,
|
||||||
|
),
|
||||||
|
onTap: controller.setHistoryVisibility,
|
||||||
),
|
),
|
||||||
trailing: const Icon(Icons.chevron_right_outlined),
|
|
||||||
subtitle: Text(
|
|
||||||
room.joinRules?.getLocalizedString(
|
|
||||||
MatrixLocals(L10n.of(context)!),
|
|
||||||
) ??
|
|
||||||
L10n.of(context)!.none,
|
|
||||||
),
|
|
||||||
onTap: controller.setJoinRules,
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
leading: CircleAvatar(
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).scaffoldBackgroundColor,
|
|
||||||
foregroundColor: iconColor,
|
|
||||||
child: const Icon(Icons.visibility_outlined),
|
|
||||||
),
|
|
||||||
trailing: const Icon(Icons.chevron_right_outlined),
|
|
||||||
title: Text(
|
|
||||||
L10n.of(context)!.visibilityOfTheChatHistory,
|
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
room.historyVisibility?.getLocalizedString(
|
|
||||||
MatrixLocals(L10n.of(context)!),
|
|
||||||
) ??
|
|
||||||
L10n.of(context)!.none,
|
|
||||||
),
|
|
||||||
onTap: controller.setHistoryVisibility,
|
|
||||||
),
|
|
||||||
if (room.joinRules == JoinRules.public)
|
if (room.joinRules == JoinRules.public)
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: CircleAvatar(
|
leading: CircleAvatar(
|
||||||
|
|
@ -331,23 +349,24 @@ class ChatDetailsView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
onTap: controller.setGuestAccess,
|
onTap: controller.setGuestAccess,
|
||||||
),
|
),
|
||||||
ListTile(
|
if (!room.isDirectChat)
|
||||||
title: Text(L10n.of(context)!.editChatPermissions),
|
ListTile(
|
||||||
subtitle: Text(
|
title: Text(L10n.of(context)!.editChatPermissions),
|
||||||
L10n.of(context)!.whoCanPerformWhichAction,
|
subtitle: Text(
|
||||||
),
|
L10n.of(context)!.whoCanPerformWhichAction,
|
||||||
leading: CircleAvatar(
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).scaffoldBackgroundColor,
|
|
||||||
foregroundColor: iconColor,
|
|
||||||
child: const Icon(
|
|
||||||
Icons.edit_attributes_outlined,
|
|
||||||
),
|
),
|
||||||
|
leading: CircleAvatar(
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).scaffoldBackgroundColor,
|
||||||
|
foregroundColor: iconColor,
|
||||||
|
child: const Icon(
|
||||||
|
Icons.edit_attributes_outlined,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
trailing: const Icon(Icons.chevron_right_outlined),
|
||||||
|
onTap: () => context
|
||||||
|
.push('/rooms/${room.id}/details/permissions'),
|
||||||
),
|
),
|
||||||
trailing: const Icon(Icons.chevron_right_outlined),
|
|
||||||
onTap: () => context
|
|
||||||
.go('/rooms/${room.id}/details/permissions'),
|
|
||||||
),
|
|
||||||
Divider(
|
Divider(
|
||||||
height: 1,
|
height: 1,
|
||||||
color: Theme.of(context).dividerColor,
|
color: Theme.of(context).dividerColor,
|
||||||
|
|
@ -363,7 +382,7 @@ class ChatDetailsView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (room.canInvite)
|
if (!room.isDirectChat && room.canInvite)
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(L10n.of(context)!.inviteContact),
|
title: Text(L10n.of(context)!.inviteContact),
|
||||||
leading: CircleAvatar(
|
leading: CircleAvatar(
|
||||||
|
|
@ -393,7 +412,7 @@ class ChatDetailsView extends StatelessWidget {
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () => context.go(
|
onTap: () => context.push(
|
||||||
'/rooms/${controller.roomId!}/details/members',
|
'/rooms/${controller.roomId!}/details/members',
|
||||||
),
|
),
|
||||||
trailing: const Icon(Icons.chevron_right_outlined),
|
trailing: const Icon(Icons.chevron_right_outlined),
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import 'package:url_launcher/url_launcher_string.dart';
|
||||||
import 'package:fluffychat/config/app_config.dart';
|
import 'package:fluffychat/config/app_config.dart';
|
||||||
import 'package:fluffychat/pages/chat_encryption_settings/chat_encryption_settings.dart';
|
import 'package:fluffychat/pages/chat_encryption_settings/chat_encryption_settings.dart';
|
||||||
import 'package:fluffychat/utils/beautify_string_extension.dart';
|
import 'package:fluffychat/utils/beautify_string_extension.dart';
|
||||||
|
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
|
||||||
|
|
||||||
class ChatEncryptionSettingsView extends StatelessWidget {
|
class ChatEncryptionSettingsView extends StatelessWidget {
|
||||||
final ChatEncryptionSettingsController controller;
|
final ChatEncryptionSettingsController controller;
|
||||||
|
|
@ -38,159 +39,165 @@ class ChatEncryptionSettingsView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: MaxWidthBody(
|
||||||
children: [
|
child: Column(
|
||||||
SwitchListTile(
|
mainAxisSize: MainAxisSize.min,
|
||||||
secondary: CircleAvatar(
|
children: [
|
||||||
foregroundColor:
|
SwitchListTile(
|
||||||
Theme.of(context).colorScheme.onPrimaryContainer,
|
secondary: CircleAvatar(
|
||||||
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
|
foregroundColor:
|
||||||
child: const Icon(Icons.lock_outlined),
|
Theme.of(context).colorScheme.onPrimaryContainer,
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).colorScheme.primaryContainer,
|
||||||
|
child: const Icon(Icons.lock_outlined),
|
||||||
|
),
|
||||||
|
title: Text(L10n.of(context)!.encryptThisChat),
|
||||||
|
value: room.encrypted,
|
||||||
|
onChanged: controller.enableEncryption,
|
||||||
),
|
),
|
||||||
title: Text(L10n.of(context)!.encryptThisChat),
|
Icon(
|
||||||
value: room.encrypted,
|
CupertinoIcons.lock_shield,
|
||||||
onChanged: controller.enableEncryption,
|
size: 128,
|
||||||
),
|
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||||
Icon(
|
),
|
||||||
CupertinoIcons.lock_shield,
|
const Divider(),
|
||||||
size: 128,
|
if (room.isDirectChat)
|
||||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
Padding(
|
||||||
),
|
padding: const EdgeInsets.all(16.0),
|
||||||
const Divider(),
|
child: SizedBox(
|
||||||
if (room.isDirectChat)
|
width: double.infinity,
|
||||||
Padding(
|
child: ElevatedButton.icon(
|
||||||
padding: const EdgeInsets.all(16.0),
|
onPressed: controller.startVerification,
|
||||||
child: SizedBox(
|
icon: const Icon(Icons.verified_outlined),
|
||||||
width: double.infinity,
|
label: Text(L10n.of(context)!.verifyStart),
|
||||||
child: ElevatedButton.icon(
|
),
|
||||||
onPressed: controller.startVerification,
|
|
||||||
icon: const Icon(Icons.verified_outlined),
|
|
||||||
label: Text(L10n.of(context)!.verifyStart),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
if (room.encrypted) ...[
|
||||||
if (room.encrypted) ...[
|
const SizedBox(height: 16),
|
||||||
const SizedBox(height: 16),
|
ListTile(
|
||||||
ListTile(
|
title: Text(
|
||||||
title: Text(
|
L10n.of(context)!.deviceKeys,
|
||||||
L10n.of(context)!.deviceKeys,
|
style: const TextStyle(
|
||||||
style: const TextStyle(
|
fontWeight: FontWeight.bold,
|
||||||
fontWeight: FontWeight.bold,
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
StreamBuilder(
|
||||||
StreamBuilder(
|
stream: room.onUpdate.stream,
|
||||||
stream: room.onUpdate.stream,
|
builder: (context, snapshot) =>
|
||||||
builder: (context, snapshot) => FutureBuilder<List<DeviceKeys>>(
|
FutureBuilder<List<DeviceKeys>>(
|
||||||
future: room.getUserDeviceKeys(),
|
future: room.getUserDeviceKeys(),
|
||||||
builder: (BuildContext context, snapshot) {
|
builder: (BuildContext context, snapshot) {
|
||||||
if (snapshot.hasError) {
|
if (snapshot.hasError) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'${L10n.of(context)!.oopsSomethingWentWrong}: ${snapshot.error}',
|
'${L10n.of(context)!.oopsSomethingWentWrong}: ${snapshot.error}',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!snapshot.hasData) {
|
if (!snapshot.hasData) {
|
||||||
return const Center(
|
return const Center(
|
||||||
child: CircularProgressIndicator.adaptive(
|
child: CircularProgressIndicator.adaptive(
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final deviceKeys = snapshot.data!;
|
final deviceKeys = snapshot.data!;
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemCount: deviceKeys.length,
|
itemCount: deviceKeys.length,
|
||||||
itemBuilder: (BuildContext context, int i) =>
|
itemBuilder: (BuildContext context, int i) =>
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
value: !deviceKeys[i].blocked,
|
value: !deviceKeys[i].blocked,
|
||||||
activeColor: deviceKeys[i].verified
|
activeColor: deviceKeys[i].verified
|
||||||
? Colors.green
|
? Colors.green
|
||||||
: Colors.orange,
|
: Colors.orange,
|
||||||
onChanged: (_) =>
|
onChanged: (_) =>
|
||||||
controller.toggleDeviceKey(deviceKeys[i]),
|
controller.toggleDeviceKey(deviceKeys[i]),
|
||||||
title: Row(
|
title: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
deviceKeys[i].verified
|
deviceKeys[i].verified
|
||||||
? Icons.verified_outlined
|
? Icons.verified_outlined
|
||||||
: deviceKeys[i].blocked
|
: deviceKeys[i].blocked
|
||||||
? Icons.block_outlined
|
? Icons.block_outlined
|
||||||
: Icons.info_outlined,
|
: Icons.info_outlined,
|
||||||
color: deviceKeys[i].verified
|
color: deviceKeys[i].verified
|
||||||
? Colors.green
|
? Colors.green
|
||||||
: deviceKeys[i].blocked
|
: deviceKeys[i].blocked
|
||||||
? Colors.red
|
? Colors.red
|
||||||
: Colors.orange,
|
: Colors.orange,
|
||||||
size: 20,
|
size: 20,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
deviceKeys[i].deviceId ??
|
deviceKeys[i].deviceId ??
|
||||||
L10n.of(context)!.unknownDevice,
|
L10n.of(context)!.unknownDevice,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Flexible(
|
Flexible(
|
||||||
fit: FlexFit.loose,
|
fit: FlexFit.loose,
|
||||||
child: Material(
|
child: Material(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
AppConfig.borderRadius,
|
AppConfig.borderRadius,
|
||||||
),
|
),
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
color:
|
|
||||||
Theme.of(context).colorScheme.primary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.primaryContainer,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(4.0),
|
|
||||||
child: Text(
|
|
||||||
deviceKeys[i].userId,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: TextStyle(
|
|
||||||
color:
|
color:
|
||||||
Theme.of(context).colorScheme.primary,
|
Theme.of(context).colorScheme.primary,
|
||||||
fontSize: 12,
|
),
|
||||||
fontStyle: FontStyle.italic,
|
),
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primaryContainer,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
child: Text(
|
||||||
|
deviceKeys[i].userId,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primary,
|
||||||
|
fontSize: 12,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
deviceKeys[i].ed25519Key?.beautified ??
|
||||||
|
L10n.of(context)!.unknownEncryptionAlgorithm,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'RobotoMono',
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
deviceKeys[i].ed25519Key?.beautified ??
|
|
||||||
L10n.of(context)!.unknownEncryptionAlgorithm,
|
|
||||||
style: TextStyle(
|
|
||||||
fontFamily: 'RobotoMono',
|
|
||||||
color: Theme.of(context).colorScheme.secondary,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
},
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
),
|
] else
|
||||||
] else
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.all(16.0),
|
||||||
padding: const EdgeInsets.all(16.0),
|
child: Center(
|
||||||
child: Center(
|
child: Text(
|
||||||
child: Text(
|
L10n.of(context)!.encryptionNotEnabled,
|
||||||
L10n.of(context)!.encryptionNotEnabled,
|
style: const TextStyle(
|
||||||
style: const TextStyle(
|
fontStyle: FontStyle.italic,
|
||||||
fontStyle: FontStyle.italic,
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue