mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2025-02-21 16:50:41 +01:00
change: Implement contact list instead of status
This commit is contained in:
parent
6960618f55
commit
b9be33c16b
74
lib/components/list_items/contact_list_tile.dart
Normal file
74
lib/components/list_items/contact_list_tile.dart
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
|
||||||
|
import 'package:famedlysdk/famedlysdk.dart';
|
||||||
|
import 'package:fluffychat/components/avatar.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../utils/presence_extension.dart';
|
||||||
|
import '../matrix.dart';
|
||||||
|
|
||||||
|
class ContactListTile extends StatelessWidget {
|
||||||
|
final Presence contact;
|
||||||
|
|
||||||
|
const ContactListTile({Key key, @required this.contact}) : super(key: key);
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var statusMsg = contact.presence?.statusMsg?.isNotEmpty ?? false
|
||||||
|
? contact.presence.statusMsg
|
||||||
|
: null;
|
||||||
|
if (contact.senderId == '@jana:janian.de') {
|
||||||
|
statusMsg = 'Hallo Welt';
|
||||||
|
}
|
||||||
|
return FutureBuilder<Profile>(
|
||||||
|
future:
|
||||||
|
Matrix.of(context).client.getProfileFromUserId(contact.senderId),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final displayname =
|
||||||
|
snapshot.data?.displayname ?? contact.senderId.localpart;
|
||||||
|
final avatarUrl = snapshot.data?.avatarUrl;
|
||||||
|
return ListTile(
|
||||||
|
leading: Avatar(avatarUrl, displayname),
|
||||||
|
title: Row(
|
||||||
|
children: [
|
||||||
|
Icon(Icons.circle, color: contact.color, size: 10),
|
||||||
|
SizedBox(width: 4),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
displayname,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
subtitle: statusMsg == null
|
||||||
|
? Text(contact.getLocalizedLastActiveAgo(context))
|
||||||
|
: Row(
|
||||||
|
children: [
|
||||||
|
Icon(Icons.edit_outlined,
|
||||||
|
color: Theme.of(context).accentColor, size: 12),
|
||||||
|
SizedBox(width: 2),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
statusMsg,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(
|
||||||
|
color:
|
||||||
|
Theme.of(context).textTheme.bodyText1.color,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () async {
|
||||||
|
if (contact.senderId == Matrix.of(context).client.userID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final roomId = await User(contact.senderId,
|
||||||
|
room: Room(id: '', client: Matrix.of(context).client))
|
||||||
|
.startDirectChat();
|
||||||
|
await AdaptivePageLayout.of(context)
|
||||||
|
.pushNamedAndRemoveUntilIsFirst('/rooms/${roomId}');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,136 +0,0 @@
|
|||||||
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
import 'package:famedlysdk/famedlysdk.dart';
|
|
||||||
import 'package:fluffychat/components/avatar.dart';
|
|
||||||
import 'package:fluffychat/utils/fluffy_share.dart';
|
|
||||||
import 'package:fluffychat/utils/status.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:future_loading_dialog/future_loading_dialog.dart';
|
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|
||||||
|
|
||||||
import '../../utils/string_color.dart';
|
|
||||||
import '../../utils/date_time_extension.dart';
|
|
||||||
import '../matrix.dart';
|
|
||||||
|
|
||||||
class StatusListTile extends StatelessWidget {
|
|
||||||
final Status status;
|
|
||||||
|
|
||||||
const StatusListTile({Key key, @required this.status}) : super(key: key);
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final text = status.message;
|
|
||||||
final isImage = text.startsWith('mxc://') && text.split(' ').length == 1;
|
|
||||||
return FutureBuilder<Profile>(
|
|
||||||
future: Matrix.of(context).client.getProfileFromUserId(status.senderId),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
final displayname =
|
|
||||||
snapshot.data?.displayname ?? status.senderId.localpart;
|
|
||||||
final avatarUrl = snapshot.data?.avatarUrl;
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
ListTile(
|
|
||||||
leading: Avatar(avatarUrl, displayname),
|
|
||||||
title: Text(
|
|
||||||
displayname,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
subtitle: Text(status.dateTime.localizedTime(context),
|
|
||||||
style: TextStyle(fontSize: 14)),
|
|
||||||
trailing: Matrix.of(context).client.userID == status.senderId
|
|
||||||
? null
|
|
||||||
: PopupMenuButton(
|
|
||||||
onSelected: (_) => AdaptivePageLayout.of(context)
|
|
||||||
.pushNamed('/settings/ignore',
|
|
||||||
arguments: status.senderId),
|
|
||||||
itemBuilder: (_) => [
|
|
||||||
PopupMenuItem(
|
|
||||||
child: Text(L10n.of(context).ignore),
|
|
||||||
value: 'ignore',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
isImage
|
|
||||||
? CachedNetworkImage(
|
|
||||||
imageUrl: Uri.parse(text).getThumbnail(
|
|
||||||
Matrix.of(context).client,
|
|
||||||
width: 360,
|
|
||||||
height: 360,
|
|
||||||
method: ThumbnailMethod.scale,
|
|
||||||
),
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
width: double.infinity,
|
|
||||||
)
|
|
||||||
: Container(
|
|
||||||
height: 256,
|
|
||||||
color: text.color,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
padding: EdgeInsets.all(12),
|
|
||||||
child: Text(
|
|
||||||
text,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 24,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 12.0, left: 12.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(CupertinoIcons.chat_bubble),
|
|
||||||
onPressed:
|
|
||||||
Matrix.of(context).client.userID == status.senderId
|
|
||||||
? null
|
|
||||||
: () async {
|
|
||||||
final result = await showFutureLoadingDialog(
|
|
||||||
context: context,
|
|
||||||
future: () => User(
|
|
||||||
status.senderId,
|
|
||||||
room: Room(
|
|
||||||
id: '',
|
|
||||||
client: Matrix.of(context).client),
|
|
||||||
).startDirectChat(),
|
|
||||||
);
|
|
||||||
if (result.error == null) {
|
|
||||||
await AdaptivePageLayout.of(context)
|
|
||||||
.pushNamed('/rooms/${result.result}');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.ios_share),
|
|
||||||
onPressed: () => AdaptivePageLayout.of(context)
|
|
||||||
.pushNamed('/newstatus', arguments: status.message),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.share_outlined),
|
|
||||||
onPressed: () => FluffyShare.share(
|
|
||||||
'$displayname: ${status.message}',
|
|
||||||
context,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.delete_outlined),
|
|
||||||
onPressed: () => showFutureLoadingDialog(
|
|
||||||
context: context,
|
|
||||||
future: () => Matrix.of(context)
|
|
||||||
.removeStatusOfUser(status.senderId),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,7 +10,6 @@ import 'package:fluffychat/utils/firebase_controller.dart';
|
|||||||
import 'package:fluffychat/utils/matrix_locals.dart';
|
import 'package:fluffychat/utils/matrix_locals.dart';
|
||||||
import 'package:fluffychat/utils/platform_infos.dart';
|
import 'package:fluffychat/utils/platform_infos.dart';
|
||||||
import 'package:fluffychat/utils/sentry_controller.dart';
|
import 'package:fluffychat/utils/sentry_controller.dart';
|
||||||
import 'package:fluffychat/utils/status.dart';
|
|
||||||
import 'package:flushbar/flushbar.dart';
|
import 'package:flushbar/flushbar.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -127,7 +126,6 @@ class MatrixState extends State<Matrix> {
|
|||||||
StreamSubscription onKeyVerificationRequestSub;
|
StreamSubscription onKeyVerificationRequestSub;
|
||||||
StreamSubscription onJitsiCallSub;
|
StreamSubscription onJitsiCallSub;
|
||||||
StreamSubscription onNotification;
|
StreamSubscription onNotification;
|
||||||
StreamSubscription<Presence> onPresence;
|
|
||||||
StreamSubscription<LoginState> onLoginStateChanged;
|
StreamSubscription<LoginState> onLoginStateChanged;
|
||||||
StreamSubscription<UiaRequest> onUiaRequest;
|
StreamSubscription<UiaRequest> onUiaRequest;
|
||||||
StreamSubscription<html.Event> onFocusSub;
|
StreamSubscription<html.Event> onFocusSub;
|
||||||
@ -290,10 +288,6 @@ class MatrixState extends State<Matrix> {
|
|||||||
LoadingDialog.defaultBackLabel = L10n.of(context).close;
|
LoadingDialog.defaultBackLabel = L10n.of(context).close;
|
||||||
LoadingDialog.defaultOnError = (Object e) => e.toLocalizedString(context);
|
LoadingDialog.defaultOnError = (Object e) => e.toLocalizedString(context);
|
||||||
|
|
||||||
onPresence ??= client.onPresence.stream
|
|
||||||
.where((p) => p.presence?.statusMsg != null)
|
|
||||||
.listen(_onPresence);
|
|
||||||
|
|
||||||
onRoomKeyRequestSub ??=
|
onRoomKeyRequestSub ??=
|
||||||
client.onRoomKeyRequest.stream.listen((RoomKeyRequest request) async {
|
client.onRoomKeyRequest.stream.listen((RoomKeyRequest request) async {
|
||||||
final room = request.room;
|
final room = request.room;
|
||||||
@ -401,45 +395,6 @@ class MatrixState extends State<Matrix> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Status> get statuses {
|
|
||||||
if (client.accountData.containsKey(Status.namespace)) {
|
|
||||||
try {
|
|
||||||
return client.accountData[Status.namespace].content
|
|
||||||
.map((k, v) => MapEntry(k, Status.fromJson(v)));
|
|
||||||
} catch (e, s) {
|
|
||||||
Logs()
|
|
||||||
.e('Unable to parse status account data. Clearing up now...', e, s);
|
|
||||||
client.setAccountData(client.userID, Status.namespace, {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onPresence(Presence presence) async {
|
|
||||||
if (statuses[presence.senderId]?.message != presence.presence.statusMsg) {
|
|
||||||
Logs().v('Update status from ${presence.senderId}');
|
|
||||||
await client.setAccountData(
|
|
||||||
client.userID,
|
|
||||||
Status.namespace,
|
|
||||||
statuses.map((k, v) => MapEntry(k, v.toJson()))
|
|
||||||
..[presence.senderId] = Status(
|
|
||||||
presence.senderId,
|
|
||||||
presence.presence.statusMsg,
|
|
||||||
DateTime.now(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> removeStatusOfUser(String userId) async {
|
|
||||||
await client.setAccountData(
|
|
||||||
client.userID,
|
|
||||||
Status.namespace,
|
|
||||||
statuses.map((k, v) => MapEntry(k, v.toJson()))..remove(userId),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
onRoomKeyRequestSub?.cancel();
|
onRoomKeyRequestSub?.cancel();
|
||||||
@ -448,7 +403,6 @@ class MatrixState extends State<Matrix> {
|
|||||||
onNotification?.cancel();
|
onNotification?.cancel();
|
||||||
onFocusSub?.cancel();
|
onFocusSub?.cancel();
|
||||||
onBlurSub?.cancel();
|
onBlurSub?.cancel();
|
||||||
onPresence?.cancel();
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,34 @@
|
|||||||
import 'package:famedlysdk/famedlysdk.dart';
|
import 'package:famedlysdk/famedlysdk.dart';
|
||||||
|
|
||||||
extension ClientPresenceExtension on Client {
|
extension ClientPresenceExtension on Client {
|
||||||
List<Presence> get statuses => presences.values
|
List<Presence> get contactList {
|
||||||
.where((p) => p.presence.statusMsg?.isNotEmpty ?? false)
|
final directChatsMxid = rooms
|
||||||
|
.where((r) => r.isDirectChat)
|
||||||
|
.map((r) => r.directChatMatrixID)
|
||||||
|
.toSet();
|
||||||
|
final contactList = directChatsMxid
|
||||||
|
.map(
|
||||||
|
(mxid) =>
|
||||||
|
presences[mxid] ??
|
||||||
|
Presence.fromJson(
|
||||||
|
{
|
||||||
|
'sender': mxid,
|
||||||
|
'type': 'm.presence',
|
||||||
|
'content': {'presence': 'online'},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
.toList();
|
.toList();
|
||||||
|
contactList.addAll(
|
||||||
|
presences.values
|
||||||
|
.where((p) =>
|
||||||
|
!directChatsMxid.contains(p.senderId) &&
|
||||||
|
(p.presence?.statusMsg?.isNotEmpty ?? false))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
contactList.sort((a, b) => (a.presence.lastActiveAgo?.toDouble() ??
|
||||||
|
double.infinity)
|
||||||
|
.compareTo((b.presence.lastActiveAgo?.toDouble() ?? double.infinity)));
|
||||||
|
return contactList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,4 +37,16 @@ extension PresenceExtension on Presence {
|
|||||||
}
|
}
|
||||||
return presence.presence.getLocalized(context);
|
return presence.presence.getLocalized(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color get color {
|
||||||
|
switch (presence?.presence ?? PresenceType.offline) {
|
||||||
|
case PresenceType.online:
|
||||||
|
return Colors.green;
|
||||||
|
case PresenceType.offline:
|
||||||
|
return Colors.red;
|
||||||
|
case PresenceType.unavailable:
|
||||||
|
default:
|
||||||
|
return Colors.grey;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
class Status {
|
|
||||||
static const String namespace = 'im.fluffychat.statuses';
|
|
||||||
final String senderId;
|
|
||||||
final String message;
|
|
||||||
final DateTime dateTime;
|
|
||||||
|
|
||||||
Status(this.senderId, this.message, this.dateTime);
|
|
||||||
|
|
||||||
Status.fromJson(Map<String, dynamic> json)
|
|
||||||
: senderId = json['sender_id'],
|
|
||||||
message = json['message'],
|
|
||||||
dateTime = DateTime.fromMillisecondsSinceEpoch(json['date_time']);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => <String, dynamic>{
|
|
||||||
'sender_id': senderId,
|
|
||||||
'message': message,
|
|
||||||
'date_time': dateTime.millisecondsSinceEpoch,
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||||
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
|
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
|
||||||
import 'package:fluffychat/app_config.dart';
|
import 'package:fluffychat/app_config.dart';
|
||||||
|
import 'package:fluffychat/components/avatar.dart';
|
||||||
import 'package:fluffychat/components/matrix.dart';
|
import 'package:fluffychat/components/matrix.dart';
|
||||||
import 'package:fluffychat/utils/fluffy_share.dart';
|
import 'package:fluffychat/utils/fluffy_share.dart';
|
||||||
import 'package:flushbar/flushbar_helper.dart';
|
import 'package:flushbar/flushbar_helper.dart';
|
||||||
@ -238,6 +239,7 @@ class _ChatDetailsState extends State<ChatDetails> {
|
|||||||
.scaffoldBackgroundColor,
|
.scaffoldBackgroundColor,
|
||||||
foregroundColor: Colors.grey,
|
foregroundColor: Colors.grey,
|
||||||
child: Icon(Icons.edit_outlined),
|
child: Icon(Icons.edit_outlined),
|
||||||
|
radius: Avatar.defaultSize / 2,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
title: Text('${L10n.of(context).groupDescription}:',
|
title: Text('${L10n.of(context).groupDescription}:',
|
||||||
|
@ -12,13 +12,14 @@ import 'package:fluffychat/app_config.dart';
|
|||||||
import 'package:fluffychat/utils/platform_infos.dart';
|
import 'package:fluffychat/utils/platform_infos.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:future_loading_dialog/future_loading_dialog.dart';
|
||||||
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
||||||
import '../components/matrix.dart';
|
import '../components/matrix.dart';
|
||||||
import '../utils/matrix_file_extension.dart';
|
import '../utils/matrix_file_extension.dart';
|
||||||
import '../utils/url_launcher.dart';
|
import '../utils/url_launcher.dart';
|
||||||
import 'home_view_parts/chat_list.dart';
|
import 'home_view_parts/chat_list.dart';
|
||||||
import 'home_view_parts/settings.dart';
|
import 'home_view_parts/settings.dart';
|
||||||
import 'home_view_parts/status_list.dart';
|
import 'home_view_parts/contact_list.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
|
|
||||||
enum SelectMode { normal, share, select }
|
enum SelectMode { normal, share, select }
|
||||||
@ -143,11 +144,30 @@ class _HomeViewState extends State<HomeView> with TickerProviderStateMixin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _setStatus() async {
|
||||||
|
final input = await showTextInputDialog(
|
||||||
|
context: context,
|
||||||
|
title: L10n.of(context).setStatus,
|
||||||
|
textFields: [
|
||||||
|
DialogTextField(
|
||||||
|
hintText: L10n.of(context).statusExampleMessage,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
if (input == null) return;
|
||||||
|
await showFutureLoadingDialog(
|
||||||
|
context: context,
|
||||||
|
future: () => Matrix.of(context).client.sendPresence(
|
||||||
|
Matrix.of(context).client.userID,
|
||||||
|
PresenceType.online,
|
||||||
|
statusMsg: input.single,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void _onFabTab() {
|
void _onFabTab() {
|
||||||
switch (currentIndex) {
|
switch (currentIndex) {
|
||||||
case 0:
|
case 0:
|
||||||
AdaptivePageLayout.of(context)
|
_setStatus();
|
||||||
.pushNamedAndRemoveUntilIsFirst('/newstatus');
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
AdaptivePageLayout.of(context)
|
AdaptivePageLayout.of(context)
|
||||||
@ -212,7 +232,7 @@ class _HomeViewState extends State<HomeView> with TickerProviderStateMixin {
|
|||||||
body: TabBarView(
|
body: TabBarView(
|
||||||
controller: _pageController,
|
controller: _pageController,
|
||||||
children: [
|
children: [
|
||||||
StatusList(key: Key('StatusList')),
|
ContactList(),
|
||||||
ChatList(
|
ChatList(
|
||||||
onCustomAppBar: (appBar) => setState(() => this.appBar = appBar),
|
onCustomAppBar: (appBar) => setState(() => this.appBar = appBar),
|
||||||
),
|
),
|
||||||
@ -246,8 +266,8 @@ class _HomeViewState extends State<HomeView> with TickerProviderStateMixin {
|
|||||||
},
|
},
|
||||||
items: [
|
items: [
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
label: L10n.of(context).status,
|
label: L10n.of(context).contacts,
|
||||||
icon: Icon(Icons.home_outlined),
|
icon: Icon(Icons.people_outlined),
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
label: L10n.of(context).messages,
|
label: L10n.of(context).messages,
|
||||||
|
72
lib/views/home_view_parts/contact_list.dart
Normal file
72
lib/views/home_view_parts/contact_list.dart
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
|
||||||
|
import 'package:fluffychat/components/avatar.dart';
|
||||||
|
import 'package:fluffychat/components/default_app_bar_search_field.dart';
|
||||||
|
import 'package:fluffychat/components/list_items/contact_list_tile.dart';
|
||||||
|
import 'package:fluffychat/components/matrix.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import '../../utils/client_presence_extension.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
|
|
||||||
|
class ContactList extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_ContactListState createState() => _ContactListState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ContactListState extends State<ContactList> {
|
||||||
|
String _searchQuery = '';
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListView(children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(12),
|
||||||
|
child: DefaultAppBarSearchField(
|
||||||
|
hintText: L10n.of(context).search,
|
||||||
|
prefixIcon: Icon(Icons.search_outlined),
|
||||||
|
onChanged: (t) => setState(() => _searchQuery = t),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: CircleAvatar(
|
||||||
|
backgroundColor: Theme.of(context).primaryColor,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
child: Icon(Icons.add_outlined),
|
||||||
|
radius: Avatar.defaultSize / 2,
|
||||||
|
),
|
||||||
|
title: Text('Add new contact'),
|
||||||
|
onTap: () =>
|
||||||
|
AdaptivePageLayout.of(context).pushNamed('/newprivatechat'),
|
||||||
|
),
|
||||||
|
Divider(height: 1),
|
||||||
|
StreamBuilder<Object>(
|
||||||
|
stream: Matrix.of(context).client.onSync.stream,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final contactList = Matrix.of(context)
|
||||||
|
.client
|
||||||
|
.contactList
|
||||||
|
.where((p) => p.senderId
|
||||||
|
.toLowerCase()
|
||||||
|
.contains(_searchQuery.toLowerCase()))
|
||||||
|
.toList();
|
||||||
|
if (contactList.isEmpty) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text(
|
||||||
|
'No contacts found...',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return ListView.builder(
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
padding: EdgeInsets.only(bottom: 24),
|
||||||
|
itemCount: contactList.length,
|
||||||
|
itemBuilder: (context, i) =>
|
||||||
|
ContactListTile(contact: contactList[i]),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -1,78 +0,0 @@
|
|||||||
import 'package:fluffychat/components/list_items/status_list_tile.dart';
|
|
||||||
import 'package:fluffychat/components/matrix.dart';
|
|
||||||
import 'package:fluffychat/utils/status.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|
||||||
|
|
||||||
class StatusList extends StatefulWidget {
|
|
||||||
const StatusList({Key key}) : super(key: key);
|
|
||||||
@override
|
|
||||||
_StatusListState createState() => _StatusListState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _StatusListState extends State<StatusList> {
|
|
||||||
bool _onlyContacts = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ListView(children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
RaisedButton(
|
|
||||||
elevation: _onlyContacts ? 7 : null,
|
|
||||||
color: !_onlyContacts ? null : Theme.of(context).primaryColor,
|
|
||||||
child: Text(
|
|
||||||
L10n.of(context).contacts,
|
|
||||||
style: TextStyle(color: _onlyContacts ? Colors.white : null),
|
|
||||||
),
|
|
||||||
onPressed: () => setState(() => _onlyContacts = true),
|
|
||||||
),
|
|
||||||
RaisedButton(
|
|
||||||
elevation: !_onlyContacts ? 7 : null,
|
|
||||||
color: _onlyContacts ? null : Theme.of(context).primaryColor,
|
|
||||||
child: Text(
|
|
||||||
L10n.of(context).all,
|
|
||||||
style: TextStyle(color: !_onlyContacts ? Colors.white : null),
|
|
||||||
),
|
|
||||||
onPressed: () => setState(() => _onlyContacts = false),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Divider(height: 1),
|
|
||||||
StreamBuilder<Object>(
|
|
||||||
stream: Matrix.of(context)
|
|
||||||
.client
|
|
||||||
.onAccountData
|
|
||||||
.stream
|
|
||||||
.where((a) => a.type == Status.namespace),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
final statuses = Matrix.of(context).statuses.values.toList()
|
|
||||||
..sort((a, b) => b.dateTime.compareTo(a.dateTime));
|
|
||||||
if (_onlyContacts) {
|
|
||||||
final client = Matrix.of(context).client;
|
|
||||||
statuses.removeWhere(
|
|
||||||
(p) => client.getDirectChatFromUserId(p.senderId) == null);
|
|
||||||
}
|
|
||||||
if (statuses.isEmpty) {
|
|
||||||
return Container(
|
|
||||||
padding: EdgeInsets.all(16),
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: Text(
|
|
||||||
L10n.of(context).noStatusesFound,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return ListView.separated(
|
|
||||||
physics: NeverScrollableScrollPhysics(),
|
|
||||||
shrinkWrap: true,
|
|
||||||
padding: EdgeInsets.only(bottom: 24),
|
|
||||||
separatorBuilder: (_, __) => Divider(height: 1),
|
|
||||||
itemCount: statuses.length,
|
|
||||||
itemBuilder: (context, i) => StatusListTile(status: statuses[i]),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user