refactor: Added and applied require_trailing_commas linter rule
This commit is contained in:
parent
adb3f766e5
commit
ec7acc5385
112 changed files with 3466 additions and 2855 deletions
|
|
@ -164,19 +164,21 @@ class ChatListController extends State<ChatList>
|
|||
|
||||
void setServer() async {
|
||||
final newServer = await showTextInputDialog(
|
||||
useRootNavigator: false,
|
||||
title: L10n.of(context)!.changeTheHomeserver,
|
||||
context: context,
|
||||
okLabel: L10n.of(context)!.ok,
|
||||
cancelLabel: L10n.of(context)!.cancel,
|
||||
textFields: [
|
||||
DialogTextField(
|
||||
prefixText: 'https://',
|
||||
hintText: Matrix.of(context).client.homeserver?.host,
|
||||
initialText: searchServer,
|
||||
keyboardType: TextInputType.url,
|
||||
autocorrect: false)
|
||||
]);
|
||||
useRootNavigator: false,
|
||||
title: L10n.of(context)!.changeTheHomeserver,
|
||||
context: context,
|
||||
okLabel: L10n.of(context)!.ok,
|
||||
cancelLabel: L10n.of(context)!.cancel,
|
||||
textFields: [
|
||||
DialogTextField(
|
||||
prefixText: 'https://',
|
||||
hintText: Matrix.of(context).client.homeserver?.host,
|
||||
initialText: searchServer,
|
||||
keyboardType: TextInputType.url,
|
||||
autocorrect: false,
|
||||
)
|
||||
],
|
||||
);
|
||||
if (newServer == null) return;
|
||||
Store().setItem(_serverStoreNamespace, newServer.single);
|
||||
setState(() {
|
||||
|
|
@ -382,9 +384,11 @@ class ChatListController extends State<ChatList>
|
|||
}
|
||||
|
||||
void toggleSelection(String roomId) {
|
||||
setState(() => selectedRoomIds.contains(roomId)
|
||||
? selectedRoomIds.remove(roomId)
|
||||
: selectedRoomIds.add(roomId));
|
||||
setState(
|
||||
() => selectedRoomIds.contains(roomId)
|
||||
? selectedRoomIds.remove(roomId)
|
||||
: selectedRoomIds.add(roomId),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> toggleUnread() async {
|
||||
|
|
@ -456,16 +460,17 @@ class ChatListController extends State<ChatList>
|
|||
|
||||
void setStatus() async {
|
||||
final input = await showTextInputDialog(
|
||||
useRootNavigator: false,
|
||||
context: context,
|
||||
title: L10n.of(context)!.setStatus,
|
||||
okLabel: L10n.of(context)!.ok,
|
||||
cancelLabel: L10n.of(context)!.cancel,
|
||||
textFields: [
|
||||
DialogTextField(
|
||||
hintText: L10n.of(context)!.statusExampleMessage,
|
||||
),
|
||||
]);
|
||||
useRootNavigator: false,
|
||||
context: context,
|
||||
title: L10n.of(context)!.setStatus,
|
||||
okLabel: L10n.of(context)!.ok,
|
||||
cancelLabel: L10n.of(context)!.cancel,
|
||||
textFields: [
|
||||
DialogTextField(
|
||||
hintText: L10n.of(context)!.statusExampleMessage,
|
||||
),
|
||||
],
|
||||
);
|
||||
if (input == null) return;
|
||||
await showFutureLoadingDialog(
|
||||
context: context,
|
||||
|
|
@ -491,22 +496,23 @@ class ChatListController extends State<ChatList>
|
|||
|
||||
Future<void> addToSpace() async {
|
||||
final selectedSpace = await showConfirmationDialog<String>(
|
||||
context: context,
|
||||
title: L10n.of(context)!.addToSpace,
|
||||
message: L10n.of(context)!.addToSpaceDescription,
|
||||
fullyCapitalizedForMaterial: false,
|
||||
actions: Matrix.of(context)
|
||||
.client
|
||||
.rooms
|
||||
.where((r) => r.isSpace)
|
||||
.map(
|
||||
(space) => AlertDialogAction(
|
||||
key: space.id,
|
||||
label: space
|
||||
.getLocalizedDisplayname(MatrixLocals(L10n.of(context)!)),
|
||||
),
|
||||
)
|
||||
.toList());
|
||||
context: context,
|
||||
title: L10n.of(context)!.addToSpace,
|
||||
message: L10n.of(context)!.addToSpaceDescription,
|
||||
fullyCapitalizedForMaterial: false,
|
||||
actions: Matrix.of(context)
|
||||
.client
|
||||
.rooms
|
||||
.where((r) => r.isSpace)
|
||||
.map(
|
||||
(space) => AlertDialogAction(
|
||||
key: space.id,
|
||||
label: space
|
||||
.getLocalizedDisplayname(MatrixLocals(L10n.of(context)!)),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
if (selectedSpace == null) return;
|
||||
final result = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
|
|
@ -532,14 +538,19 @@ class ChatListController extends State<ChatList>
|
|||
}
|
||||
|
||||
bool get anySelectedRoomNotMarkedUnread => selectedRoomIds.any(
|
||||
(roomId) => !Matrix.of(context).client.getRoomById(roomId)!.markedUnread);
|
||||
(roomId) =>
|
||||
!Matrix.of(context).client.getRoomById(roomId)!.markedUnread,
|
||||
);
|
||||
|
||||
bool get anySelectedRoomNotFavorite => selectedRoomIds.any(
|
||||
(roomId) => !Matrix.of(context).client.getRoomById(roomId)!.isFavourite);
|
||||
(roomId) => !Matrix.of(context).client.getRoomById(roomId)!.isFavourite,
|
||||
);
|
||||
|
||||
bool get anySelectedRoomNotMuted => selectedRoomIds.any((roomId) =>
|
||||
Matrix.of(context).client.getRoomById(roomId)!.pushRuleState ==
|
||||
PushRuleState.notify);
|
||||
bool get anySelectedRoomNotMuted => selectedRoomIds.any(
|
||||
(roomId) =>
|
||||
Matrix.of(context).client.getRoomById(roomId)!.pushRuleState ==
|
||||
PushRuleState.notify,
|
||||
);
|
||||
|
||||
bool waitForFirstSync = false;
|
||||
|
||||
|
|
@ -624,9 +635,10 @@ class ChatListController extends State<ChatList>
|
|||
switch (action) {
|
||||
case EditBundleAction.addToBundle:
|
||||
final bundle = await showTextInputDialog(
|
||||
context: context,
|
||||
title: l10n.bundleName,
|
||||
textFields: [DialogTextField(hintText: l10n.bundleName)]);
|
||||
context: context,
|
||||
title: l10n.bundleName,
|
||||
textFields: [DialogTextField(hintText: l10n.bundleName)],
|
||||
);
|
||||
if (bundle == null || bundle.isEmpty || bundle.single.isEmpty) return;
|
||||
await showFutureLoadingDialog(
|
||||
context: context,
|
||||
|
|
|
|||
|
|
@ -46,247 +46,248 @@ class ChatListViewBody extends StatelessWidget {
|
|||
);
|
||||
},
|
||||
child: StreamBuilder(
|
||||
key: ValueKey(client.userID.toString() +
|
||||
key: ValueKey(
|
||||
client.userID.toString() +
|
||||
controller.activeFilter.toString() +
|
||||
controller.activeSpaceId.toString()),
|
||||
stream: client.onSync.stream
|
||||
.where((s) => s.hasRoomUpdate)
|
||||
.rateLimit(const Duration(seconds: 1)),
|
||||
builder: (context, _) {
|
||||
if (controller.activeFilter == ActiveFilter.spaces &&
|
||||
!controller.isSearchMode) {
|
||||
return SpaceView(
|
||||
controller,
|
||||
scrollController: controller.scrollController,
|
||||
key: Key(controller.activeSpaceId ?? 'Spaces'),
|
||||
);
|
||||
}
|
||||
if (controller.waitForFirstSync && client.prevBatch != null) {
|
||||
final rooms = controller.filteredRooms;
|
||||
final displayStoriesHeader = {
|
||||
ActiveFilter.allChats,
|
||||
ActiveFilter.messages,
|
||||
}.contains(controller.activeFilter) &&
|
||||
client.storiesRooms.isNotEmpty;
|
||||
return ListView.builder(
|
||||
controller: controller.scrollController,
|
||||
// add +1 space below in order to properly scroll below the spaces bar
|
||||
itemCount: rooms.length + 1,
|
||||
itemBuilder: (BuildContext context, int i) {
|
||||
if (i == 0) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (controller.isSearchMode) ...[
|
||||
SearchTitle(
|
||||
title: L10n.of(context)!.publicRooms,
|
||||
icon: const Icon(Icons.explore_outlined),
|
||||
),
|
||||
AnimatedContainer(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: const BoxDecoration(),
|
||||
height: roomSearchResult == null ||
|
||||
roomSearchResult.chunk.isEmpty
|
||||
? 0
|
||||
: 106,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
child: roomSearchResult == null
|
||||
? null
|
||||
: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: roomSearchResult.chunk.length,
|
||||
itemBuilder: (context, i) => _SearchItem(
|
||||
title: roomSearchResult.chunk[i].name ??
|
||||
roomSearchResult.chunk[i]
|
||||
.canonicalAlias?.localpart ??
|
||||
L10n.of(context)!.group,
|
||||
avatar:
|
||||
roomSearchResult.chunk[i].avatarUrl,
|
||||
onPressed: () => showAdaptiveBottomSheet(
|
||||
context: context,
|
||||
builder: (c) => PublicRoomBottomSheet(
|
||||
roomAlias: roomSearchResult
|
||||
.chunk[i].canonicalAlias ??
|
||||
roomSearchResult.chunk[i].roomId,
|
||||
outerContext: context,
|
||||
chunk: roomSearchResult.chunk[i],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SearchTitle(
|
||||
title: L10n.of(context)!.users,
|
||||
icon: const Icon(Icons.group_outlined),
|
||||
),
|
||||
AnimatedContainer(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: const BoxDecoration(),
|
||||
height: userSearchResult == null ||
|
||||
userSearchResult.results.isEmpty
|
||||
? 0
|
||||
: 106,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
child: userSearchResult == null
|
||||
? null
|
||||
: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: userSearchResult.results.length,
|
||||
itemBuilder: (context, i) => _SearchItem(
|
||||
title: userSearchResult
|
||||
.results[i].displayName ??
|
||||
userSearchResult
|
||||
.results[i].userId.localpart ??
|
||||
L10n.of(context)!.unknownDevice,
|
||||
avatar:
|
||||
userSearchResult.results[i].avatarUrl,
|
||||
onPressed: () => showAdaptiveBottomSheet(
|
||||
context: context,
|
||||
builder: (c) => ProfileBottomSheet(
|
||||
userId: userSearchResult
|
||||
.results[i].userId,
|
||||
outerContext: context,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SearchTitle(
|
||||
title: L10n.of(context)!.stories,
|
||||
icon: const Icon(Icons.camera_alt_outlined),
|
||||
),
|
||||
],
|
||||
if (displayStoriesHeader)
|
||||
StoriesHeader(
|
||||
key: const Key('stories_header'),
|
||||
filter: controller.searchController.text,
|
||||
),
|
||||
const ConnectionStatusHeader(),
|
||||
controller.activeSpaceId.toString(),
|
||||
),
|
||||
stream: client.onSync.stream
|
||||
.where((s) => s.hasRoomUpdate)
|
||||
.rateLimit(const Duration(seconds: 1)),
|
||||
builder: (context, _) {
|
||||
if (controller.activeFilter == ActiveFilter.spaces &&
|
||||
!controller.isSearchMode) {
|
||||
return SpaceView(
|
||||
controller,
|
||||
scrollController: controller.scrollController,
|
||||
key: Key(controller.activeSpaceId ?? 'Spaces'),
|
||||
);
|
||||
}
|
||||
if (controller.waitForFirstSync && client.prevBatch != null) {
|
||||
final rooms = controller.filteredRooms;
|
||||
final displayStoriesHeader = {
|
||||
ActiveFilter.allChats,
|
||||
ActiveFilter.messages,
|
||||
}.contains(controller.activeFilter) &&
|
||||
client.storiesRooms.isNotEmpty;
|
||||
return ListView.builder(
|
||||
controller: controller.scrollController,
|
||||
// add +1 space below in order to properly scroll below the spaces bar
|
||||
itemCount: rooms.length + 1,
|
||||
itemBuilder: (BuildContext context, int i) {
|
||||
if (i == 0) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (controller.isSearchMode) ...[
|
||||
SearchTitle(
|
||||
title: L10n.of(context)!.publicRooms,
|
||||
icon: const Icon(Icons.explore_outlined),
|
||||
),
|
||||
AnimatedContainer(
|
||||
height: controller.isTorBrowser ? 64 : 0,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: const BoxDecoration(),
|
||||
child: Material(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: ListTile(
|
||||
leading: const Icon(Icons.vpn_key),
|
||||
title: Text(L10n.of(context)!.dehydrateTor),
|
||||
subtitle:
|
||||
Text(L10n.of(context)!.dehydrateTorLong),
|
||||
trailing:
|
||||
const Icon(Icons.chevron_right_outlined),
|
||||
onTap: controller.dehydrate,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (controller.isSearchMode)
|
||||
SearchTitle(
|
||||
title: L10n.of(context)!.chats,
|
||||
icon: const Icon(Icons.chat_outlined),
|
||||
),
|
||||
if (rooms.isEmpty && !controller.isSearchMode)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(32.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/start_chat.png',
|
||||
height: 256,
|
||||
height: roomSearchResult == null ||
|
||||
roomSearchResult.chunk.isEmpty
|
||||
? 0
|
||||
: 106,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
child: roomSearchResult == null
|
||||
? null
|
||||
: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: roomSearchResult.chunk.length,
|
||||
itemBuilder: (context, i) => _SearchItem(
|
||||
title: roomSearchResult.chunk[i].name ??
|
||||
roomSearchResult.chunk[i].canonicalAlias
|
||||
?.localpart ??
|
||||
L10n.of(context)!.group,
|
||||
avatar: roomSearchResult.chunk[i].avatarUrl,
|
||||
onPressed: () => showAdaptiveBottomSheet(
|
||||
context: context,
|
||||
builder: (c) => PublicRoomBottomSheet(
|
||||
roomAlias: roomSearchResult
|
||||
.chunk[i].canonicalAlias ??
|
||||
roomSearchResult.chunk[i].roomId,
|
||||
outerContext: context,
|
||||
chunk: roomSearchResult.chunk[i],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SearchTitle(
|
||||
title: L10n.of(context)!.users,
|
||||
icon: const Icon(Icons.group_outlined),
|
||||
),
|
||||
AnimatedContainer(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: const BoxDecoration(),
|
||||
height: userSearchResult == null ||
|
||||
userSearchResult.results.isEmpty
|
||||
? 0
|
||||
: 106,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
child: userSearchResult == null
|
||||
? null
|
||||
: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: userSearchResult.results.length,
|
||||
itemBuilder: (context, i) => _SearchItem(
|
||||
title: userSearchResult
|
||||
.results[i].displayName ??
|
||||
userSearchResult
|
||||
.results[i].userId.localpart ??
|
||||
L10n.of(context)!.unknownDevice,
|
||||
avatar:
|
||||
userSearchResult.results[i].avatarUrl,
|
||||
onPressed: () => showAdaptiveBottomSheet(
|
||||
context: context,
|
||||
builder: (c) => ProfileBottomSheet(
|
||||
userId:
|
||||
userSearchResult.results[i].userId,
|
||||
outerContext: context,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SearchTitle(
|
||||
title: L10n.of(context)!.stories,
|
||||
icon: const Icon(Icons.camera_alt_outlined),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
i--;
|
||||
if (!rooms[i]
|
||||
.getLocalizedDisplayname(MatrixLocals(L10n.of(context)!))
|
||||
.toLowerCase()
|
||||
.contains(
|
||||
controller.searchController.text.toLowerCase())) {
|
||||
return Container();
|
||||
}
|
||||
return ChatListItem(
|
||||
rooms[i],
|
||||
key: Key('chat_list_item_${rooms[i].id}'),
|
||||
selected: controller.selectedRoomIds.contains(rooms[i].id),
|
||||
onTap: controller.selectMode == SelectMode.select
|
||||
? () => controller.toggleSelection(rooms[i].id)
|
||||
: null,
|
||||
onLongPress: () => controller.toggleSelection(rooms[i].id),
|
||||
activeChat: controller.activeChat == rooms[i].id,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
const dummyChatCount = 5;
|
||||
final titleColor =
|
||||
Theme.of(context).textTheme.bodyLarge!.color!.withAlpha(100);
|
||||
final subtitleColor =
|
||||
Theme.of(context).textTheme.bodyLarge!.color!.withAlpha(50);
|
||||
return ListView.builder(
|
||||
key: const Key('dummychats'),
|
||||
itemCount: dummyChatCount,
|
||||
itemBuilder: (context, i) => Opacity(
|
||||
opacity: (dummyChatCount - i) / dummyChatCount,
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: titleColor,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 1,
|
||||
color: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
),
|
||||
),
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 14,
|
||||
decoration: BoxDecoration(
|
||||
color: titleColor,
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
if (displayStoriesHeader)
|
||||
StoriesHeader(
|
||||
key: const Key('stories_header'),
|
||||
filter: controller.searchController.text,
|
||||
),
|
||||
const ConnectionStatusHeader(),
|
||||
AnimatedContainer(
|
||||
height: controller.isTorBrowser ? 64 : 0,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: const BoxDecoration(),
|
||||
child: Material(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: ListTile(
|
||||
leading: const Icon(Icons.vpn_key),
|
||||
title: Text(L10n.of(context)!.dehydrateTor),
|
||||
subtitle: Text(L10n.of(context)!.dehydrateTorLong),
|
||||
trailing: const Icon(Icons.chevron_right_outlined),
|
||||
onTap: controller.dehydrate,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 36),
|
||||
Container(
|
||||
height: 14,
|
||||
width: 14,
|
||||
decoration: BoxDecoration(
|
||||
color: subtitleColor,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
if (controller.isSearchMode)
|
||||
SearchTitle(
|
||||
title: L10n.of(context)!.chats,
|
||||
icon: const Icon(Icons.chat_outlined),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Container(
|
||||
height: 14,
|
||||
width: 14,
|
||||
decoration: BoxDecoration(
|
||||
color: subtitleColor,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
if (rooms.isEmpty && !controller.isSearchMode)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(32.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/start_chat.png',
|
||||
height: 256,
|
||||
),
|
||||
const Divider(height: 1),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: subtitleColor,
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
),
|
||||
height: 12,
|
||||
margin: const EdgeInsets.only(right: 22),
|
||||
);
|
||||
}
|
||||
i--;
|
||||
if (!rooms[i]
|
||||
.getLocalizedDisplayname(MatrixLocals(L10n.of(context)!))
|
||||
.toLowerCase()
|
||||
.contains(
|
||||
controller.searchController.text.toLowerCase(),
|
||||
)) {
|
||||
return Container();
|
||||
}
|
||||
return ChatListItem(
|
||||
rooms[i],
|
||||
key: Key('chat_list_item_${rooms[i].id}'),
|
||||
selected: controller.selectedRoomIds.contains(rooms[i].id),
|
||||
onTap: controller.selectMode == SelectMode.select
|
||||
? () => controller.toggleSelection(rooms[i].id)
|
||||
: null,
|
||||
onLongPress: () => controller.toggleSelection(rooms[i].id),
|
||||
activeChat: controller.activeChat == rooms[i].id,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
const dummyChatCount = 5;
|
||||
final titleColor =
|
||||
Theme.of(context).textTheme.bodyLarge!.color!.withAlpha(100);
|
||||
final subtitleColor =
|
||||
Theme.of(context).textTheme.bodyLarge!.color!.withAlpha(50);
|
||||
return ListView.builder(
|
||||
key: const Key('dummychats'),
|
||||
itemCount: dummyChatCount,
|
||||
itemBuilder: (context, i) => Opacity(
|
||||
opacity: (dummyChatCount - i) / dummyChatCount,
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: titleColor,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 1,
|
||||
color: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
),
|
||||
),
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 14,
|
||||
decoration: BoxDecoration(
|
||||
color: titleColor,
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 36),
|
||||
Container(
|
||||
height: 14,
|
||||
width: 14,
|
||||
decoration: BoxDecoration(
|
||||
color: subtitleColor,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Container(
|
||||
height: 14,
|
||||
width: 14,
|
||||
decoration: BoxDecoration(
|
||||
color: subtitleColor,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: subtitleColor,
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
),
|
||||
height: 12,
|
||||
margin: const EdgeInsets.only(right: 22),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,22 +120,28 @@ class ChatListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||
),
|
||||
IconButton(
|
||||
tooltip: L10n.of(context)!.toggleUnread,
|
||||
icon: Icon(controller.anySelectedRoomNotMarkedUnread
|
||||
? Icons.mark_chat_read_outlined
|
||||
: Icons.mark_chat_unread_outlined),
|
||||
icon: Icon(
|
||||
controller.anySelectedRoomNotMarkedUnread
|
||||
? Icons.mark_chat_read_outlined
|
||||
: Icons.mark_chat_unread_outlined,
|
||||
),
|
||||
onPressed: controller.toggleUnread,
|
||||
),
|
||||
IconButton(
|
||||
tooltip: L10n.of(context)!.toggleFavorite,
|
||||
icon: Icon(controller.anySelectedRoomNotFavorite
|
||||
? Icons.push_pin_outlined
|
||||
: Icons.push_pin),
|
||||
icon: Icon(
|
||||
controller.anySelectedRoomNotFavorite
|
||||
? Icons.push_pin_outlined
|
||||
: Icons.push_pin,
|
||||
),
|
||||
onPressed: controller.toggleFavouriteRoom,
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(controller.anySelectedRoomNotMuted
|
||||
? Icons.notifications_off_outlined
|
||||
: Icons.notifications_outlined),
|
||||
icon: Icon(
|
||||
controller.anySelectedRoomNotMuted
|
||||
? Icons.notifications_off_outlined
|
||||
: Icons.notifications_outlined,
|
||||
),
|
||||
tooltip: L10n.of(context)!.toggleMuted,
|
||||
onPressed: controller.toggleMuted,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -38,15 +38,16 @@ class ChatListItem extends StatelessWidget {
|
|||
if (activeChat) return;
|
||||
if (room.membership == Membership.invite) {
|
||||
final joinResult = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () async {
|
||||
final waitForRoom = room.client.waitForRoomInSync(
|
||||
room.id,
|
||||
join: true,
|
||||
);
|
||||
await room.join();
|
||||
await waitForRoom;
|
||||
});
|
||||
context: context,
|
||||
future: () async {
|
||||
final waitForRoom = room.client.waitForRoomInSync(
|
||||
room.id,
|
||||
join: true,
|
||||
);
|
||||
await room.join();
|
||||
await waitForRoom;
|
||||
},
|
||||
);
|
||||
if (joinResult.error != null) return;
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +108,9 @@ class ChatListItem extends StatelessWidget {
|
|||
);
|
||||
if (confirmed == OkCancelResult.cancel) return;
|
||||
await showFutureLoadingDialog(
|
||||
context: context, future: () => room.leave());
|
||||
context: context,
|
||||
future: () => room.leave(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -183,7 +186,8 @@ class ChatListItem extends StatelessWidget {
|
|||
if (room.isFavourite)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
right: room.notificationCount > 0 ? 4.0 : 0.0),
|
||||
right: room.notificationCount > 0 ? 4.0 : 0.0,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.push_pin,
|
||||
size: 16,
|
||||
|
|
@ -282,7 +286,8 @@ class ChatListItem extends StatelessWidget {
|
|||
: null,
|
||||
),
|
||||
);
|
||||
}),
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
AnimatedContainer(
|
||||
|
|
|
|||
|
|
@ -109,56 +109,60 @@ class ChatListView extends StatelessWidget {
|
|||
children: [
|
||||
if (FluffyThemes.isColumnMode(context) &&
|
||||
FluffyThemes.getDisplayNavigationRail(context)) ...[
|
||||
Builder(builder: (context) {
|
||||
final allSpaces = client.rooms.where((room) => room.isSpace);
|
||||
final rootSpaces = allSpaces
|
||||
.where(
|
||||
(space) => !allSpaces.any(
|
||||
(parentSpace) => parentSpace.spaceChildren
|
||||
.any((child) => child.roomId == space.id),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
final destinations = getNavigationDestinations(context);
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final allSpaces =
|
||||
client.rooms.where((room) => room.isSpace);
|
||||
final rootSpaces = allSpaces
|
||||
.where(
|
||||
(space) => !allSpaces.any(
|
||||
(parentSpace) => parentSpace.spaceChildren
|
||||
.any((child) => child.roomId == space.id),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
final destinations = getNavigationDestinations(context);
|
||||
|
||||
return SizedBox(
|
||||
width: 64,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.vertical,
|
||||
itemCount: rootSpaces.length + destinations.length,
|
||||
itemBuilder: (context, i) {
|
||||
if (i < destinations.length) {
|
||||
return SizedBox(
|
||||
width: 64,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.vertical,
|
||||
itemCount: rootSpaces.length + destinations.length,
|
||||
itemBuilder: (context, i) {
|
||||
if (i < destinations.length) {
|
||||
return NaviRailItem(
|
||||
isSelected: i == controller.selectedIndex,
|
||||
onTap: () => controller.onDestinationSelected(i),
|
||||
icon: destinations[i].icon,
|
||||
selectedIcon: destinations[i].selectedIcon,
|
||||
toolTip: destinations[i].label,
|
||||
);
|
||||
}
|
||||
i -= destinations.length;
|
||||
final isSelected =
|
||||
controller.activeFilter == ActiveFilter.spaces &&
|
||||
rootSpaces[i].id == controller.activeSpaceId;
|
||||
return NaviRailItem(
|
||||
isSelected: i == controller.selectedIndex,
|
||||
onTap: () => controller.onDestinationSelected(i),
|
||||
icon: destinations[i].icon,
|
||||
selectedIcon: destinations[i].selectedIcon,
|
||||
toolTip: destinations[i].label,
|
||||
);
|
||||
}
|
||||
i -= destinations.length;
|
||||
final isSelected =
|
||||
controller.activeFilter == ActiveFilter.spaces &&
|
||||
rootSpaces[i].id == controller.activeSpaceId;
|
||||
return NaviRailItem(
|
||||
toolTip: rootSpaces[i].getLocalizedDisplayname(
|
||||
MatrixLocals(L10n.of(context)!)),
|
||||
isSelected: isSelected,
|
||||
onTap: () =>
|
||||
controller.setActiveSpace(rootSpaces[i].id),
|
||||
icon: Avatar(
|
||||
mxContent: rootSpaces[i].avatar,
|
||||
name: rootSpaces[i].getLocalizedDisplayname(
|
||||
toolTip: rootSpaces[i].getLocalizedDisplayname(
|
||||
MatrixLocals(L10n.of(context)!),
|
||||
),
|
||||
size: 32,
|
||||
fontSize: 12,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
isSelected: isSelected,
|
||||
onTap: () =>
|
||||
controller.setActiveSpace(rootSpaces[i].id),
|
||||
icon: Avatar(
|
||||
mxContent: rootSpaces[i].avatar,
|
||||
name: rootSpaces[i].getLocalizedDisplayname(
|
||||
MatrixLocals(L10n.of(context)!),
|
||||
),
|
||||
size: 32,
|
||||
fontSize: 12,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Container(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1,
|
||||
|
|
|
|||
|
|
@ -20,11 +20,13 @@ class ClientChooserButton extends StatelessWidget {
|
|||
List<PopupMenuEntry<Object>> _bundleMenuItems(BuildContext context) {
|
||||
final matrix = Matrix.of(context);
|
||||
final bundles = matrix.accountBundles.keys.toList()
|
||||
..sort((a, b) => a!.isValidMatrixId == b!.isValidMatrixId
|
||||
? 0
|
||||
: a.isValidMatrixId && !b.isValidMatrixId
|
||||
? -1
|
||||
: 1);
|
||||
..sort(
|
||||
(a, b) => a!.isValidMatrixId == b!.isValidMatrixId
|
||||
? 0
|
||||
: a.isValidMatrixId && !b.isValidMatrixId
|
||||
? -1
|
||||
: 1,
|
||||
);
|
||||
return <PopupMenuEntry<Object>>[
|
||||
PopupMenuItem(
|
||||
value: SettingsAction.newStory,
|
||||
|
|
@ -142,7 +144,9 @@ class ClientChooserButton extends StatelessWidget {
|
|||
IconButton(
|
||||
icon: const Icon(Icons.edit_outlined),
|
||||
onPressed: () => controller.editBundlesForAccount(
|
||||
client.userID, bundle),
|
||||
client.userID,
|
||||
bundle,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -270,9 +274,12 @@ class ClientChooserButton extends StatelessWidget {
|
|||
break;
|
||||
case SettingsAction.invite:
|
||||
FluffyShare.share(
|
||||
L10n.of(context)!.inviteText(Matrix.of(context).client.userID!,
|
||||
'https://matrix.to/#/${Matrix.of(context).client.userID}?client=im.fluffychat'),
|
||||
context);
|
||||
L10n.of(context)!.inviteText(
|
||||
Matrix.of(context).client.userID!,
|
||||
'https://matrix.to/#/${Matrix.of(context).client.userID}?client=im.fluffychat',
|
||||
),
|
||||
context,
|
||||
);
|
||||
break;
|
||||
case SettingsAction.settings:
|
||||
VRouter.of(context).to('/settings');
|
||||
|
|
@ -290,11 +297,13 @@ class ClientChooserButton extends StatelessWidget {
|
|||
BuildContext context,
|
||||
) {
|
||||
final bundles = matrix.accountBundles.keys.toList()
|
||||
..sort((a, b) => a!.isValidMatrixId == b!.isValidMatrixId
|
||||
? 0
|
||||
: a.isValidMatrixId && !b.isValidMatrixId
|
||||
? -1
|
||||
: 1);
|
||||
..sort(
|
||||
(a, b) => a!.isValidMatrixId == b!.isValidMatrixId
|
||||
? 0
|
||||
: a.isValidMatrixId && !b.isValidMatrixId
|
||||
? -1
|
||||
: 1,
|
||||
);
|
||||
// beginning from end if negative
|
||||
if (index < 0) {
|
||||
int clientCount = 0;
|
||||
|
|
@ -320,11 +329,13 @@ class ClientChooserButton extends StatelessWidget {
|
|||
int index = 0;
|
||||
|
||||
final bundles = matrix.accountBundles.keys.toList()
|
||||
..sort((a, b) => a!.isValidMatrixId == b!.isValidMatrixId
|
||||
? 0
|
||||
: a.isValidMatrixId && !b.isValidMatrixId
|
||||
? -1
|
||||
: 1);
|
||||
..sort(
|
||||
(a, b) => a!.isValidMatrixId == b!.isValidMatrixId
|
||||
? 0
|
||||
: a.isValidMatrixId && !b.isValidMatrixId
|
||||
? -1
|
||||
: 1,
|
||||
);
|
||||
for (final bundleName in bundles) {
|
||||
final bundle = matrix.accountBundles[bundleName];
|
||||
if (bundle == null) return null;
|
||||
|
|
|
|||
|
|
@ -48,17 +48,18 @@ class NaviRailItem extends StatelessWidget {
|
|||
onPressed: onTap,
|
||||
tooltip: toolTip,
|
||||
icon: Material(
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
color: isSelected
|
||||
? Theme.of(context).colorScheme.primaryContainer
|
||||
: Theme.of(context).colorScheme.background,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: isSelected ? selectedIcon ?? icon : icon,
|
||||
)),
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
color: isSelected
|
||||
? Theme.of(context).colorScheme.primaryContainer
|
||||
: Theme.of(context).colorScheme.background,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: isSelected ? selectedIcon ?? icon : icon,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -45,13 +45,15 @@ class SearchTitle extends StatelessWidget {
|
|||
children: [
|
||||
icon,
|
||||
const SizedBox(width: 16),
|
||||
Text(title,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
)),
|
||||
Text(
|
||||
title,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
if (trailing != null)
|
||||
Expanded(
|
||||
child: Align(
|
||||
|
|
|
|||
|
|
@ -53,11 +53,14 @@ class _SpaceViewState extends State<SpaceView> {
|
|||
final result = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () async {
|
||||
await client.joinRoom(spaceChild.roomId,
|
||||
serverName: space?.spaceChildren
|
||||
.firstWhereOrNull(
|
||||
(child) => child.roomId == spaceChild.roomId)
|
||||
?.via);
|
||||
await client.joinRoom(
|
||||
spaceChild.roomId,
|
||||
serverName: space?.spaceChildren
|
||||
.firstWhereOrNull(
|
||||
(child) => child.roomId == spaceChild.roomId,
|
||||
)
|
||||
?.via,
|
||||
);
|
||||
if (client.getRoomById(spaceChild.roomId) == null) {
|
||||
// Wait for room actually appears in sync
|
||||
await client.waitForRoomInSync(spaceChild.roomId, join: true);
|
||||
|
|
@ -78,8 +81,10 @@ class _SpaceViewState extends State<SpaceView> {
|
|||
VRouter.of(context).toSegments(['rooms', spaceChild.roomId]);
|
||||
}
|
||||
|
||||
void _onSpaceChildContextMenu(
|
||||
[SpaceRoomsChunk? spaceChild, Room? room]) async {
|
||||
void _onSpaceChildContextMenu([
|
||||
SpaceRoomsChunk? spaceChild,
|
||||
Room? room,
|
||||
]) async {
|
||||
final client = Matrix.of(context).client;
|
||||
final activeSpaceId = widget.controller.activeSpaceId;
|
||||
final activeSpace =
|
||||
|
|
@ -169,8 +174,10 @@ class _SpaceViewState extends State<SpaceView> {
|
|||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
subtitle: Text(L10n.of(context)!
|
||||
.numChats(rootSpace.spaceChildren.length.toString())),
|
||||
subtitle: Text(
|
||||
L10n.of(context)!
|
||||
.numChats(rootSpace.spaceChildren.length.toString()),
|
||||
),
|
||||
onTap: () => widget.controller.setActiveSpace(rootSpace.id),
|
||||
onLongPress: () => _onSpaceChildContextMenu(null, rootSpace),
|
||||
trailing: const Icon(Icons.chevron_right_outlined),
|
||||
|
|
@ -180,166 +187,166 @@ class _SpaceViewState extends State<SpaceView> {
|
|||
);
|
||||
}
|
||||
return FutureBuilder<GetSpaceHierarchyResponse>(
|
||||
future: getFuture(activeSpaceId),
|
||||
builder: (context, snapshot) {
|
||||
final response = snapshot.data;
|
||||
final error = snapshot.error;
|
||||
if (error != null) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(error.toLocalizedString(context)),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: _refresh,
|
||||
icon: const Icon(Icons.refresh_outlined),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
if (response == null) {
|
||||
return const Center(child: CircularProgressIndicator.adaptive());
|
||||
}
|
||||
final parentSpace = allSpaces.firstWhereOrNull((space) => space
|
||||
.spaceChildren
|
||||
.any((child) => child.roomId == activeSpaceId));
|
||||
final spaceChildren = response.rooms;
|
||||
final canLoadMore = response.nextBatch != null;
|
||||
return VWidgetGuard(
|
||||
onSystemPop: (redirector) async {
|
||||
if (parentSpace != null) {
|
||||
widget.controller.setActiveSpace(parentSpace.id);
|
||||
redirector.stopRedirection();
|
||||
return;
|
||||
future: getFuture(activeSpaceId),
|
||||
builder: (context, snapshot) {
|
||||
final response = snapshot.data;
|
||||
final error = snapshot.error;
|
||||
if (error != null) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(error.toLocalizedString(context)),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: _refresh,
|
||||
icon: const Icon(Icons.refresh_outlined),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
if (response == null) {
|
||||
return const Center(child: CircularProgressIndicator.adaptive());
|
||||
}
|
||||
final parentSpace = allSpaces.firstWhereOrNull(
|
||||
(space) =>
|
||||
space.spaceChildren.any((child) => child.roomId == activeSpaceId),
|
||||
);
|
||||
final spaceChildren = response.rooms;
|
||||
final canLoadMore = response.nextBatch != null;
|
||||
return VWidgetGuard(
|
||||
onSystemPop: (redirector) async {
|
||||
if (parentSpace != null) {
|
||||
widget.controller.setActiveSpace(parentSpace.id);
|
||||
redirector.stopRedirection();
|
||||
return;
|
||||
}
|
||||
},
|
||||
child: ListView.builder(
|
||||
itemCount: spaceChildren.length + 1 + (canLoadMore ? 1 : 0),
|
||||
controller: widget.scrollController,
|
||||
itemBuilder: (context, i) {
|
||||
if (i == 0) {
|
||||
return ListTile(
|
||||
leading: BackButton(
|
||||
onPressed: () =>
|
||||
widget.controller.setActiveSpace(parentSpace?.id),
|
||||
),
|
||||
title: Text(
|
||||
parentSpace == null
|
||||
? L10n.of(context)!.allSpaces
|
||||
: parentSpace.getLocalizedDisplayname(
|
||||
MatrixLocals(L10n.of(context)!),
|
||||
),
|
||||
),
|
||||
trailing: IconButton(
|
||||
icon: snapshot.connectionState != ConnectionState.done
|
||||
? const CircularProgressIndicator.adaptive()
|
||||
: const Icon(Icons.refresh_outlined),
|
||||
onPressed: snapshot.connectionState != ConnectionState.done
|
||||
? null
|
||||
: _refresh,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: ListView.builder(
|
||||
itemCount: spaceChildren.length + 1 + (canLoadMore ? 1 : 0),
|
||||
controller: widget.scrollController,
|
||||
itemBuilder: (context, i) {
|
||||
if (i == 0) {
|
||||
return ListTile(
|
||||
leading: BackButton(
|
||||
onPressed: () =>
|
||||
widget.controller.setActiveSpace(parentSpace?.id),
|
||||
),
|
||||
title: Text(parentSpace == null
|
||||
? L10n.of(context)!.allSpaces
|
||||
: parentSpace.getLocalizedDisplayname(
|
||||
MatrixLocals(L10n.of(context)!),
|
||||
)),
|
||||
trailing: IconButton(
|
||||
icon: snapshot.connectionState != ConnectionState.done
|
||||
? const CircularProgressIndicator.adaptive()
|
||||
: const Icon(Icons.refresh_outlined),
|
||||
onPressed:
|
||||
snapshot.connectionState != ConnectionState.done
|
||||
? null
|
||||
: _refresh,
|
||||
),
|
||||
);
|
||||
}
|
||||
i--;
|
||||
if (canLoadMore && i == spaceChildren.length) {
|
||||
return ListTile(
|
||||
title: Text(L10n.of(context)!.loadMore),
|
||||
trailing: const Icon(Icons.chevron_right_outlined),
|
||||
onTap: () {
|
||||
prevBatch = response.nextBatch;
|
||||
_refresh();
|
||||
},
|
||||
);
|
||||
}
|
||||
final spaceChild = spaceChildren[i];
|
||||
final room = client.getRoomById(spaceChild.roomId);
|
||||
if (room != null && !room.isSpace) {
|
||||
return ChatListItem(
|
||||
room,
|
||||
onLongPress: () =>
|
||||
_onSpaceChildContextMenu(spaceChild, room),
|
||||
activeChat: widget.controller.activeChat == room.id,
|
||||
);
|
||||
}
|
||||
final isSpace = spaceChild.roomType == 'm.space';
|
||||
final topic = spaceChild.topic?.isEmpty ?? true
|
||||
? null
|
||||
: spaceChild.topic;
|
||||
if (spaceChild.roomId == activeSpaceId) {
|
||||
return SearchTitle(
|
||||
title: spaceChild.name ??
|
||||
spaceChild.canonicalAlias ??
|
||||
'Space',
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Avatar(
|
||||
size: 24,
|
||||
mxContent: spaceChild.avatarUrl,
|
||||
name: spaceChild.name,
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondaryContainer
|
||||
.withAlpha(128),
|
||||
trailing: const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Icon(Icons.edit_outlined),
|
||||
),
|
||||
onTap: () => _onJoinSpaceChild(spaceChild),
|
||||
);
|
||||
}
|
||||
return ListTile(
|
||||
leading: Avatar(
|
||||
i--;
|
||||
if (canLoadMore && i == spaceChildren.length) {
|
||||
return ListTile(
|
||||
title: Text(L10n.of(context)!.loadMore),
|
||||
trailing: const Icon(Icons.chevron_right_outlined),
|
||||
onTap: () {
|
||||
prevBatch = response.nextBatch;
|
||||
_refresh();
|
||||
},
|
||||
);
|
||||
}
|
||||
final spaceChild = spaceChildren[i];
|
||||
final room = client.getRoomById(spaceChild.roomId);
|
||||
if (room != null && !room.isSpace) {
|
||||
return ChatListItem(
|
||||
room,
|
||||
onLongPress: () => _onSpaceChildContextMenu(spaceChild, room),
|
||||
activeChat: widget.controller.activeChat == room.id,
|
||||
);
|
||||
}
|
||||
final isSpace = spaceChild.roomType == 'm.space';
|
||||
final topic =
|
||||
spaceChild.topic?.isEmpty ?? true ? null : spaceChild.topic;
|
||||
if (spaceChild.roomId == activeSpaceId) {
|
||||
return SearchTitle(
|
||||
title:
|
||||
spaceChild.name ?? spaceChild.canonicalAlias ?? 'Space',
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Avatar(
|
||||
size: 24,
|
||||
mxContent: spaceChild.avatarUrl,
|
||||
name: spaceChild.name,
|
||||
fontSize: 9,
|
||||
),
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
spaceChild.name ??
|
||||
spaceChild.canonicalAlias ??
|
||||
L10n.of(context)!.chat,
|
||||
maxLines: 1,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
if (!isSpace) ...[
|
||||
const Icon(
|
||||
Icons.people_outline,
|
||||
size: 16,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
spaceChild.numJoinedMembers.toString(),
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondaryContainer
|
||||
.withAlpha(128),
|
||||
trailing: const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Icon(Icons.edit_outlined),
|
||||
),
|
||||
onTap: () => _onJoinSpaceChild(spaceChild),
|
||||
);
|
||||
}
|
||||
return ListTile(
|
||||
leading: Avatar(
|
||||
mxContent: spaceChild.avatarUrl,
|
||||
name: spaceChild.name,
|
||||
),
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
spaceChild.name ??
|
||||
spaceChild.canonicalAlias ??
|
||||
L10n.of(context)!.chat,
|
||||
maxLines: 1,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
onTap: () => _onJoinSpaceChild(spaceChild),
|
||||
onLongPress: () =>
|
||||
_onSpaceChildContextMenu(spaceChild, room),
|
||||
subtitle: Text(
|
||||
topic ??
|
||||
(isSpace
|
||||
? L10n.of(context)!.enterSpace
|
||||
: L10n.of(context)!.enterRoom),
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onBackground),
|
||||
),
|
||||
trailing: isSpace
|
||||
? const Icon(Icons.chevron_right_outlined)
|
||||
: null,
|
||||
);
|
||||
}),
|
||||
);
|
||||
});
|
||||
if (!isSpace) ...[
|
||||
const Icon(
|
||||
Icons.people_outline,
|
||||
size: 16,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
spaceChild.numJoinedMembers.toString(),
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
onTap: () => _onJoinSpaceChild(spaceChild),
|
||||
onLongPress: () => _onSpaceChildContextMenu(spaceChild, room),
|
||||
subtitle: Text(
|
||||
topic ??
|
||||
(isSpace
|
||||
? L10n.of(context)!.enterSpace
|
||||
: L10n.of(context)!.enterRoom),
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onBackground,
|
||||
),
|
||||
),
|
||||
trailing:
|
||||
isSpace ? const Icon(Icons.chevron_right_outlined) : null,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue