horrible implementation of thread list in room
This commit is contained in:
parent
1757a7a4af
commit
0f5c19b0ce
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:extera_next/pages/chat_thread/chat_threads.dart';
|
|
||||||
import 'package:extera_next/pages/chat_thread/thread.dart';
|
import 'package:extera_next/pages/chat_thread/thread.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
@ -153,13 +152,6 @@ abstract class AppRoutes {
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'threads',
|
path: 'threads',
|
||||||
pageBuilder: (context, state) => defaultPageBuilder(
|
|
||||||
context,
|
|
||||||
state,
|
|
||||||
ChatThreads(
|
|
||||||
roomId: state.pathParameters['roomid']!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
redirect: loggedOutRedirect,
|
redirect: loggedOutRedirect,
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
|
|
@ -377,6 +369,7 @@ abstract class AppRoutes {
|
||||||
roomId: state.pathParameters['roomid']!,
|
roomId: state.pathParameters['roomid']!,
|
||||||
shareItems: shareItems,
|
shareItems: shareItems,
|
||||||
eventId: state.uri.queryParameters['event'],
|
eventId: state.uri.queryParameters['event'],
|
||||||
|
showThreadRoots: state.uri.queryParameters['threads'] == 'true',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -51,12 +51,14 @@ class ChatPage extends StatelessWidget {
|
||||||
final String roomId;
|
final String roomId;
|
||||||
final List<ShareItem>? shareItems;
|
final List<ShareItem>? shareItems;
|
||||||
final String? eventId;
|
final String? eventId;
|
||||||
|
final bool? showThreadRoots;
|
||||||
|
|
||||||
const ChatPage({
|
const ChatPage({
|
||||||
super.key,
|
super.key,
|
||||||
required this.roomId,
|
required this.roomId,
|
||||||
this.eventId,
|
this.eventId,
|
||||||
this.shareItems,
|
this.shareItems,
|
||||||
|
this.showThreadRoots,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -79,6 +81,7 @@ class ChatPage extends StatelessWidget {
|
||||||
room: room,
|
room: room,
|
||||||
shareItems: shareItems,
|
shareItems: shareItems,
|
||||||
eventId: eventId,
|
eventId: eventId,
|
||||||
|
showThreadRoots: showThreadRoots,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -88,6 +91,7 @@ class ChatPageWithRoom extends StatefulWidget {
|
||||||
final Thread? thread;
|
final Thread? thread;
|
||||||
final List<ShareItem>? shareItems;
|
final List<ShareItem>? shareItems;
|
||||||
final String? eventId;
|
final String? eventId;
|
||||||
|
final bool? showThreadRoots;
|
||||||
|
|
||||||
const ChatPageWithRoom({
|
const ChatPageWithRoom({
|
||||||
super.key,
|
super.key,
|
||||||
|
|
@ -95,6 +99,7 @@ class ChatPageWithRoom extends StatefulWidget {
|
||||||
this.thread,
|
this.thread,
|
||||||
this.shareItems,
|
this.shareItems,
|
||||||
this.eventId,
|
this.eventId,
|
||||||
|
this.showThreadRoots,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -104,6 +109,7 @@ class ChatPageWithRoom extends StatefulWidget {
|
||||||
class ChatController extends State<ChatPageWithRoom>
|
class ChatController extends State<ChatPageWithRoom>
|
||||||
with WidgetsBindingObserver {
|
with WidgetsBindingObserver {
|
||||||
Room get room => sendingClient.getRoomById(roomId) ?? widget.room;
|
Room get room => sendingClient.getRoomById(roomId) ?? widget.room;
|
||||||
|
bool get showThreadRoots => (widget.showThreadRoots ?? false);
|
||||||
Thread? get thread =>
|
Thread? get thread =>
|
||||||
sendingClient.getRoomById(roomId)?.threads[threadRootEventId] ??
|
sendingClient.getRoomById(roomId)?.threads[threadRootEventId] ??
|
||||||
widget.room.threads[threadRootEventId];
|
widget.room.threads[threadRootEventId];
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,12 @@ import 'package:extera_next/utils/platform_infos.dart';
|
||||||
|
|
||||||
class ChatEventList extends StatelessWidget {
|
class ChatEventList extends StatelessWidget {
|
||||||
final ChatController controller;
|
final ChatController controller;
|
||||||
|
final bool showThreadRoots;
|
||||||
|
|
||||||
const ChatEventList({
|
const ChatEventList({
|
||||||
super.key,
|
super.key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
|
this.showThreadRoots = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -37,7 +39,14 @@ class ChatEventList extends StatelessWidget {
|
||||||
|
|
||||||
final horizontalPadding = FluffyThemes.isColumnMode(context) ? 8.0 : 0.0;
|
final horizontalPadding = FluffyThemes.isColumnMode(context) ? 8.0 : 0.0;
|
||||||
|
|
||||||
final events = timeline.events.filterByVisibleInGui().filterByThreaded(controller.thread != null);
|
var events = timeline.events.filterByVisibleInGui();
|
||||||
|
|
||||||
|
if (showThreadRoots) {
|
||||||
|
events = events.filterThreadRoots();
|
||||||
|
} else {
|
||||||
|
events = events.filterByThreaded(controller.thread != null);
|
||||||
|
}
|
||||||
|
|
||||||
final animateInEventIndex = controller.animateInEventIndex;
|
final animateInEventIndex = controller.animateInEventIndex;
|
||||||
final threads = controller.room.threads;
|
final threads = controller.room.threads;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,7 @@ class ChatView extends StatelessWidget {
|
||||||
onTap: controller.clearSingleSelectedEvent,
|
onTap: controller.clearSingleSelectedEvent,
|
||||||
child: ChatEventList(
|
child: ChatEventList(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
showThreadRoots: controller.showThreadRoots,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -349,7 +350,8 @@ class ChatView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
else if (controller.room.canSendDefaultMessages &&
|
else if (controller.room.canSendDefaultMessages &&
|
||||||
controller.room.membership == Membership.join)
|
controller.room.membership == Membership.join &&
|
||||||
|
!controller.showThreadRoots)
|
||||||
Container(
|
Container(
|
||||||
margin: EdgeInsets.all(bottomSheetPadding),
|
margin: EdgeInsets.all(bottomSheetPadding),
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:extera_next/pages/chat_thread/chat_threads_view.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,7 @@ class ChatDetailsView extends StatelessWidget {
|
||||||
subtitle:
|
subtitle:
|
||||||
Text(L10n.of(context).chatThreadsDescription),
|
Text(L10n.of(context).chatThreadsDescription),
|
||||||
onTap: () =>
|
onTap: () =>
|
||||||
context.push('/rooms/${room.id}/threads'),
|
context.push('/rooms/${room.id}?threads=true'),
|
||||||
trailing: const Icon(Icons.chevron_right_outlined),
|
trailing: const Icon(Icons.chevron_right_outlined),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
import 'package:extera_next/pages/chat_thread/chat_threads_view.dart';
|
|
||||||
import 'package:extera_next/widgets/matrix.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:matrix/matrix.dart';
|
|
||||||
import 'package:scroll_to_index/scroll_to_index.dart';
|
|
||||||
|
|
||||||
class ChatThreads extends StatefulWidget {
|
|
||||||
final String roomId;
|
|
||||||
|
|
||||||
const ChatThreads({
|
|
||||||
super.key,
|
|
||||||
required this.roomId,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
ChatThreadsController createState() => ChatThreadsController();
|
|
||||||
}
|
|
||||||
|
|
||||||
class ChatThreadsController extends State<ChatThreads> {
|
|
||||||
String get roomId => widget.roomId;
|
|
||||||
Room? get room => Matrix.of(context).client.getRoomById(roomId);
|
|
||||||
|
|
||||||
bool isLoadingThreads = false;
|
|
||||||
|
|
||||||
final AutoScrollController scrollController = AutoScrollController();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => ChatThreadsView(this);
|
|
||||||
|
|
||||||
void loadThreads([dynamic _]) async {
|
|
||||||
final room = Matrix.of(context).client.getRoomById(roomId);
|
|
||||||
|
|
||||||
if (room == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
isLoadingThreads = true;
|
|
||||||
|
|
||||||
await room.loadThreadsFromServer();
|
|
||||||
|
|
||||||
isLoadingThreads = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Thread>? get threads => room?.threads.values.toList();
|
|
||||||
|
|
||||||
Stream get onChanged => Matrix.of(context).client.onSync.stream.where(
|
|
||||||
(e) =>
|
|
||||||
(e.rooms?.join?.containsKey(roomId) ?? false) &&
|
|
||||||
(e.rooms!.join![roomId]?.timeline?.events
|
|
||||||
?.any((s) => s.type == EventTypes.Message && s.content['m.relates_to'] != null) ??
|
|
||||||
false),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
import 'package:extera_next/config/themes.dart';
|
|
||||||
import 'package:extera_next/generated/l10n/l10n.dart';
|
|
||||||
import 'package:extera_next/pages/chat_thread/chat_threads.dart';
|
|
||||||
import 'package:extera_next/utils/platform_infos.dart';
|
|
||||||
import 'package:extera_next/widgets/avatar.dart';
|
|
||||||
import 'package:extera_next/widgets/layouts/max_width_body.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:matrix/matrix.dart';
|
|
||||||
import 'package:scroll_to_index/scroll_to_index.dart';
|
|
||||||
|
|
||||||
class ChatThreadsView extends StatelessWidget {
|
|
||||||
final ChatThreadsController controller;
|
|
||||||
|
|
||||||
const ChatThreadsView(this.controller, {super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final horizontalPadding = FluffyThemes.isColumnMode(context) ? 8.0 : 0.0;
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: const Center(child: BackButton()),
|
|
||||||
title: Text(L10n.of(context).chatThreads),
|
|
||||||
),
|
|
||||||
body: MaxWidthBody(
|
|
||||||
child: ListView.custom(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
top: 16,
|
|
||||||
bottom: 8,
|
|
||||||
left: horizontalPadding,
|
|
||||||
right: horizontalPadding,
|
|
||||||
),
|
|
||||||
reverse: true,
|
|
||||||
controller: controller.scrollController,
|
|
||||||
keyboardDismissBehavior: PlatformInfos.isIOS
|
|
||||||
? ScrollViewKeyboardDismissBehavior.onDrag
|
|
||||||
: ScrollViewKeyboardDismissBehavior.manual,
|
|
||||||
childrenDelegate: SliverChildBuilderDelegate(
|
|
||||||
(BuildContext context, int i) {
|
|
||||||
if (i == (controller.threads?.length ?? 0) + 1) {
|
|
||||||
if (controller.isLoadingThreads) {
|
|
||||||
return const Center(
|
|
||||||
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
|
|
||||||
);
|
|
||||||
} else if (!(controller.room?.loadedAllThreads ?? false)) {
|
|
||||||
return Builder(
|
|
||||||
builder: (context) {
|
|
||||||
WidgetsBinding.instance
|
|
||||||
.addPostFrameCallback(controller.loadThreads);
|
|
||||||
return Center(
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: controller.loadThreads,
|
|
||||||
icon: const Icon(Icons.refresh_outlined),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
i--;
|
|
||||||
|
|
||||||
final thread = controller.threads![i];
|
|
||||||
|
|
||||||
return AutoScrollTag(
|
|
||||||
key: ValueKey(thread.rootEvent.eventId),
|
|
||||||
index: i,
|
|
||||||
controller: controller.scrollController,
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 16.0,
|
|
||||||
vertical: 8.0,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: <Widget>[
|
|
||||||
FutureBuilder<User?>(
|
|
||||||
future: thread.rootEvent.fetchSenderUser(),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
final user = snapshot.data ??
|
|
||||||
thread.rootEvent.senderFromMemoryOrFallback;
|
|
||||||
|
|
||||||
return Avatar(
|
|
||||||
mxContent: user.avatarUrl,
|
|
||||||
name: user.calcDisplayname(),
|
|
||||||
size: 48,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(thread.rootEvent.senderFromMemoryOrFallback.calcDisplayname()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 4.0),
|
|
||||||
Text(thread.rootEvent.text),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
childCount: (controller.threads?.length ?? 0) + 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue