mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2024-11-27 23:09:35 +01:00
Implement status feature and new design
This commit is contained in:
parent
be948ff8b1
commit
6c5976f4a1
@ -1,3 +1,8 @@
|
|||||||
|
# Version 0.13.0 - 2020-??-??
|
||||||
|
### Features:
|
||||||
|
- New status feature
|
||||||
|
- Enhanced chat list design
|
||||||
|
|
||||||
# Version 0.12.4 - 2020-04-17
|
# Version 0.12.4 - 2020-04-17
|
||||||
### Fixed
|
### Fixed
|
||||||
- Login without google services
|
- Login without google services
|
||||||
|
93
lib/components/list_items/presence_list_item.dart
Normal file
93
lib/components/list_items/presence_list_item.dart
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import 'package:famedlysdk/famedlysdk.dart';
|
||||||
|
import 'package:fluffychat/i18n/i18n.dart';
|
||||||
|
import 'package:fluffychat/utils/app_route.dart';
|
||||||
|
import 'package:fluffychat/utils/date_time_extension.dart';
|
||||||
|
import 'package:fluffychat/views/chat.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../avatar.dart';
|
||||||
|
import '../matrix.dart';
|
||||||
|
import 'package:fluffychat/utils/presence_extension.dart';
|
||||||
|
|
||||||
|
class PresenceListItem extends StatelessWidget {
|
||||||
|
final Presence presence;
|
||||||
|
|
||||||
|
const PresenceListItem(this.presence);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return FutureBuilder<Profile>(
|
||||||
|
future: Matrix.of(context).client.getProfileFromUserId(presence.sender),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
MxContent avatarUrl = MxContent('');
|
||||||
|
String displayname = presence.sender.localpart;
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
avatarUrl = snapshot.data.avatarUrl;
|
||||||
|
displayname = snapshot.data.displayname;
|
||||||
|
}
|
||||||
|
return InkWell(
|
||||||
|
onTap: () => showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (c) => AlertDialog(
|
||||||
|
title: ListTile(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
leading: Avatar(avatarUrl, displayname),
|
||||||
|
title: Text(displayname),
|
||||||
|
subtitle: Text(presence.sender),
|
||||||
|
),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(presence.getLocalizedStatusMessage(context)),
|
||||||
|
Text(
|
||||||
|
presence.time.localizedTime(context),
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
if (presence.sender != Matrix.of(context).client.userID)
|
||||||
|
FlatButton(
|
||||||
|
child: Text(I18n.of(context).sendAMessage),
|
||||||
|
onPressed: () async {
|
||||||
|
final String roomId = await User(
|
||||||
|
presence.sender,
|
||||||
|
room: Room(id: '', client: Matrix.of(context).client),
|
||||||
|
).startDirectChat();
|
||||||
|
await Navigator.of(context).pushAndRemoveUntil(
|
||||||
|
AppRoute.defaultRoute(
|
||||||
|
context,
|
||||||
|
ChatView(roomId),
|
||||||
|
),
|
||||||
|
(Route r) => r.isFirst);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
FlatButton(
|
||||||
|
child: Text(I18n.of(context).close),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
width: 80,
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
SizedBox(height: 6),
|
||||||
|
Avatar(avatarUrl, displayname),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(6.0),
|
||||||
|
child: Text(
|
||||||
|
displayname,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -406,7 +406,7 @@ class MatrixState extends State<Matrix> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
if (widget.client == null) {
|
if (widget.client == null) {
|
||||||
debugPrint("[Matrix] Init matrix client");
|
debugPrint("[Matrix] Init matrix client");
|
||||||
client = Client(widget.clientName, debug: true);
|
client = Client(widget.clientName, debug: false);
|
||||||
onJitsiCallSub ??= client.onEvent.stream
|
onJitsiCallSub ??= client.onEvent.stream
|
||||||
.where((e) =>
|
.where((e) =>
|
||||||
e.type == 'timeline' &&
|
e.type == 'timeline' &&
|
||||||
|
@ -624,6 +624,8 @@ class I18n {
|
|||||||
|
|
||||||
String get setInvitationLink => Intl.message("Set invitation link");
|
String get setInvitationLink => Intl.message("Set invitation link");
|
||||||
|
|
||||||
|
String get setStatus => Intl.message('Set status');
|
||||||
|
|
||||||
String get settings => Intl.message("Settings");
|
String get settings => Intl.message("Settings");
|
||||||
|
|
||||||
String get signUp => Intl.message("Sign up");
|
String get signUp => Intl.message("Sign up");
|
||||||
@ -632,6 +634,8 @@ class I18n {
|
|||||||
|
|
||||||
String get systemTheme => Intl.message("System");
|
String get systemTheme => Intl.message("System");
|
||||||
|
|
||||||
|
String get statusExampleMessage => Intl.message("How are you today?");
|
||||||
|
|
||||||
String get lightTheme => Intl.message("Light");
|
String get lightTheme => Intl.message("Light");
|
||||||
|
|
||||||
String get darkTheme => Intl.message("Dark");
|
String get darkTheme => Intl.message("Dark");
|
||||||
|
11
lib/utils/client_presence_extension.dart
Normal file
11
lib/utils/client_presence_extension.dart
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:famedlysdk/famedlysdk.dart';
|
||||||
|
import 'presence_extension.dart';
|
||||||
|
|
||||||
|
extension ClientPresenceExtension on Client {
|
||||||
|
List<Presence> get statusList {
|
||||||
|
final statusList = presences.values.toList();
|
||||||
|
statusList.removeWhere((Presence p) => !p.isStatus);
|
||||||
|
statusList.sort((a, b) => b.time.compareTo(a.time));
|
||||||
|
return statusList;
|
||||||
|
}
|
||||||
|
}
|
25
lib/utils/presence_extension.dart
Normal file
25
lib/utils/presence_extension.dart
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import 'package:famedlysdk/famedlysdk.dart';
|
||||||
|
import 'package:fluffychat/i18n/i18n.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
extension PresenceExtension on Presence {
|
||||||
|
bool get isStatus =>
|
||||||
|
(statusMsg?.isNotEmpty ?? false) ||
|
||||||
|
this.displayname != null ||
|
||||||
|
this.avatarUrl != null;
|
||||||
|
|
||||||
|
String getLocalizedStatusMessage(BuildContext context) {
|
||||||
|
if (!isStatus) return null;
|
||||||
|
if (statusMsg?.isNotEmpty ?? false) {
|
||||||
|
return statusMsg;
|
||||||
|
}
|
||||||
|
if (displayname != null) {
|
||||||
|
return I18n.of(context)
|
||||||
|
.changedTheDisplaynameTo(sender.localpart, displayname);
|
||||||
|
}
|
||||||
|
if (avatarUrl != null) {
|
||||||
|
return I18n.of(context).changedTheProfileAvatar(sender.localpart);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -2,13 +2,15 @@ import 'dart:async';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:famedlysdk/famedlysdk.dart';
|
import 'package:famedlysdk/famedlysdk.dart';
|
||||||
|
import 'package:fluffychat/components/dialogs/simple_dialogs.dart';
|
||||||
|
import 'package:fluffychat/components/list_items/presence_list_item.dart';
|
||||||
import 'package:fluffychat/components/list_items/public_room_list_item.dart';
|
import 'package:fluffychat/components/list_items/public_room_list_item.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
||||||
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
||||||
|
import 'package:share/share.dart';
|
||||||
|
|
||||||
import '../components/dialogs/simple_dialogs.dart';
|
|
||||||
import '../components/theme_switcher.dart';
|
import '../components/theme_switcher.dart';
|
||||||
import '../components/adaptive_page_layout.dart';
|
import '../components/adaptive_page_layout.dart';
|
||||||
import '../components/list_items/chat_list_item.dart';
|
import '../components/list_items/chat_list_item.dart';
|
||||||
@ -16,6 +18,7 @@ import '../components/matrix.dart';
|
|||||||
import '../i18n/i18n.dart';
|
import '../i18n/i18n.dart';
|
||||||
import '../utils/app_route.dart';
|
import '../utils/app_route.dart';
|
||||||
import '../utils/url_launcher.dart';
|
import '../utils/url_launcher.dart';
|
||||||
|
import '../utils/client_presence_extension.dart';
|
||||||
import 'archive.dart';
|
import 'archive.dart';
|
||||||
import 'new_group.dart';
|
import 'new_group.dart';
|
||||||
import 'new_private_chat.dart';
|
import 'new_private_chat.dart';
|
||||||
@ -48,7 +51,7 @@ class ChatList extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ChatListState extends State<ChatList> {
|
class _ChatListState extends State<ChatList> {
|
||||||
bool searchMode = false;
|
bool get searchMode => searchController.text?.isNotEmpty ?? false;
|
||||||
StreamSubscription sub;
|
StreamSubscription sub;
|
||||||
final TextEditingController searchController = TextEditingController();
|
final TextEditingController searchController = TextEditingController();
|
||||||
SelectMode selectMode = SelectMode.normal;
|
SelectMode selectMode = SelectMode.normal;
|
||||||
@ -71,6 +74,13 @@ class _ChatListState extends State<ChatList> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
searchController.addListener(() {
|
searchController.addListener(() {
|
||||||
coolDown?.cancel();
|
coolDown?.cancel();
|
||||||
|
if (searchController.text.isEmpty) {
|
||||||
|
setState(() {
|
||||||
|
loadingPublicRooms = false;
|
||||||
|
publicRoomsResponse = null;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
coolDown = Timer(Duration(seconds: 1), () async {
|
coolDown = Timer(Duration(seconds: 1), () async {
|
||||||
setState(() => loadingPublicRooms = true);
|
setState(() => loadingPublicRooms = true);
|
||||||
final newPublicRoomsResponse =
|
final newPublicRoomsResponse =
|
||||||
@ -160,6 +170,39 @@ class _ChatListState extends State<ChatList> {
|
|||||||
ReceiveSharingIntent.getInitialText().then(_processIncomingSharedText);
|
ReceiveSharingIntent.getInitialText().then(_processIncomingSharedText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _drawerTapAction(Widget view) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
Navigator.of(context).pushAndRemoveUntil(
|
||||||
|
AppRoute.defaultRoute(
|
||||||
|
context,
|
||||||
|
view,
|
||||||
|
),
|
||||||
|
(r) => r.isFirst,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setStatus(BuildContext context) async {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
final status = await SimpleDialogs(context).enterText(
|
||||||
|
multiLine: true,
|
||||||
|
titleText: I18n.of(context).setStatus,
|
||||||
|
labelText: I18n.of(context).setStatus,
|
||||||
|
hintText: I18n.of(context).statusExampleMessage,
|
||||||
|
);
|
||||||
|
if (status?.isEmpty ?? true) return;
|
||||||
|
await Matrix.of(context).tryRequestWithLoadingDialog(
|
||||||
|
Matrix.of(context).client.jsonRequest(
|
||||||
|
type: HTTPType.PUT,
|
||||||
|
action:
|
||||||
|
'/client/r0/presence/${Matrix.of(context).client.userID}/status',
|
||||||
|
data: {
|
||||||
|
"presence": "online",
|
||||||
|
"status_msg": status,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
sub?.cancel();
|
sub?.cancel();
|
||||||
@ -186,109 +229,102 @@ class _ChatListState extends State<ChatList> {
|
|||||||
setState(() => selectMode = SelectMode.normal);
|
setState(() => selectMode = SelectMode.normal);
|
||||||
}
|
}
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
drawer: Drawer(
|
||||||
title: searchMode
|
child: SafeArea(
|
||||||
? TextField(
|
child: ListView(
|
||||||
autofocus: true,
|
padding: EdgeInsets.zero,
|
||||||
autocorrect: false,
|
children: <Widget>[
|
||||||
controller: searchController,
|
ListTile(
|
||||||
decoration: InputDecoration(
|
leading: Icon(Icons.edit),
|
||||||
border: InputBorder.none,
|
title: Text(I18n.of(context).setStatus),
|
||||||
hintText: I18n.of(context).searchForAChat,
|
onTap: () => _setStatus(context),
|
||||||
),
|
|
||||||
)
|
|
||||||
: Text(
|
|
||||||
selectMode == SelectMode.share
|
|
||||||
? I18n.of(context).share
|
|
||||||
: I18n.of(context).fluffychat,
|
|
||||||
),
|
),
|
||||||
leading: searchMode
|
Divider(height: 1),
|
||||||
? IconButton(
|
ListTile(
|
||||||
icon: Icon(Icons.arrow_back),
|
leading: Icon(Icons.people_outline),
|
||||||
onPressed: () => setState(() {
|
title: Text(I18n.of(context).createNewGroup),
|
||||||
publicRoomsResponse = null;
|
onTap: () => _drawerTapAction(NewGroupView()),
|
||||||
loadingPublicRooms = false;
|
),
|
||||||
searchMode = false;
|
ListTile(
|
||||||
}),
|
leading: Icon(Icons.person_add),
|
||||||
)
|
title: Text(I18n.of(context).newPrivateChat),
|
||||||
: selectMode == SelectMode.share
|
onTap: () => _drawerTapAction(NewPrivateChatView()),
|
||||||
? IconButton(
|
),
|
||||||
icon: Icon(Icons.close),
|
Divider(height: 1),
|
||||||
onPressed: () {
|
ListTile(
|
||||||
Matrix.of(context).shareContent = null;
|
leading: Icon(Icons.archive),
|
||||||
setState(() => selectMode = SelectMode.normal);
|
title: Text(I18n.of(context).archive),
|
||||||
},
|
onTap: () => _drawerTapAction(
|
||||||
)
|
Archive(),
|
||||||
: null,
|
|
||||||
automaticallyImplyLeading: false,
|
|
||||||
actions: searchMode
|
|
||||||
? <Widget>[
|
|
||||||
if (loadingPublicRooms)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 8.0),
|
|
||||||
child: Center(
|
|
||||||
child: CircularProgressIndicator(strokeWidth: 2),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.domain),
|
|
||||||
onPressed: () async {
|
|
||||||
final String newSearchServer = await SimpleDialogs(context)
|
|
||||||
.enterText(
|
|
||||||
titleText: I18n.of(context).changeTheServer,
|
|
||||||
labelText: I18n.of(context).changeTheServer,
|
|
||||||
hintText: Matrix.of(context).client.userID.domain,
|
|
||||||
prefixText: "https://");
|
|
||||||
if (newSearchServer?.isNotEmpty ?? false) {
|
|
||||||
searchServer = newSearchServer;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
]
|
|
||||||
: <Widget>[
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.search),
|
|
||||||
onPressed: () => setState(() => searchMode = true),
|
|
||||||
),
|
),
|
||||||
if (selectMode == SelectMode.normal)
|
),
|
||||||
PopupMenuButton(
|
ListTile(
|
||||||
onSelected: (String choice) {
|
leading: Icon(Icons.settings),
|
||||||
switch (choice) {
|
title: Text(I18n.of(context).settings),
|
||||||
case "settings":
|
onTap: () => _drawerTapAction(
|
||||||
Navigator.of(context).pushAndRemoveUntil(
|
SettingsView(),
|
||||||
AppRoute.defaultRoute(
|
),
|
||||||
context,
|
),
|
||||||
SettingsView(),
|
Divider(height: 1),
|
||||||
),
|
ListTile(
|
||||||
(r) => r.isFirst,
|
leading: Icon(Icons.share),
|
||||||
);
|
title: Text(I18n.of(context).inviteContact),
|
||||||
break;
|
onTap: () {
|
||||||
case "archive":
|
Navigator.of(context).pop();
|
||||||
Navigator.of(context).pushAndRemoveUntil(
|
Share.share(I18n.of(context).inviteText(
|
||||||
AppRoute.defaultRoute(
|
Matrix.of(context).client.userID,
|
||||||
context,
|
"https://matrix.to/#/${Matrix.of(context).client.userID}"));
|
||||||
Archive(),
|
},
|
||||||
),
|
),
|
||||||
(r) => r.isFirst,
|
],
|
||||||
);
|
),
|
||||||
break;
|
),
|
||||||
}
|
|
||||||
},
|
|
||||||
itemBuilder: (BuildContext context) =>
|
|
||||||
<PopupMenuEntry<String>>[
|
|
||||||
PopupMenuItem<String>(
|
|
||||||
value: "archive",
|
|
||||||
child: Text(I18n.of(context).archive),
|
|
||||||
),
|
|
||||||
PopupMenuItem<String>(
|
|
||||||
value: "settings",
|
|
||||||
child: Text(I18n.of(context).settings),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
floatingActionButton: selectMode == SelectMode.share
|
appBar: AppBar(
|
||||||
|
elevation: 0,
|
||||||
|
titleSpacing: 6,
|
||||||
|
title: Container(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
height: 42,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).secondaryHeaderColor,
|
||||||
|
borderRadius: BorderRadius.circular(90),
|
||||||
|
),
|
||||||
|
child: TextField(
|
||||||
|
autocorrect: false,
|
||||||
|
controller: searchController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
suffixIcon: loadingPublicRooms
|
||||||
|
? Container(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
)
|
||||||
|
: Icon(Icons.search),
|
||||||
|
contentPadding: EdgeInsets.all(9),
|
||||||
|
border: InputBorder.none,
|
||||||
|
hintText: I18n.of(context).searchForAChat,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottom: Matrix.of(context).client.statusList.isEmpty
|
||||||
|
? null
|
||||||
|
: 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]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
floatingActionButton: AdaptivePageLayout.columnMode(context) &&
|
||||||
|
selectMode == SelectMode.share
|
||||||
? null
|
? null
|
||||||
: SpeedDial(
|
: SpeedDial(
|
||||||
child: Icon(Icons.add),
|
child: Icon(Icons.add),
|
||||||
@ -318,61 +354,76 @@ class _ChatListState extends State<ChatList> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: FutureBuilder<bool>(
|
body: Column(
|
||||||
future: waitForFirstSync(context),
|
children: <Widget>[
|
||||||
builder: (BuildContext context, snapshot) {
|
Divider(
|
||||||
if (snapshot.hasData) {
|
height: 1,
|
||||||
List<Room> rooms = List<Room>.from(Matrix.of(context).client.rooms);
|
color: Theme.of(context).secondaryHeaderColor,
|
||||||
rooms.removeWhere((Room room) =>
|
),
|
||||||
searchMode &&
|
Expanded(
|
||||||
!room.displayname
|
child: FutureBuilder<bool>(
|
||||||
.toLowerCase()
|
future: waitForFirstSync(context),
|
||||||
.contains(searchController.text.toLowerCase() ?? ""));
|
builder: (BuildContext context, snapshot) {
|
||||||
if (rooms.isEmpty && (!searchMode || publicRoomsResponse == null)) {
|
if (snapshot.hasData) {
|
||||||
return Center(
|
List<Room> rooms =
|
||||||
child: Column(
|
List<Room>.from(Matrix.of(context).client.rooms);
|
||||||
mainAxisSize: MainAxisSize.min,
|
rooms.removeWhere((Room room) =>
|
||||||
children: <Widget>[
|
searchMode &&
|
||||||
Icon(
|
!room.displayname
|
||||||
searchMode ? Icons.search : Icons.chat_bubble_outline,
|
.toLowerCase()
|
||||||
size: 80,
|
.contains(searchController.text.toLowerCase() ?? ""));
|
||||||
color: Colors.grey,
|
if (rooms.isEmpty &&
|
||||||
),
|
(!searchMode || publicRoomsResponse == null)) {
|
||||||
Text(searchMode
|
return Center(
|
||||||
? I18n.of(context).noRoomsFound
|
child: Column(
|
||||||
: I18n.of(context).startYourFirstChat),
|
mainAxisSize: MainAxisSize.min,
|
||||||
],
|
children: <Widget>[
|
||||||
),
|
Icon(
|
||||||
);
|
searchMode
|
||||||
}
|
? Icons.search
|
||||||
final int publicRoomsCount =
|
: Icons.chat_bubble_outline,
|
||||||
(publicRoomsResponse?.publicRooms?.length ?? 0);
|
size: 80,
|
||||||
final int totalCount = rooms.length + publicRoomsCount;
|
color: Colors.grey,
|
||||||
return ListView.separated(
|
|
||||||
separatorBuilder: (BuildContext context, int i) =>
|
|
||||||
i == totalCount - publicRoomsCount - 1
|
|
||||||
? Material(
|
|
||||||
elevation: 2,
|
|
||||||
child: ListTile(
|
|
||||||
title: Text(I18n.of(context).publicRooms),
|
|
||||||
),
|
),
|
||||||
)
|
Text(searchMode
|
||||||
: Container(),
|
? I18n.of(context).noRoomsFound
|
||||||
itemCount: totalCount,
|
: I18n.of(context).startYourFirstChat),
|
||||||
itemBuilder: (BuildContext context, int i) => i < rooms.length
|
],
|
||||||
? ChatListItem(
|
),
|
||||||
rooms[i],
|
);
|
||||||
activeChat: widget.activeChat == rooms[i].id,
|
}
|
||||||
)
|
final int publicRoomsCount =
|
||||||
: PublicRoomListItem(
|
(publicRoomsResponse?.publicRooms?.length ?? 0);
|
||||||
publicRoomsResponse.publicRooms[i - rooms.length]),
|
final int totalCount = rooms.length + publicRoomsCount;
|
||||||
);
|
return ListView.separated(
|
||||||
} else {
|
separatorBuilder: (BuildContext context, int i) =>
|
||||||
return Center(
|
i == totalCount - publicRoomsCount - 1
|
||||||
child: CircularProgressIndicator(),
|
? Material(
|
||||||
);
|
elevation: 2,
|
||||||
}
|
child: ListTile(
|
||||||
},
|
title: Text(I18n.of(context).publicRooms),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Container(),
|
||||||
|
itemCount: totalCount,
|
||||||
|
itemBuilder: (BuildContext context, int i) => i <
|
||||||
|
rooms.length
|
||||||
|
? ChatListItem(
|
||||||
|
rooms[i],
|
||||||
|
activeChat: widget.activeChat == rooms[i].id,
|
||||||
|
)
|
||||||
|
: PublicRoomListItem(
|
||||||
|
publicRoomsResponse.publicRooms[i - rooms.length]),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user