Merge branch 'soru/update-sdk' into 'master'

move to new sdk

See merge request ChristianPauly/fluffychat-flutter!71
This commit is contained in:
Christian Pauly 2020-06-10 08:07:02 +00:00
commit 35beaa4492
26 changed files with 172 additions and 201 deletions

View file

@ -46,9 +46,9 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
notificationChangeSub ??= Matrix.of(context) notificationChangeSub ??= Matrix.of(context)
.client .client
.onUserEvent .onAccountData
.stream .stream
.where((u) => u.type == 'account_data' && u.eventType == 'm.push_rules') .where((u) => u.type == 'm.push_rules')
.listen( .listen(
(u) => setState(() => null), (u) => setState(() => null),
); );

View file

@ -27,7 +27,7 @@ class PresenceDialog extends StatelessWidget {
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
leading: Avatar(avatarUrl, displayname), leading: Avatar(avatarUrl, displayname),
title: Text(displayname), title: Text(displayname),
subtitle: Text(presence.sender), subtitle: Text(presence.senderId),
), ),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -38,7 +38,7 @@ class PresenceDialog extends StatelessWidget {
Text( Text(
presence.presence.toString().split('.').last, presence.presence.toString().split('.').last,
style: TextStyle( style: TextStyle(
color: presence.currentlyActive == true color: presence.presence.currentlyActive == true
? Colors.green ? Colors.green
: Theme.of(context).primaryColor, : Theme.of(context).primaryColor,
), ),
@ -46,12 +46,12 @@ class PresenceDialog extends StatelessWidget {
], ],
), ),
actions: <Widget>[ actions: <Widget>[
if (presence.sender != Matrix.of(context).client.userID) if (presence.senderId != Matrix.of(context).client.userID)
FlatButton( FlatButton(
child: Text(L10n.of(context).sendAMessage), child: Text(L10n.of(context).sendAMessage),
onPressed: () async { onPressed: () async {
final roomId = await User( final roomId = await User(
presence.sender, presence.senderId,
room: Room(id: '', client: Matrix.of(context).client), room: Room(id: '', client: Matrix.of(context).client),
).startDirectChat(); ).startDirectChat();
await Navigator.of(context).pushAndRemoveUntil( await Navigator.of(context).pushAndRemoveUntil(

View file

@ -1,5 +1,6 @@
import 'package:bubble/bubble.dart'; import 'package:bubble/bubble.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:famedlysdk/encryption.dart';
import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart';
import 'package:fluffychat/components/message_content.dart'; import 'package:fluffychat/components/message_content.dart';
import 'package:fluffychat/components/reply_content.dart'; import 'package:fluffychat/components/reply_content.dart';
@ -98,11 +99,11 @@ class Message extends StatelessWidget {
['m.in_reply_to']['event_id'], ['m.in_reply_to']['event_id'],
content: {'msgtype': 'm.text', 'body': '...'}, content: {'msgtype': 'm.text', 'body': '...'},
senderId: event.senderId, senderId: event.senderId,
typeKey: 'm.room.message', type: 'm.room.message',
room: event.room, room: event.room,
roomId: event.roomId, roomId: event.roomId,
status: 1, status: 1,
time: DateTime.now(), originServerTs: DateTime.now(),
); );
return Container( return Container(
margin: EdgeInsets.symmetric(vertical: 4.0), margin: EdgeInsets.symmetric(vertical: 4.0),
@ -218,7 +219,7 @@ class _MetaRow extends StatelessWidget {
), ),
if (showDisplayname) SizedBox(width: 4), if (showDisplayname) SizedBox(width: 4),
Text( Text(
event.time.localizedTime(context), event.originServerTs.localizedTime(context),
style: TextStyle( style: TextStyle(
color: color, color: color,
fontSize: 11, fontSize: 11,

View file

@ -13,9 +13,9 @@ class PresenceListItem extends StatelessWidget {
static final Map<String, Profile> _presences = {}; static final Map<String, Profile> _presences = {};
Future<Profile> _requestProfile(BuildContext context) async { Future<Profile> _requestProfile(BuildContext context) async {
_presences[presence.sender] ??= _presences[presence.senderId] ??=
await Matrix.of(context).client.getProfileFromUserId(presence.sender); await Matrix.of(context).client.getProfileFromUserId(presence.senderId);
return _presences[presence.sender]; return _presences[presence.senderId];
} }
@override @override
@ -25,7 +25,7 @@ class PresenceListItem extends StatelessWidget {
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData) return Container(); if (!snapshot.hasData) return Container();
Uri avatarUrl; Uri avatarUrl;
var displayname = presence.sender.localpart; var displayname = presence.senderId.localpart;
if (snapshot.hasData) { if (snapshot.hasData) {
avatarUrl = snapshot.data.avatarUrl; avatarUrl = snapshot.data.avatarUrl;
displayname = snapshot.data.displayname; displayname = snapshot.data.displayname;

View file

@ -1,4 +1,5 @@
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:famedlysdk/matrix_api.dart';
import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -6,15 +7,16 @@ import '../../l10n/l10n.dart';
import '../../utils/app_route.dart'; import '../../utils/app_route.dart';
import '../../views/chat.dart'; import '../../views/chat.dart';
import '../avatar.dart'; import '../avatar.dart';
import '../matrix.dart';
class PublicRoomListItem extends StatelessWidget { class PublicRoomListItem extends StatelessWidget {
final PublicRoomEntry publicRoomEntry; final PublicRoom publicRoomEntry;
const PublicRoomListItem(this.publicRoomEntry, {Key key}) : super(key: key); const PublicRoomListItem(this.publicRoomEntry, {Key key}) : super(key: key);
void joinAction(BuildContext context) async { void joinAction(BuildContext context) async {
final success = await SimpleDialogs(context) final success = await SimpleDialogs(context).tryRequestWithLoadingDialog(
.tryRequestWithLoadingDialog(publicRoomEntry.join()); Matrix.of(context).client.api.joinRoom(publicRoomEntry.roomId));
if (success != false) { if (success != false) {
await Navigator.of(context).push( await Navigator.of(context).push(
AppRoute.defaultRoute( AppRoute.defaultRoute(

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:famedlysdk/encryption.dart';
import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart';
import 'package:fluffychat/utils/firebase_controller.dart'; import 'package:fluffychat/utils/firebase_controller.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -84,7 +85,7 @@ class MatrixState extends State<Matrix> {
} }
} }
Map<String, dynamic> getAuthByPassword(String password, String session) => { Map<String, dynamic> getAuthByPassword(String password, [String session]) => {
'type': 'm.login.password', 'type': 'm.login.password',
'identifier': { 'identifier': {
'type': 'm.id.user', 'type': 'm.id.user',
@ -92,7 +93,7 @@ class MatrixState extends State<Matrix> {
}, },
'user': client.userID, 'user': client.userID,
'password': password, 'password': password,
'session': session, if (session != null) 'session': session,
}; };
StreamSubscription onRoomKeyRequestSub; StreamSubscription onRoomKeyRequestSub;
@ -102,7 +103,7 @@ class MatrixState extends State<Matrix> {
final event = Event.fromJson( final event = Event.fromJson(
eventUpdate.content, client.getRoomById(eventUpdate.roomID)); eventUpdate.content, client.getRoomById(eventUpdate.roomID));
if (DateTime.now().millisecondsSinceEpoch - if (DateTime.now().millisecondsSinceEpoch -
event.time.millisecondsSinceEpoch > event.originServerTs.millisecondsSinceEpoch >
1000 * 60 * 5) { 1000 * 60 * 5) {
return; return;
} }
@ -227,11 +228,12 @@ class _InheritedMatrix extends InheritedWidget {
@override @override
bool updateShouldNotify(_InheritedMatrix old) { bool updateShouldNotify(_InheritedMatrix old) {
var update = old.data.client.accessToken != data.client.accessToken || var update =
old.data.client.api.accessToken != data.client.api.accessToken ||
old.data.client.userID != data.client.userID || old.data.client.userID != data.client.userID ||
old.data.client.deviceID != data.client.deviceID || old.data.client.deviceID != data.client.deviceID ||
old.data.client.deviceName != data.client.deviceName || old.data.client.deviceName != data.client.deviceName ||
old.data.client.homeserver != data.client.homeserver; old.data.client.api.homeserver != data.client.api.homeserver;
return update; return update;
} }
} }

View file

@ -90,8 +90,8 @@ class MessageContent extends StatelessWidget {
break; break;
default: default:
return Text( return Text(
L10n.of(context).userSentUnknownEvent( L10n.of(context)
event.sender.calcDisplayname(), event.typeKey), .userSentUnknownEvent(event.sender.calcDisplayname(), event.type),
style: TextStyle( style: TextStyle(
color: textColor, color: textColor,
decoration: event.redacted ? TextDecoration.lineThrough : null, decoration: event.redacted ? TextDecoration.lineThrough : null,

View file

@ -3,7 +3,7 @@ import 'package:famedlysdk/famedlysdk.dart';
extension ClientPresenceExtension on Client { extension ClientPresenceExtension on Client {
List<Presence> get statusList { List<Presence> get statusList {
final statusList = presences.values.toList().reversed.toList(); final statusList = presences.values.toList().reversed.toList();
statusList.removeWhere((p) => p.statusMsg?.isEmpty ?? true); statusList.removeWhere((p) => p.presence.statusMsg?.isEmpty ?? true);
statusList.reversed.toList(); statusList.reversed.toList();
return statusList; return statusList;
} }

View file

@ -42,7 +42,7 @@ abstract class FirebaseController {
); );
return; return;
} }
final pushers = await client.getPushers(); final pushers = await client.api.requestPushers();
final currentPushers = pushers.where((pusher) => pusher.pushkey == token); final currentPushers = pushers.where((pusher) => pusher.pushkey == token);
if (currentPushers.length == 1 && if (currentPushers.length == 1 &&
currentPushers.first.kind == 'http' && currentPushers.first.kind == 'http' &&
@ -50,35 +50,35 @@ abstract class FirebaseController {
currentPushers.first.appDisplayName == clientName && currentPushers.first.appDisplayName == clientName &&
currentPushers.first.deviceDisplayName == client.deviceName && currentPushers.first.deviceDisplayName == client.deviceName &&
currentPushers.first.lang == 'en' && currentPushers.first.lang == 'en' &&
currentPushers.first.data.url == GATEWAY_URL && currentPushers.first.data.url.toString() == GATEWAY_URL &&
currentPushers.first.data.format == PUSHER_FORMAT) { currentPushers.first.data.format == PUSHER_FORMAT) {
debugPrint('[Push] Pusher already set'); debugPrint('[Push] Pusher already set');
} else { } else {
if (currentPushers.isNotEmpty) { if (currentPushers.isNotEmpty) {
for (final currentPusher in currentPushers) { for (final currentPusher in currentPushers) {
await client.setPushers( currentPusher.pushkey = token;
token, currentPusher.kind = 'null';
'null', await client.api.setPusher(
currentPusher.appId, currentPusher,
currentPusher.appDisplayName,
currentPusher.deviceDisplayName,
currentPusher.lang,
currentPusher.data.url,
append: true, append: true,
); );
debugPrint('[Push] Remove legacy pusher for this device'); debugPrint('[Push] Remove legacy pusher for this device');
} }
} }
await client.setPushers( await client.api.setPusher(
Pusher(
token, token,
'http',
APP_ID, APP_ID,
clientName, clientName,
client.deviceName, client.deviceName,
'en', 'en',
GATEWAY_URL, PusherData(
append: false, url: Uri.parse(GATEWAY_URL),
format: PUSHER_FORMAT, format: PUSHER_FORMAT,
),
kind: 'http',
),
append: false,
); );
} }
@ -224,7 +224,7 @@ abstract class FirebaseController {
messages: [ messages: [
Message( Message(
body, body,
event.time, event.originServerTs,
person, person,
) )
], ],

View file

@ -5,9 +5,11 @@ import 'date_time_extension.dart';
extension PresenceExtension on Presence { extension PresenceExtension on Presence {
String getLocalizedStatusMessage(BuildContext context) { String getLocalizedStatusMessage(BuildContext context) {
if (statusMsg?.isNotEmpty ?? false) { if (presence.statusMsg?.isNotEmpty ?? false) {
return statusMsg; return presence.statusMsg;
} }
return L10n.of(context).lastActiveAgo(time.localizedTimeShort(context)); return L10n.of(context).lastActiveAgo(
DateTime.fromMillisecondsSinceEpoch(presence.lastActiveAgo)
.localizedTimeShort(context));
} }
} }

View file

@ -10,11 +10,13 @@ extension RoomStatusExtension on Room {
String getLocalizedStatus(BuildContext context) { String getLocalizedStatus(BuildContext context) {
if (isDirectChat) { if (isDirectChat) {
if (directChatPresence != null) { if (directChatPresence != null) {
if (directChatPresence.currentlyActive == true) { if (directChatPresence.presence.currentlyActive == true) {
return L10n.of(context).currentlyActive; return L10n.of(context).currentlyActive;
} }
return L10n.of(context) return L10n.of(context).lastActiveAgo(
.lastActiveAgo(directChatPresence.time.localizedTimeShort(context)); DateTime.fromMillisecondsSinceEpoch(
directChatPresence.presence.lastActiveAgo)
.localizedTimeShort(context));
} }
return L10n.of(context).lastSeenLongTimeAgo; return L10n.of(context).lastSeenLongTimeAgo;
} }

View file

@ -23,7 +23,7 @@ class UrlLauncher {
final identifier = url.replaceAll('https://matrix.to/#/', ''); final identifier = url.replaceAll('https://matrix.to/#/', '');
if (identifier.substring(0, 1) == '#') { if (identifier.substring(0, 1) == '#') {
final response = await SimpleDialogs(context).tryRequestWithLoadingDialog( final response = await SimpleDialogs(context).tryRequestWithLoadingDialog(
matrix.client.joinRoomById( matrix.client.api.joinRoom(
Uri.encodeComponent(identifier), Uri.encodeComponent(identifier),
), ),
); );

View file

@ -33,7 +33,7 @@ class AppInfo extends StatelessWidget {
), ),
ListTile( ListTile(
title: Text('Homeserver:'), title: Text('Homeserver:'),
subtitle: Text(client.homeserver), subtitle: Text(client.api.homeserver.toString()),
), ),
ListTile( ListTile(
title: Text('Device name:'), title: Text('Device name:'),

View file

@ -14,9 +14,8 @@ class AuthWebView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final url = final url = Matrix.of(context).client.api.homeserver.toString() +
'/_matrix/client/r0/auth/$authType/fallback/web?session=$session' + '/_matrix/client/r0/auth/$authType/fallback/web?session=$session';
Matrix.of(context).client.homeserver;
if (kIsWeb) launch(url); if (kIsWeb) launch(url);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(

View file

@ -372,7 +372,7 @@ class _ChatState extends State<_Chat> {
.client .client
.onPresence .onPresence
.stream .stream
.where((p) => p.sender == room.directChatMatrixID), .where((p) => p.senderId == room.directChatMatrixID),
builder: (context, snapshot) { builder: (context, snapshot) {
return ListTile( return ListTile(
leading: Avatar(room.avatar, room.displayname), leading: Avatar(room.avatar, room.displayname),
@ -557,7 +557,8 @@ class _ChatState extends State<_Chat> {
); );
} }
selectedEvents.sort( selectedEvents.sort(
(a, b) => a.time.compareTo(b.time), (a, b) => a.originServerTs
.compareTo(b.originServerTs),
); );
} }
}, },

View file

@ -1,4 +1,5 @@
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:famedlysdk/matrix_api.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart'; import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/chat_settings_popup_menu.dart'; import 'package:fluffychat/components/chat_settings_popup_menu.dart';
import 'package:fluffychat/components/content_banner.dart'; import 'package:fluffychat/components/content_banner.dart';
@ -61,28 +62,22 @@ class _ChatDetailsState extends State<ChatDetails> {
var newAliases = List<String>.from(aliases); var newAliases = List<String>.from(aliases);
newAliases.add(canonicalAlias); newAliases.add(canonicalAlias);
final response = await SimpleDialogs(context).tryRequestWithLoadingDialog( final response = await SimpleDialogs(context).tryRequestWithLoadingDialog(
widget.room.client.jsonRequest( widget.room.client.api.requestRoomAliasInformations(canonicalAlias),
type: HTTPType.GET,
action: '/client/r0/directory/room/$canonicalAlias',
),
); );
if (response == false) { if (response == false) {
final success = final success =
await SimpleDialogs(context).tryRequestWithLoadingDialog( await SimpleDialogs(context).tryRequestWithLoadingDialog(
widget.room.client.jsonRequest( widget.room.client.api
type: HTTPType.PUT, .createRoomAlias(canonicalAlias, widget.room.id),
action: '/client/r0/directory/room/$canonicalAlias',
data: {'room_id': widget.room.id}),
); );
if (success == false) return; if (success == false) return;
} }
} }
await SimpleDialogs(context).tryRequestWithLoadingDialog( await SimpleDialogs(context).tryRequestWithLoadingDialog(
widget.room.client.jsonRequest( widget.room.client.api
type: HTTPType.PUT, .sendState(widget.room.id, 'm.room.canonical_alias', {
action: 'alias': '#$s:$domain',
'/client/r0/rooms/${widget.room.id}/state/m.room.canonical_alias', }),
data: {'alias': '#$s:$domain'}),
); );
} }

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:famedlysdk/matrix_api.dart';
import 'package:fluffychat/components/dialogs/simple_dialogs.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/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';
@ -93,7 +94,7 @@ class _ChatListState extends State<ChatList> {
setState(() => loadingPublicRooms = true); setState(() => loadingPublicRooms = true);
final newPublicRoomsResponse = final newPublicRoomsResponse =
await SimpleDialogs(context).tryRequestWithErrorToast( await SimpleDialogs(context).tryRequestWithErrorToast(
Matrix.of(context).client.requestPublicRooms( Matrix.of(context).client.api.searchPublicRooms(
limit: 30, limit: 30,
includeAllNetworks: true, includeAllNetworks: true,
genericSearchTerm: searchController.text, genericSearchTerm: searchController.text,
@ -107,13 +108,12 @@ class _ChatListState extends State<ChatList> {
if (searchController.text.isNotEmpty && if (searchController.text.isNotEmpty &&
searchController.text.isValidMatrixId && searchController.text.isValidMatrixId &&
searchController.text.sigil == '#') { searchController.text.sigil == '#') {
publicRoomsResponse.publicRooms.add( publicRoomsResponse.chunk.add(
PublicRoomEntry( PublicRoom.fromJson({
aliases: [searchController.text], 'aliases': [searchController.text],
name: searchController.text, 'name': searchController.text,
roomId: searchController.text, 'room_id': searchController.text,
client: Matrix.of(context).client, }),
),
); );
} }
} }
@ -199,15 +199,9 @@ class _ChatListState extends State<ChatList> {
); );
if (status?.isEmpty ?? true) return; if (status?.isEmpty ?? true) return;
await SimpleDialogs(context).tryRequestWithLoadingDialog( await SimpleDialogs(context).tryRequestWithLoadingDialog(
Matrix.of(context).client.jsonRequest( Matrix.of(context).client.api.sendPresence(
type: HTTPType.PUT, Matrix.of(context).client.userID, PresenceType.online,
action: statusMsg: status),
'/client/r0/presence/${Matrix.of(context).client.userID}/status',
data: {
'presence': 'online',
'status_msg': status,
},
),
); );
} }
@ -412,8 +406,7 @@ class _ChatListState extends State<ChatList> {
); );
} }
final publicRoomsCount = final publicRoomsCount =
(publicRoomsResponse?.publicRooms?.length ?? (publicRoomsResponse?.chunk?.length ?? 0);
0);
final totalCount = final totalCount =
rooms.length + publicRoomsCount; rooms.length + publicRoomsCount;
return ListView.separated( return ListView.separated(
@ -469,7 +462,7 @@ class _ChatListState extends State<ChatList> {
rooms[i].id, rooms[i].id,
) )
: PublicRoomListItem(publicRoomsResponse : PublicRoomListItem(publicRoomsResponse
.publicRooms[i - rooms.length]); .chunk[i - rooms.length]);
}); });
} else { } else {
return Center( return Center(

View file

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:famedlysdk/matrix_api.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart'; import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/avatar.dart'; import 'package:fluffychat/components/avatar.dart';
import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart';
@ -23,7 +24,7 @@ class _InvitationSelectionState extends State<InvitationSelection> {
TextEditingController controller = TextEditingController(); TextEditingController controller = TextEditingController();
String currentSearchTerm; String currentSearchTerm;
bool loading = false; bool loading = false;
List<Map<String, dynamic>> foundProfiles = []; List<Profile> foundProfiles = [];
Timer coolDown; Timer coolDown;
Future<List<User>> getContacts(BuildContext context) async { Future<List<User>> getContacts(BuildContext context) async {
@ -84,32 +85,23 @@ class _InvitationSelectionState extends State<InvitationSelection> {
setState(() => loading = true); setState(() => loading = true);
final matrix = Matrix.of(context); final matrix = Matrix.of(context);
final response = await SimpleDialogs(context).tryRequestWithErrorToast( final response = await SimpleDialogs(context).tryRequestWithErrorToast(
matrix.client.jsonRequest( matrix.client.api.searchUser(text, limit: 10),
type: HTTPType.POST,
action: '/client/r0/user_directory/search',
data: {
'search_term': text,
'limit': 10,
}),
); );
setState(() => loading = false); setState(() => loading = false);
if (response == false || if (response == false || (response?.results == null)) return;
!(response is Map) ||
(response['results'] == null)) return;
setState(() { setState(() {
foundProfiles = List<Map<String, dynamic>>.from(response['results']); foundProfiles = List<Profile>.from(response.results);
if ('@$text'.isValidMatrixId && if ('@$text'.isValidMatrixId &&
foundProfiles foundProfiles.indexWhere((profile) => '@$text' == profile.userId) ==
.indexWhere((profile) => '@$text' == profile['user_id']) ==
-1) { -1) {
setState(() => foundProfiles = [ setState(() => foundProfiles = [
{'user_id': '@$text'} Profile.fromJson({'user_id': '@$text'}),
]); ]);
} }
foundProfiles.removeWhere((profile) => foundProfiles.removeWhere((profile) =>
widget.room widget.room
.getParticipants() .getParticipants()
.indexWhere((u) => u.id == profile['user_id']) != .indexWhere((u) => u.id == profile.userId) !=
-1); -1);
}); });
} }
@ -160,19 +152,15 @@ class _InvitationSelectionState extends State<InvitationSelection> {
itemCount: foundProfiles.length, itemCount: foundProfiles.length,
itemBuilder: (BuildContext context, int i) => ListTile( itemBuilder: (BuildContext context, int i) => ListTile(
leading: Avatar( leading: Avatar(
foundProfiles[i]['avatar_url'] == null foundProfiles[i].avatarUrl,
? null foundProfiles[i].displayname ?? foundProfiles[i].userId,
: Uri.parse(foundProfiles[i]['avatar_url']),
foundProfiles[i]['display_name'] ??
foundProfiles[i]['user_id'],
), ),
title: Text( title: Text(
foundProfiles[i]['display_name'] ?? foundProfiles[i].displayname ??
(foundProfiles[i]['user_id'] as String).localpart, foundProfiles[i].userId.localpart,
), ),
subtitle: Text(foundProfiles[i]['user_id']), subtitle: Text(foundProfiles[i].userId),
onTap: () => onTap: () => inviteAction(context, foundProfiles[i].userId),
inviteAction(context, foundProfiles[i]['user_id']),
), ),
) )
: FutureBuilder<List<User>>( : FutureBuilder<List<User>>(

View file

@ -91,7 +91,7 @@ class _LoginState extends State<Login> {
.getWellKnownInformationsByUserId(userId); .getWellKnownInformationsByUserId(userId);
final newDomain = wellKnownInformations.mHomeserver?.baseUrl; final newDomain = wellKnownInformations.mHomeserver?.baseUrl;
if ((newDomain?.isNotEmpty ?? false) && if ((newDomain?.isNotEmpty ?? false) &&
newDomain != Matrix.of(context).client.homeserver) { newDomain != Matrix.of(context).client.api.homeserver.toString()) {
await SimpleDialogs(context).tryRequestWithErrorToast( await SimpleDialogs(context).tryRequestWithErrorToast(
Matrix.of(context).client.checkServer(newDomain)); Matrix.of(context).client.checkServer(newDomain));
setState(() => usernameError = null); setState(() => usernameError = null);
@ -110,7 +110,9 @@ class _LoginState extends State<Login> {
title: Text( title: Text(
L10n.of(context).logInTo(Matrix.of(context) L10n.of(context).logInTo(Matrix.of(context)
.client .client
.api
.homeserver .homeserver
.toString()
.replaceFirst('https://', '')), .replaceFirst('https://', '')),
), ),
), ),

View file

@ -1,3 +1,4 @@
import 'package:famedlysdk/matrix_api.dart' as api;
import 'package:fluffychat/components/adaptive_page_layout.dart'; import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
@ -32,20 +33,17 @@ class _NewGroupState extends State<_NewGroup> {
void submitAction(BuildContext context) async { void submitAction(BuildContext context) async {
final matrix = Matrix.of(context); final matrix = Matrix.of(context);
var params = <String, dynamic>{};
if (publicGroup) {
params['preset'] = 'public_chat';
params['visibility'] = 'public';
if (controller.text.isNotEmpty) {
params['room_alias_name'] = controller.text;
}
} else {
params['preset'] = 'private_chat';
}
if (controller.text.isNotEmpty) params['name'] = controller.text;
final String roomID = final String roomID =
await SimpleDialogs(context).tryRequestWithLoadingDialog( await SimpleDialogs(context).tryRequestWithLoadingDialog(
matrix.client.createRoom(params: params), matrix.client.api.createRoom(
preset: publicGroup
? api.CreateRoomPreset.public_chat
: api.CreateRoomPreset.private_chat,
visibility: publicGroup ? api.Visibility.public : null,
roomAliasName:
publicGroup && controller.text.isNotEmpty ? controller.text : null,
name: controller.text.isNotEmpty ? controller.text : null,
),
); );
Navigator.of(context).pop(); Navigator.of(context).pop();
if (roomID != null) { if (roomID != null) {

View file

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:famedlysdk/matrix_api.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart'; import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/avatar.dart'; import 'package:fluffychat/components/avatar.dart';
import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart';
@ -34,14 +35,14 @@ class _NewPrivateChatState extends State<_NewPrivateChat> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
bool loading = false; bool loading = false;
String currentSearchTerm; String currentSearchTerm;
List<Map<String, dynamic>> foundProfiles = []; List<Profile> foundProfiles = [];
Timer coolDown; Timer coolDown;
Map<String, dynamic> get foundProfile => foundProfiles.firstWhere( Profile get foundProfile =>
(user) => user['user_id'] == '@$currentSearchTerm', foundProfiles.firstWhere((user) => user.userId == '@$currentSearchTerm',
orElse: () => null); orElse: () => null);
bool get correctMxId => bool get correctMxId =>
foundProfiles foundProfiles
.indexWhere((user) => user['user_id'] == '@$currentSearchTerm') != .indexWhere((user) => user.userId == '@$currentSearchTerm') !=
-1; -1;
void submitAction(BuildContext context) async { void submitAction(BuildContext context) async {
@ -89,20 +90,12 @@ class _NewPrivateChatState extends State<_NewPrivateChat> {
setState(() => loading = true); setState(() => loading = true);
final matrix = Matrix.of(context); final matrix = Matrix.of(context);
final response = await SimpleDialogs(context).tryRequestWithErrorToast( final response = await SimpleDialogs(context).tryRequestWithErrorToast(
matrix.client.jsonRequest( matrix.client.api.searchUser(text, limit: 10),
type: HTTPType.POST,
action: '/client/r0/user_directory/search',
data: {
'search_term': text,
'limit': 10,
}),
); );
setState(() => loading = false); setState(() => loading = false);
if (response == false || if (response == false || (response?.results?.isEmpty ?? true)) return;
!(response is Map) ||
(response['results']?.isEmpty ?? true)) return;
setState(() { setState(() {
foundProfiles = List<Map<String, dynamic>>.from(response['results']); foundProfiles = List<Profile>.from(response.results);
}); });
} }
@ -158,11 +151,8 @@ class _NewPrivateChatState extends State<_NewPrivateChat> {
? Padding( ? Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Avatar( child: Avatar(
foundProfile['avatar_url'] == null foundProfile.avatarUrl,
? null foundProfile.displayname ?? foundProfile.userId,
: Uri.parse(foundProfile['avatar_url']),
foundProfile['display_name'] ??
foundProfile['user_id'],
size: 12, size: 12,
), ),
) )
@ -184,24 +174,21 @@ class _NewPrivateChatState extends State<_NewPrivateChat> {
onTap: () { onTap: () {
setState(() { setState(() {
controller.text = currentSearchTerm = controller.text = currentSearchTerm =
foundProfile['user_id'].substring(1); foundProfile.userId.substring(1);
}); });
}, },
leading: Avatar( leading: Avatar(
foundProfile['avatar_url'] == null foundProfile.avatarUrl,
? null foundProfile.displayname ?? foundProfile.userId,
: Uri.parse(foundProfile['avatar_url']),
foundProfile['display_name'] ?? foundProfile['user_id'],
//size: 24, //size: 24,
), ),
title: Text( title: Text(
foundProfile['display_name'] ?? foundProfile.displayname ?? foundProfile.userId.localpart,
(foundProfile['user_id'] as String).localpart,
style: TextStyle(), style: TextStyle(),
maxLines: 1, maxLines: 1,
), ),
subtitle: Text( subtitle: Text(
foundProfile['user_id'], foundProfile.userId,
maxLines: 1, maxLines: 1,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,

View file

@ -25,36 +25,32 @@ class DevicesSettings extends StatefulWidget {
} }
class DevicesSettingsState extends State<DevicesSettings> { class DevicesSettingsState extends State<DevicesSettings> {
List<UserDevice> devices; List<Device> devices;
Future<bool> _loadUserDevices(BuildContext context) async { Future<bool> _loadUserDevices(BuildContext context) async {
if (devices != null) return true; if (devices != null) return true;
devices = await Matrix.of(context).client.requestUserDevices(); devices = await Matrix.of(context).client.api.requestDevices();
return true; return true;
} }
void reload() => setState(() => devices = null); void reload() => setState(() => devices = null);
void _removeDevicesAction( void _removeDevicesAction(BuildContext context, List<Device> devices) async {
BuildContext context, List<UserDevice> devices) async {
if (await SimpleDialogs(context).askConfirmation() == false) return; if (await SimpleDialogs(context).askConfirmation() == false) return;
var matrix = Matrix.of(context); var matrix = Matrix.of(context);
var deviceIds = <String>[]; var deviceIds = <String>[];
for (var userDevice in devices) { for (var userDevice in devices) {
deviceIds.add(userDevice.deviceId); deviceIds.add(userDevice.deviceId);
} }
final success = await SimpleDialogs(context)
.tryRequestWithLoadingDialog(matrix.client.deleteDevices(deviceIds),
onAdditionalAuth: (MatrixException exception) async {
final password = await SimpleDialogs(context).enterText( final password = await SimpleDialogs(context).enterText(
titleText: L10n.of(context).pleaseEnterYourPassword, titleText: L10n.of(context).pleaseEnterYourPassword,
labelText: L10n.of(context).pleaseEnterYourPassword, labelText: L10n.of(context).pleaseEnterYourPassword,
hintText: '******', hintText: '******',
password: true); password: true);
if (password == null) return; if (password == null) return;
await matrix.client.deleteDevices(deviceIds,
auth: matrix.getAuthByPassword(password, exception.session)); final success = await SimpleDialogs(context).tryRequestWithLoadingDialog(
return; matrix.client.api.deleteDevices(deviceIds,
}); auth: matrix.getAuthByPassword(password)));
if (success != false) { if (success != false) {
reload(); reload();
} }
@ -81,9 +77,9 @@ class DevicesSettingsState extends State<DevicesSettings> {
if (!snapshot.hasData || this.devices == null) { if (!snapshot.hasData || this.devices == null) {
return Center(child: CircularProgressIndicator()); return Center(child: CircularProgressIndicator());
} }
Function isOwnDevice = (UserDevice userDevice) => Function isOwnDevice = (Device userDevice) =>
userDevice.deviceId == Matrix.of(context).client.deviceID; userDevice.deviceId == Matrix.of(context).client.deviceID;
final devices = List<UserDevice>.from(this.devices); final devices = List<Device>.from(this.devices);
var thisDevice = devices.firstWhere(isOwnDevice, orElse: () => null); var thisDevice = devices.firstWhere(isOwnDevice, orElse: () => null);
devices.removeWhere(isOwnDevice); devices.removeWhere(isOwnDevice);
devices.sort((a, b) => b.lastSeenTs.compareTo(a.lastSeenTs)); devices.sort((a, b) => b.lastSeenTs.compareTo(a.lastSeenTs));
@ -134,7 +130,7 @@ class DevicesSettingsState extends State<DevicesSettings> {
} }
class UserDeviceListItem extends StatelessWidget { class UserDeviceListItem extends StatelessWidget {
final UserDevice userDevice; final Device userDevice;
final Function remove; final Function remove;
const UserDeviceListItem(this.userDevice, {this.remove, Key key}) const UserDeviceListItem(this.userDevice, {this.remove, Key key})

View file

@ -70,21 +70,16 @@ class _EmotesSettingsState extends State<EmotesSettings> {
content['short'][emote.emote] = emote.mxc; content['short'][emote.emote] = emote.mxc;
} }
debugPrint(content.toString()); debugPrint(content.toString());
var path = '';
if (widget.room != null) { if (widget.room != null) {
path = '/client/r0/rooms/${widget.room.id}/state/im.ponies.room_emotes/';
} else {
path =
'/client/r0/user/${client.userID}/account_data/im.ponies.user_emotes';
}
debugPrint(path);
await SimpleDialogs(context).tryRequestWithLoadingDialog( await SimpleDialogs(context).tryRequestWithLoadingDialog(
client.jsonRequest( client.api.sendState(widget.room.id, 'im.ponies.room_emotes', content),
type: HTTPType.PUT,
action: path,
data: content,
),
); );
} else {
await SimpleDialogs(context).tryRequestWithLoadingDialog(
client.api
.setAccountData(client.userID, 'im.ponies.user_emotes', content),
);
}
} }
bool get readonly => widget.room == null bool get readonly => widget.room == null
@ -378,11 +373,14 @@ class _EmoteImagePickerState extends State<_EmoteImagePicker> {
maxWidth: 128, maxWidth: 128,
maxHeight: 128); maxHeight: 128);
if (file == null) return; if (file == null) return;
final matrixFile =
MatrixFile(bytes: await file.readAsBytes(), path: file.path);
final uploadResp = final uploadResp =
await SimpleDialogs(context).tryRequestWithLoadingDialog( await SimpleDialogs(context).tryRequestWithLoadingDialog(
Matrix.of(context).client.upload( Matrix.of(context)
MatrixFile(bytes: await file.readAsBytes(), path: file.path), .client
), .api
.upload(matrixFile.bytes, matrixFile.path),
); );
setState(() { setState(() {
widget.controller.text = uploadResp; widget.controller.text = uploadResp;

View file

@ -49,7 +49,7 @@ class _SignUpState extends State<SignUp> {
usernameController.text.toLowerCase().replaceAll(' ', '-'); usernameController.text.toLowerCase().replaceAll(' ', '-');
try { try {
await matrix.client.usernameAvailable(preferredUsername); await matrix.client.api.usernameAvailable(preferredUsername);
} on MatrixException catch (exception) { } on MatrixException catch (exception) {
setState(() => usernameError = exception.errorMessage); setState(() => usernameError = exception.errorMessage);
return setState(() => loading = false); return setState(() => loading = false);
@ -73,7 +73,12 @@ class _SignUpState extends State<SignUp> {
elevation: 0, elevation: 0,
leading: loading ? Container() : null, leading: loading ? Container() : null,
title: Text( title: Text(
Matrix.of(context).client.homeserver.replaceFirst('https://', ''), Matrix.of(context)
.client
.api
.homeserver
.toString()
.replaceFirst('https://', ''),
), ),
), ),
body: ListView( body: ListView(

View file

@ -133,8 +133,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: "359e03496ad72f125ae275788621ac4f42d99d01" ref: "857775cf37804440717ce797e0ed63fd39066904"
resolved-ref: "359e03496ad72f125ae275788621ac4f42d99d01" resolved-ref: "857775cf37804440717ce797e0ed63fd39066904"
url: "https://gitlab.com/famedly/famedlysdk.git" url: "https://gitlab.com/famedly/famedlysdk.git"
source: git source: git
version: "0.0.1" version: "0.0.1"

View file

@ -27,7 +27,7 @@ dependencies:
famedlysdk: famedlysdk:
git: git:
url: https://gitlab.com/famedly/famedlysdk.git url: https://gitlab.com/famedly/famedlysdk.git
ref: 359e03496ad72f125ae275788621ac4f42d99d01 ref: 857775cf37804440717ce797e0ed63fd39066904
localstorage: ^3.0.1+4 localstorage: ^3.0.1+4
bubble: ^1.1.9+1 bubble: ^1.1.9+1