From ad757cb56d4098b47766796df2fc66f7415e9569 Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sat, 9 May 2020 05:17:55 +0000 Subject: [PATCH] Krille/use stream builder --- lib/views/chat_details.dart | 583 ++++++++++++------------ lib/views/chat_encryption_settings.dart | 189 ++++---- lib/views/chat_list.dart | 439 +++++++++--------- 3 files changed, 607 insertions(+), 604 deletions(-) diff --git a/lib/views/chat_details.dart b/lib/views/chat_details.dart index 254764f5..f023e340 100644 --- a/lib/views/chat_details.dart +++ b/lib/views/chat_details.dart @@ -1,4 +1,3 @@ -import 'dart:async'; import 'dart:io'; import 'package:famedlysdk/famedlysdk.dart'; @@ -131,14 +130,6 @@ class _ChatDetailsState extends State { if (participants != null) setState(() => members = participants); } - StreamSubscription onUpdate; - - @override - void dispose() { - onUpdate?.cancel(); - super.dispose(); - } - @override Widget build(BuildContext context) { if (widget.room == null) { @@ -156,293 +147,313 @@ class _ChatDetailsState extends State { final int actualMembersCount = widget.room.mInvitedMemberCount + widget.room.mJoinedMemberCount; final bool canRequestMoreMembers = members.length < actualMembersCount; - this.onUpdate ??= widget.room.onUpdate.stream - .listen((id) => setState(() => members = null)); return AdaptivePageLayout( primaryPage: FocusPage.SECOND, firstScaffold: ChatList( activeChat: widget.room.id, ), - secondScaffold: Scaffold( - body: NestedScrollView( - headerSliverBuilder: - (BuildContext context, bool innerBoxIsScrolled) => [ - SliverAppBar( - expandedHeight: 300.0, - floating: true, - pinned: true, - actions: [ - if (widget.room.canonicalAlias?.isNotEmpty ?? false) - IconButton( - icon: Icon(Icons.share), - onPressed: () { - Clipboard.setData( - ClipboardData(text: widget.room.canonicalAlias), - ); - showToast(L10n.of(context).copiedToClipboard); - }, + secondScaffold: StreamBuilder( + stream: widget.room.onUpdate.stream, + builder: (context, snapshot) { + return Scaffold( + body: NestedScrollView( + headerSliverBuilder: + (BuildContext context, bool innerBoxIsScrolled) => [ + SliverAppBar( + expandedHeight: 300.0, + floating: true, + pinned: true, + actions: [ + if (widget.room.canonicalAlias?.isNotEmpty ?? false) + IconButton( + icon: Icon(Icons.share), + onPressed: () { + Clipboard.setData( + ClipboardData(text: widget.room.canonicalAlias), + ); + showToast(L10n.of(context).copiedToClipboard); + }, + ), + ChatSettingsPopupMenu(widget.room, false) + ], + title: Text( + widget.room.getLocalizedDisplayname(L10n.of(context)), + style: TextStyle( + color: Theme.of(context) + .appBarTheme + .textTheme + .headline6 + .color)), + backgroundColor: Theme.of(context).appBarTheme.color, + flexibleSpace: FlexibleSpaceBar( + background: ContentBanner(widget.room.avatar, + onEdit: widget.room.canSendEvent("m.room.avatar") && + !kIsWeb + ? () => setAvatarAction(context) + : null), + ), ), - ChatSettingsPopupMenu(widget.room, false) - ], - title: Text(widget.room.getLocalizedDisplayname(L10n.of(context)), - style: TextStyle( - color: Theme.of(context) - .appBarTheme - .textTheme - .headline6 - .color)), - backgroundColor: Theme.of(context).appBarTheme.color, - flexibleSpace: FlexibleSpaceBar( - background: ContentBanner(widget.room.avatar, - onEdit: widget.room.canSendEvent("m.room.avatar") && !kIsWeb - ? () => setAvatarAction(context) - : null), - ), - ), - ], - body: ListView.builder( - itemCount: members.length + 1 + (canRequestMoreMembers ? 1 : 0), - itemBuilder: (BuildContext context, int i) => i == 0 - ? Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - ListTile( - leading: widget.room.canSendEvent("m.room.topic") - ? CircleAvatar( + ], + body: ListView.builder( + itemCount: + members.length + 1 + (canRequestMoreMembers ? 1 : 0), + itemBuilder: (BuildContext context, int i) => i == 0 + ? Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ListTile( + leading: widget.room.canSendEvent("m.room.topic") + ? CircleAvatar( + backgroundColor: Theme.of(context) + .scaffoldBackgroundColor, + foregroundColor: Colors.grey, + child: Icon(Icons.edit), + ) + : null, + title: Text( + "${L10n.of(context).groupDescription}:", + style: TextStyle( + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.bold)), + subtitle: LinkText( + text: widget.room.topic?.isEmpty ?? true + ? L10n.of(context).addGroupDescription + : widget.room.topic, + linkStyle: TextStyle(color: Colors.blueAccent), + textStyle: TextStyle( + fontSize: 14, + color: Theme.of(context) + .textTheme + .bodyText2 + .color, + ), + ), + onTap: widget.room.canSendEvent("m.room.topic") + ? () => setTopicAction(context) + : null, + ), + Divider(thickness: 1), + ListTile( + title: Text( + L10n.of(context).settings, + style: TextStyle( + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.bold, + ), + ), + ), + if (widget.room.canSendEvent("m.room.name")) + ListTile( + leading: CircleAvatar( + backgroundColor: + Theme.of(context).scaffoldBackgroundColor, + foregroundColor: Colors.grey, + child: Icon(Icons.people), + ), + title: Text( + L10n.of(context).changeTheNameOfTheGroup), + subtitle: Text(widget.room + .getLocalizedDisplayname(L10n.of(context))), + onTap: () => setDisplaynameAction(context), + ), + if (widget.room + .canSendEvent("m.room.canonical_alias") && + widget.room.joinRules == JoinRules.public) + ListTile( + leading: CircleAvatar( + backgroundColor: + Theme.of(context).scaffoldBackgroundColor, + foregroundColor: Colors.grey, + child: Icon(Icons.link), + ), + onTap: () => setCanonicalAliasAction(context), + title: Text(L10n.of(context).setInvitationLink), + subtitle: Text( + (widget.room.canonicalAlias?.isNotEmpty ?? + false) + ? widget.room.canonicalAlias + : L10n.of(context).none), + ), + PopupMenuButton( + child: ListTile( + leading: CircleAvatar( + backgroundColor: Theme.of(context) + .scaffoldBackgroundColor, + foregroundColor: Colors.grey, + child: Icon(Icons.public)), + title: Text(L10n.of(context) + .whoIsAllowedToJoinThisGroup), + subtitle: Text( + widget.room.joinRules + .getLocalizedString(L10n.of(context)), + ), + ), + onSelected: (JoinRules joinRule) => + SimpleDialogs(context) + .tryRequestWithLoadingDialog( + widget.room.setJoinRules(joinRule), + ), + itemBuilder: (BuildContext context) => + >[ + if (widget.room.canChangeJoinRules) + PopupMenuItem( + value: JoinRules.public, + child: Text(JoinRules.public + .getLocalizedString(L10n.of(context))), + ), + if (widget.room.canChangeJoinRules) + PopupMenuItem( + value: JoinRules.invite, + child: Text(JoinRules.invite + .getLocalizedString(L10n.of(context))), + ), + ], + ), + PopupMenuButton( + child: ListTile( + leading: CircleAvatar( + backgroundColor: + Theme.of(context).scaffoldBackgroundColor, + foregroundColor: Colors.grey, + child: Icon(Icons.visibility), + ), + title: Text(L10n.of(context) + .visibilityOfTheChatHistory), + subtitle: Text( + widget.room.historyVisibility + .getLocalizedString(L10n.of(context)), + ), + ), + onSelected: + (HistoryVisibility historyVisibility) => + SimpleDialogs(context) + .tryRequestWithLoadingDialog( + widget.room + .setHistoryVisibility(historyVisibility), + ), + itemBuilder: (BuildContext context) => + >[ + if (widget.room.canChangeHistoryVisibility) + PopupMenuItem( + value: HistoryVisibility.invited, + child: Text(HistoryVisibility.invited + .getLocalizedString(L10n.of(context))), + ), + if (widget.room.canChangeHistoryVisibility) + PopupMenuItem( + value: HistoryVisibility.joined, + child: Text(HistoryVisibility.joined + .getLocalizedString(L10n.of(context))), + ), + if (widget.room.canChangeHistoryVisibility) + PopupMenuItem( + value: HistoryVisibility.shared, + child: Text(HistoryVisibility.shared + .getLocalizedString(L10n.of(context))), + ), + if (widget.room.canChangeHistoryVisibility) + PopupMenuItem( + value: HistoryVisibility.world_readable, + child: Text(HistoryVisibility.world_readable + .getLocalizedString(L10n.of(context))), + ), + ], + ), + if (widget.room.joinRules == JoinRules.public) + PopupMenuButton( + child: ListTile( + leading: CircleAvatar( + backgroundColor: Theme.of(context) + .scaffoldBackgroundColor, + foregroundColor: Colors.grey, + child: Icon(Icons.info_outline), + ), + title: Text( + L10n.of(context).areGuestsAllowedToJoin), + subtitle: Text( + widget.room.guestAccess + .getLocalizedString(L10n.of(context)), + ), + ), + onSelected: (GuestAccess guestAccess) => + SimpleDialogs(context) + .tryRequestWithLoadingDialog( + widget.room.setGuestAccess(guestAccess), + ), + itemBuilder: (BuildContext context) => + >[ + if (widget.room.canChangeGuestAccess) + PopupMenuItem( + value: GuestAccess.can_join, + child: Text( + GuestAccess.can_join.getLocalizedString( + L10n.of(context)), + ), + ), + if (widget.room.canChangeGuestAccess) + PopupMenuItem( + value: GuestAccess.forbidden, + child: Text( + GuestAccess.forbidden + .getLocalizedString( + L10n.of(context)), + ), + ), + ], + ), + Divider(thickness: 1), + ListTile( + title: Text( + actualMembersCount > 1 + ? L10n.of(context).countParticipants( + actualMembersCount.toString()) + : L10n.of(context).emptyChat, + style: TextStyle( + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.bold, + ), + ), + ), + widget.room.canInvite + ? ListTile( + title: Text(L10n.of(context).inviteContact), + leading: CircleAvatar( + child: Icon(Icons.add), + backgroundColor: + Theme.of(context).primaryColor, + foregroundColor: Colors.white, + ), + onTap: () => Navigator.of(context).push( + AppRoute.defaultRoute( + context, + InvitationSelection(widget.room), + ), + ), + ) + : Container(), + ], + ) + : i < members.length + 1 + ? ParticipantListItem(members[i - 1]) + : ListTile( + title: Text(L10n.of(context) + .loadCountMoreParticipants( + (actualMembersCount - members.length) + .toString())), + leading: CircleAvatar( backgroundColor: Theme.of(context).scaffoldBackgroundColor, - foregroundColor: Colors.grey, - child: Icon(Icons.edit), - ) - : null, - title: Text("${L10n.of(context).groupDescription}:", - style: TextStyle( - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.bold)), - subtitle: LinkText( - text: widget.room.topic?.isEmpty ?? true - ? L10n.of(context).addGroupDescription - : widget.room.topic, - linkStyle: TextStyle(color: Colors.blueAccent), - textStyle: TextStyle( - fontSize: 14, - color: Theme.of(context).textTheme.bodyText2.color, - ), - ), - onTap: widget.room.canSendEvent("m.room.topic") - ? () => setTopicAction(context) - : null, - ), - Divider(thickness: 1), - ListTile( - title: Text( - L10n.of(context).settings, - style: TextStyle( - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.bold, - ), - ), - ), - if (widget.room.canSendEvent("m.room.name")) - ListTile( - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: Colors.grey, - child: Icon(Icons.people), - ), - title: Text(L10n.of(context).changeTheNameOfTheGroup), - subtitle: Text(widget.room - .getLocalizedDisplayname(L10n.of(context))), - onTap: () => setDisplaynameAction(context), - ), - if (widget.room.canSendEvent("m.room.canonical_alias") && - widget.room.joinRules == JoinRules.public) - ListTile( - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: Colors.grey, - child: Icon(Icons.link), - ), - onTap: () => setCanonicalAliasAction(context), - title: Text(L10n.of(context).setInvitationLink), - subtitle: Text( - (widget.room.canonicalAlias?.isNotEmpty ?? false) - ? widget.room.canonicalAlias - : L10n.of(context).none), - ), - PopupMenuButton( - child: ListTile( - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: Colors.grey, - child: Icon(Icons.public)), - title: Text( - L10n.of(context).whoIsAllowedToJoinThisGroup), - subtitle: Text( - widget.room.joinRules - .getLocalizedString(L10n.of(context)), - ), - ), - onSelected: (JoinRules joinRule) => - SimpleDialogs(context).tryRequestWithLoadingDialog( - widget.room.setJoinRules(joinRule), - ), - itemBuilder: (BuildContext context) => - >[ - if (widget.room.canChangeJoinRules) - PopupMenuItem( - value: JoinRules.public, - child: Text(JoinRules.public - .getLocalizedString(L10n.of(context))), - ), - if (widget.room.canChangeJoinRules) - PopupMenuItem( - value: JoinRules.invite, - child: Text(JoinRules.invite - .getLocalizedString(L10n.of(context))), - ), - ], - ), - PopupMenuButton( - child: ListTile( - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: Colors.grey, - child: Icon(Icons.visibility), - ), - title: - Text(L10n.of(context).visibilityOfTheChatHistory), - subtitle: Text( - widget.room.historyVisibility - .getLocalizedString(L10n.of(context)), - ), - ), - onSelected: (HistoryVisibility historyVisibility) => - SimpleDialogs(context).tryRequestWithLoadingDialog( - widget.room.setHistoryVisibility(historyVisibility), - ), - itemBuilder: (BuildContext context) => - >[ - if (widget.room.canChangeHistoryVisibility) - PopupMenuItem( - value: HistoryVisibility.invited, - child: Text(HistoryVisibility.invited - .getLocalizedString(L10n.of(context))), - ), - if (widget.room.canChangeHistoryVisibility) - PopupMenuItem( - value: HistoryVisibility.joined, - child: Text(HistoryVisibility.joined - .getLocalizedString(L10n.of(context))), - ), - if (widget.room.canChangeHistoryVisibility) - PopupMenuItem( - value: HistoryVisibility.shared, - child: Text(HistoryVisibility.shared - .getLocalizedString(L10n.of(context))), - ), - if (widget.room.canChangeHistoryVisibility) - PopupMenuItem( - value: HistoryVisibility.world_readable, - child: Text(HistoryVisibility.world_readable - .getLocalizedString(L10n.of(context))), - ), - ], - ), - if (widget.room.joinRules == JoinRules.public) - PopupMenuButton( - child: ListTile( - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: Colors.grey, - child: Icon(Icons.info_outline), - ), - title: - Text(L10n.of(context).areGuestsAllowedToJoin), - subtitle: Text( - widget.room.guestAccess - .getLocalizedString(L10n.of(context)), - ), - ), - onSelected: (GuestAccess guestAccess) => - SimpleDialogs(context) - .tryRequestWithLoadingDialog( - widget.room.setGuestAccess(guestAccess), - ), - itemBuilder: (BuildContext context) => - >[ - if (widget.room.canChangeGuestAccess) - PopupMenuItem( - value: GuestAccess.can_join, - child: Text( - GuestAccess.can_join - .getLocalizedString(L10n.of(context)), + child: Icon( + Icons.refresh, + color: Colors.grey, ), ), - if (widget.room.canChangeGuestAccess) - PopupMenuItem( - value: GuestAccess.forbidden, - child: Text( - GuestAccess.forbidden - .getLocalizedString(L10n.of(context)), - ), - ), - ], - ), - Divider(thickness: 1), - ListTile( - title: Text( - actualMembersCount > 1 - ? L10n.of(context).countParticipants( - actualMembersCount.toString()) - : L10n.of(context).emptyChat, - style: TextStyle( - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.bold, - ), - ), - ), - widget.room.canInvite - ? ListTile( - title: Text(L10n.of(context).inviteContact), - leading: CircleAvatar( - child: Icon(Icons.add), - backgroundColor: Theme.of(context).primaryColor, - foregroundColor: Colors.white, - ), - onTap: () => Navigator.of(context).push( - AppRoute.defaultRoute( - context, - InvitationSelection(widget.room), - ), - ), - ) - : Container(), - ], - ) - : i < members.length + 1 - ? ParticipantListItem(members[i - 1]) - : ListTile( - title: Text(L10n.of(context).loadCountMoreParticipants( - (actualMembersCount - members.length).toString())), - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - child: Icon( - Icons.refresh, - color: Colors.grey, - ), - ), - onTap: () => requestMoreMembersAction(context), - ), - ), - ), - ), + onTap: () => requestMoreMembersAction(context), + ), + ), + ), + ); + }), ); } } diff --git a/lib/views/chat_encryption_settings.dart b/lib/views/chat_encryption_settings.dart index 66bf4961..282e157c 100644 --- a/lib/views/chat_encryption_settings.dart +++ b/lib/views/chat_encryption_settings.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/components/adaptive_page_layout.dart'; import 'package:fluffychat/components/avatar.dart'; @@ -35,120 +33,105 @@ class ChatEncryptionSettings extends StatefulWidget { } class _ChatEncryptionSettingsState extends State { - Room room; - - StreamSubscription roomUpdate; - - @override - void dispose() { - roomUpdate?.cancel(); - super.dispose(); - } - @override Widget build(BuildContext context) { - room ??= Matrix.of(context).client.getRoomById(widget.id); - roomUpdate ??= room.onUpdate.stream.listen((s) => setState(() => null)); + final room = Matrix.of(context).client.getRoomById(widget.id); return Scaffold( appBar: AppBar( title: Text(L10n.of(context).participatingUserDevices), ), - body: Column( - children: [ - FutureBuilder>( - future: room.getUserDeviceKeys(), - builder: (BuildContext context, snapshot) { - if (snapshot.hasError) { - return Center( - child: Text(L10n.of(context).oopsSomethingWentWrong + - ": " + - snapshot.error.toString()), - ); - } - if (!snapshot.hasData) { - return Center(child: CircularProgressIndicator()); - } - final List deviceKeys = snapshot.data; - return Expanded( - child: ListView.separated( - separatorBuilder: (BuildContext context, int i) => - Divider(height: 1), - itemCount: deviceKeys.length, - itemBuilder: (BuildContext context, int i) => Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (i == 0 || - deviceKeys[i].userId != deviceKeys[i - 1].userId) - Material( - child: ListTile( - leading: Avatar( - room + body: StreamBuilder( + stream: room.onUpdate.stream, + builder: (context, snapshot) { + return FutureBuilder>( + future: room.getUserDeviceKeys(), + builder: (BuildContext context, snapshot) { + if (snapshot.hasError) { + return Center( + child: Text(L10n.of(context).oopsSomethingWentWrong + + ": " + + snapshot.error.toString()), + ); + } + if (!snapshot.hasData) { + return Center(child: CircularProgressIndicator()); + } + final List deviceKeys = snapshot.data; + return Expanded( + child: ListView.separated( + separatorBuilder: (BuildContext context, int i) => + Divider(height: 1), + itemCount: deviceKeys.length, + itemBuilder: (BuildContext context, int i) => Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (i == 0 || + deviceKeys[i].userId != deviceKeys[i - 1].userId) + Material( + child: ListTile( + leading: Avatar( + room + .getUserByMXIDSync(deviceKeys[i].userId) + .avatarUrl, + room + .getUserByMXIDSync(deviceKeys[i].userId) + .calcDisplayname(), + ), + title: Text(room .getUserByMXIDSync(deviceKeys[i].userId) - .avatarUrl, - room - .getUserByMXIDSync(deviceKeys[i].userId) - .calcDisplayname(), + .calcDisplayname()), + subtitle: Text(deviceKeys[i].userId), ), - title: Text(room - .getUserByMXIDSync(deviceKeys[i].userId) - .calcDisplayname()), - subtitle: Text(deviceKeys[i].userId), + elevation: 2, ), - elevation: 2, - ), - CheckboxListTile( - title: Text( - "${deviceKeys[i].unsigned["device_display_name"] ?? L10n.of(context).unknownDevice} - ${deviceKeys[i].deviceId}", - style: TextStyle( - color: deviceKeys[i].blocked - ? Colors.red - : deviceKeys[i].verified - ? Colors.green - : Colors.orange), - ), - subtitle: Text( - deviceKeys[i] - .keys["ed25519:${deviceKeys[i].deviceId}"] - .beautified, - style: TextStyle( - color: - Theme.of(context).textTheme.bodyText2.color), - ), - value: deviceKeys[i].verified, - onChanged: (bool newVal) { - if (newVal == true) { - if (deviceKeys[i].blocked) { + CheckboxListTile( + title: Text( + "${deviceKeys[i].unsigned["device_display_name"] ?? L10n.of(context).unknownDevice} - ${deviceKeys[i].deviceId}", + style: TextStyle( + color: deviceKeys[i].blocked + ? Colors.red + : deviceKeys[i].verified + ? Colors.green + : Colors.orange), + ), + subtitle: Text( + deviceKeys[i] + .keys["ed25519:${deviceKeys[i].deviceId}"] + .beautified, + style: TextStyle( + color: Theme.of(context) + .textTheme + .bodyText2 + .color), + ), + value: deviceKeys[i].verified, + onChanged: (bool newVal) { + if (newVal == true) { + if (deviceKeys[i].blocked) { + deviceKeys[i].setBlocked( + false, Matrix.of(context).client); + } deviceKeys[i] - .setBlocked(false, Matrix.of(context).client); + .setVerified(true, Matrix.of(context).client); + } else { + if (deviceKeys[i].verified) { + deviceKeys[i].setVerified( + false, Matrix.of(context).client); + } + deviceKeys[i] + .setBlocked(true, Matrix.of(context).client); } - deviceKeys[i] - .setVerified(true, Matrix.of(context).client); - } else { - if (deviceKeys[i].verified) { - deviceKeys[i].setVerified( - false, Matrix.of(context).client); - } - deviceKeys[i] - .setBlocked(true, Matrix.of(context).client); - } - setState(() => null); - }, - ), - ], + setState(() => null); + }, + ), + ], + ), ), - ), - ); - }, - ), - Divider(thickness: 1, height: 1), - ListTile( - title: Text("Outbound MegOlm session ID:"), - subtitle: Text( - room.outboundGroupSession?.session_id()?.beautified ?? "None"), - ), - ], - ), + ); + }, + ); + }), ); } } diff --git a/lib/views/chat_list.dart b/lib/views/chat_list.dart index 23f27ad8..13567ae9 100644 --- a/lib/views/chat_list.dart +++ b/lib/views/chat_list.dart @@ -52,21 +52,17 @@ class ChatList extends StatefulWidget { class _ChatListState extends State { bool get searchMode => searchController.text?.isNotEmpty ?? false; - StreamSubscription sub; final TextEditingController searchController = TextEditingController(); - SelectMode selectMode = SelectMode.normal; Timer coolDown; PublicRoomsResponse publicRoomsResponse; bool loadingPublicRooms = false; String searchServer; - Future waitForFirstSync(BuildContext context) async { + Future waitForFirstSync(BuildContext context) async { Client client = Matrix.of(context).client; if (client.prevBatch?.isEmpty ?? true) { await client.onFirstSync.stream.first; } - sub ??= client.onSync.stream - .listen((s) => mounted ? setState(() => null) : null); return true; } @@ -205,230 +201,243 @@ class _ChatListState extends State { @override void dispose() { - sub?.cancel(); searchController.removeListener( () => setState(() => null), ); _intentDataStreamSubscription?.cancel(); _intentFileStreamSubscription?.cancel(); - _onShareContentChangedSub?.cancel(); super.dispose(); } - StreamSubscription _onShareContentChangedSub; - @override Widget build(BuildContext context) { - _onShareContentChangedSub ??= Matrix.of(context) - .onShareContentChanged - .stream - .listen((c) => setState(() => null)); - if (Matrix.of(context).shareContent != null) { - selectMode = SelectMode.share; - } else if (selectMode == SelectMode.share) { - setState(() => selectMode = SelectMode.normal); - } - return Scaffold( - drawer: selectMode == SelectMode.share - ? null - : Drawer( - child: SafeArea( - child: ListView( - padding: EdgeInsets.zero, - children: [ - ListTile( - leading: Icon(Icons.edit), - title: Text(L10n.of(context).setStatus), - onTap: () => _setStatus(context), - ), - Divider(height: 1), - ListTile( - leading: Icon(Icons.people_outline), - title: Text(L10n.of(context).createNewGroup), - onTap: () => _drawerTapAction(NewGroupView()), - ), - ListTile( - leading: Icon(Icons.person_add), - title: Text(L10n.of(context).newPrivateChat), - onTap: () => _drawerTapAction(NewPrivateChatView()), - ), - Divider(height: 1), - ListTile( - leading: Icon(Icons.archive), - title: Text(L10n.of(context).archive), - onTap: () => _drawerTapAction( - Archive(), - ), - ), - ListTile( - leading: Icon(Icons.settings), - title: Text(L10n.of(context).settings), - onTap: () => _drawerTapAction( - SettingsView(), - ), - ), - Divider(height: 1), - ListTile( - leading: Icon(Icons.share), - title: Text(L10n.of(context).inviteContact), - onTap: () { - Navigator.of(context).pop(); - Share.share(L10n.of(context).inviteText( - Matrix.of(context).client.userID, - "https://matrix.to/#/${Matrix.of(context).client.userID}")); - }, - ), - ], - ), - ), - ), - appBar: AppBar( - leading: selectMode != SelectMode.share - ? null - : IconButton( - icon: Icon(Icons.close), - onPressed: () => Matrix.of(context).shareContent = null, - ), - titleSpacing: 0, - title: selectMode == SelectMode.share - ? Text(L10n.of(context).share) - : Container( - padding: EdgeInsets.all(8), - height: 42, - margin: EdgeInsets.only(right: 8), - decoration: BoxDecoration( - color: Theme.of(context).secondaryHeaderColor, - borderRadius: BorderRadius.circular(90), - ), - child: TextField( - autocorrect: false, - controller: searchController, - decoration: InputDecoration( - suffixIcon: loadingPublicRooms - ? Container( - alignment: Alignment.centerRight, - child: Container( - width: 20, - height: 20, - child: CircularProgressIndicator(), + return StreamBuilder( + stream: Matrix.of(context).onShareContentChanged.stream, + builder: (context, snapshot) { + final selectMode = Matrix.of(context).shareContent == null + ? SelectMode.normal + : SelectMode.share; + return Scaffold( + drawer: selectMode == SelectMode.share + ? null + : Drawer( + child: SafeArea( + child: ListView( + padding: EdgeInsets.zero, + children: [ + ListTile( + leading: Icon(Icons.edit), + title: Text(L10n.of(context).setStatus), + onTap: () => _setStatus(context), + ), + Divider(height: 1), + ListTile( + leading: Icon(Icons.people_outline), + title: Text(L10n.of(context).createNewGroup), + onTap: () => _drawerTapAction(NewGroupView()), + ), + ListTile( + leading: Icon(Icons.person_add), + title: Text(L10n.of(context).newPrivateChat), + onTap: () => _drawerTapAction(NewPrivateChatView()), + ), + Divider(height: 1), + ListTile( + leading: Icon(Icons.archive), + title: Text(L10n.of(context).archive), + onTap: () => _drawerTapAction( + Archive(), ), - ) - : Icon(Icons.search), - contentPadding: EdgeInsets.all(9), - border: InputBorder.none, - hintText: L10n.of(context).searchForAChat, + ), + ListTile( + leading: Icon(Icons.settings), + title: Text(L10n.of(context).settings), + onTap: () => _drawerTapAction( + SettingsView(), + ), + ), + Divider(height: 1), + ListTile( + leading: Icon(Icons.share), + title: Text(L10n.of(context).inviteContact), + onTap: () { + Navigator.of(context).pop(); + Share.share(L10n.of(context).inviteText( + Matrix.of(context).client.userID, + "https://matrix.to/#/${Matrix.of(context).client.userID}")); + }, + ), + ], + ), + ), ), - ), - ), - ), - floatingActionButton: (AdaptivePageLayout.columnMode(context) || - selectMode == SelectMode.share) - ? null - : SpeedDial( - child: Icon(Icons.add), - overlayColor: blackWhiteColor(context), - foregroundColor: Colors.white, - backgroundColor: Theme.of(context).primaryColor, - children: [ - SpeedDialChild( - child: Icon(Icons.people_outline), - foregroundColor: Colors.white, - backgroundColor: Colors.blue, - label: L10n.of(context).createNewGroup, - labelStyle: TextStyle(fontSize: 18.0, color: Colors.black), - onTap: () => Navigator.of(context).pushAndRemoveUntil( - AppRoute.defaultRoute(context, NewGroupView()), - (r) => r.isFirst), - ), - SpeedDialChild( - child: Icon(Icons.person_add), - foregroundColor: Colors.white, - backgroundColor: Colors.green, - label: L10n.of(context).newPrivateChat, - labelStyle: TextStyle(fontSize: 18.0, color: Colors.black), - onTap: () => Navigator.of(context).pushAndRemoveUntil( - AppRoute.defaultRoute(context, NewPrivateChatView()), - (r) => r.isFirst), - ), - ], - ), - body: FutureBuilder( - future: waitForFirstSync(context), - builder: (BuildContext context, snapshot) { - if (snapshot.hasData) { - List rooms = List.from(Matrix.of(context).client.rooms); - rooms.removeWhere((Room room) => - searchMode && - !room.displayname - .toLowerCase() - .contains(searchController.text.toLowerCase() ?? "")); - if (rooms.isEmpty && (!searchMode || publicRoomsResponse == null)) { - return Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - searchMode ? Icons.search : Icons.chat_bubble_outline, - size: 80, - color: Colors.grey, + appBar: AppBar( + leading: selectMode != SelectMode.share + ? null + : IconButton( + icon: Icon(Icons.close), + onPressed: () => Matrix.of(context).shareContent = null, ), - Text(searchMode - ? L10n.of(context).noRoomsFound - : L10n.of(context).startYourFirstChat), - ], - ), - ); - } - final int publicRoomsCount = - (publicRoomsResponse?.publicRooms?.length ?? 0); - final int totalCount = rooms.length + publicRoomsCount; - return ListView.separated( - separatorBuilder: (BuildContext context, int i) => - i == totalCount - publicRoomsCount - ? Material( - elevation: 2, - child: ListTile( - title: Text(L10n.of(context).publicRooms), - ), - ) - : Container(), - itemCount: totalCount + 1, - itemBuilder: (BuildContext context, int i) { - if (i == 0) { - return Matrix.of(context).client.statusList.isEmpty - ? Container() - : PreferredSize( - preferredSize: Size.fromHeight(89), - child: Container( - height: 81, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: - Matrix.of(context).client.statusList.length, - itemBuilder: (BuildContext context, int i) => - PresenceListItem(Matrix.of(context) - .client - .statusList[i]), - ), + titleSpacing: 0, + title: selectMode == SelectMode.share + ? Text(L10n.of(context).share) + : Container( + padding: EdgeInsets.all(8), + height: 42, + margin: EdgeInsets.only(right: 8), + decoration: BoxDecoration( + color: Theme.of(context).secondaryHeaderColor, + borderRadius: BorderRadius.circular(90), + ), + child: TextField( + autocorrect: false, + controller: searchController, + decoration: InputDecoration( + suffixIcon: loadingPublicRooms + ? Container( + alignment: Alignment.centerRight, + child: Container( + width: 20, + height: 20, + child: CircularProgressIndicator(), + ), + ) + : Icon(Icons.search), + contentPadding: EdgeInsets.all(9), + border: InputBorder.none, + hintText: L10n.of(context).searchForAChat, + ), + ), + ), + ), + floatingActionButton: (AdaptivePageLayout.columnMode(context) || + selectMode == SelectMode.share) + ? null + : SpeedDial( + child: Icon(Icons.add), + overlayColor: blackWhiteColor(context), + foregroundColor: Colors.white, + backgroundColor: Theme.of(context).primaryColor, + children: [ + SpeedDialChild( + child: Icon(Icons.people_outline), + foregroundColor: Colors.white, + backgroundColor: Colors.blue, + label: L10n.of(context).createNewGroup, + labelStyle: + TextStyle(fontSize: 18.0, color: Colors.black), + onTap: () => Navigator.of(context).pushAndRemoveUntil( + AppRoute.defaultRoute(context, NewGroupView()), + (r) => r.isFirst), + ), + SpeedDialChild( + child: Icon(Icons.person_add), + foregroundColor: Colors.white, + backgroundColor: Colors.green, + label: L10n.of(context).newPrivateChat, + labelStyle: + TextStyle(fontSize: 18.0, color: Colors.black), + onTap: () => Navigator.of(context).pushAndRemoveUntil( + AppRoute.defaultRoute( + context, NewPrivateChatView()), + (r) => r.isFirst), + ), + ], + ), + body: StreamBuilder( + stream: Matrix.of(context).client.onSync.stream, + builder: (context, snapshot) { + return FutureBuilder( + future: waitForFirstSync(context), + builder: (BuildContext context, snapshot) { + if (snapshot.hasData) { + List rooms = + List.from(Matrix.of(context).client.rooms); + rooms.removeWhere((Room room) => + searchMode && + !room.displayname.toLowerCase().contains( + searchController.text.toLowerCase() ?? "")); + if (rooms.isEmpty && + (!searchMode || publicRoomsResponse == null)) { + return Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + searchMode + ? Icons.search + : Icons.chat_bubble_outline, + size: 80, + color: Colors.grey, + ), + Text(searchMode + ? L10n.of(context).noRoomsFound + : L10n.of(context).startYourFirstChat), + ], ), ); - } - i--; - return i < rooms.length - ? ChatListItem( - rooms[i], - activeChat: widget.activeChat == rooms[i].id, - ) - : PublicRoomListItem( - publicRoomsResponse.publicRooms[i - rooms.length]); - }); - } else { - return Center( - child: CircularProgressIndicator(), - ); - } - }, - ), - ); + } + final int publicRoomsCount = + (publicRoomsResponse?.publicRooms?.length ?? 0); + final int totalCount = rooms.length + publicRoomsCount; + return ListView.separated( + separatorBuilder: (BuildContext context, int i) => + i == totalCount - publicRoomsCount + ? Material( + elevation: 2, + child: ListTile( + title: Text( + L10n.of(context).publicRooms), + ), + ) + : Container(), + itemCount: totalCount + 1, + itemBuilder: (BuildContext context, int i) { + if (i == 0) { + return Matrix.of(context) + .client + .statusList + .isEmpty + ? Container() + : PreferredSize( + preferredSize: Size.fromHeight(89), + child: Container( + height: 81, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: Matrix.of(context) + .client + .statusList + .length, + itemBuilder: + (BuildContext context, int i) => + PresenceListItem( + Matrix.of(context) + .client + .statusList[i]), + ), + ), + ); + } + i--; + return i < rooms.length + ? ChatListItem( + rooms[i], + activeChat: + widget.activeChat == rooms[i].id, + ) + : PublicRoomListItem(publicRoomsResponse + .publicRooms[i - rooms.length]); + }); + } else { + return Center( + child: CircularProgressIndicator(), + ); + } + }, + ); + }), + ); + }); } }