Merge branch 'krille/apl' into 'main'

refactor: Use APL

See merge request famedly/fluffychat!338
This commit is contained in:
Krille Fear 2021-01-16 11:46:38 +00:00
commit 4b0f9fc8de
40 changed files with 1012 additions and 1283 deletions

View File

@ -1,52 +0,0 @@
import 'package:flutter/material.dart';
enum FocusPage { FIRST, SECOND }
class AdaptivePageLayout extends StatelessWidget {
final Widget firstScaffold;
final Widget secondScaffold;
final FocusPage primaryPage;
final double minWidth;
static const double defaultMinWidth = 400;
static bool columnMode(BuildContext context) =>
MediaQuery.of(context).size.width > 2 * defaultMinWidth;
AdaptivePageLayout(
{this.firstScaffold,
this.secondScaffold,
this.primaryPage = FocusPage.FIRST,
this.minWidth = defaultMinWidth,
Key key})
: super(key: key);
@override
Widget build(BuildContext context) {
return OrientationBuilder(builder: (context, orientation) {
if (orientation == Orientation.portrait || !columnMode(context)) {
if (primaryPage == FocusPage.FIRST) {
return firstScaffold;
} else {
return secondScaffold;
}
}
return Row(
children: <Widget>[
Container(
width: minWidth,
child: firstScaffold,
),
Container(
width: 1,
color: Theme.of(context).secondaryHeaderColor, //Color(0xFFE8E8E8),
),
Expanded(
child: Container(
child: secondScaffold,
),
)
],
);
});
}
}

View File

@ -1,10 +1,8 @@
import 'dart:async'; import 'dart:async';
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:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/views/chat_details.dart';
import 'package:fluffychat/views/chat_list.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@ -95,9 +93,8 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
final success = await showFutureLoadingDialog( final success = await showFutureLoadingDialog(
context: context, future: () => widget.room.leave()); context: context, future: () => widget.room.leave());
if (success.error == null) { if (success.error == null) {
await Navigator.of(context).pushAndRemoveUntil( await AdaptivePageLayout.of(context)
AppRoute.defaultRoute(context, ChatListView()), .pushNamedAndRemoveAllOthers('/');
(Route r) => false);
} }
} }
break; break;
@ -117,12 +114,9 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
startCallAction(context); startCallAction(context);
break; break;
case 'details': case 'details':
await Navigator.of(context).push( await AdaptivePageLayout.of(context).pushNamedAndRemoveAllOthers(
AppRoute.defaultRoute( '/rooms/${widget.room.id}/details');
context,
ChatDetails(widget.room),
),
);
break; break;
} }
}, },

View File

@ -1,11 +1,6 @@
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:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/views/archive.dart';
import 'package:fluffychat/views/discover_view.dart';
import 'package:fluffychat/views/new_group.dart';
import 'package:fluffychat/views/new_private_chat.dart';
import 'package:fluffychat/views/settings.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -13,15 +8,9 @@ import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'matrix.dart'; import 'matrix.dart';
class DefaultDrawer extends StatelessWidget { class DefaultDrawer extends StatelessWidget {
void _drawerTapAction(BuildContext context, Widget view) { void _drawerTapAction(BuildContext context, String route) {
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.of(context).pushAndRemoveUntil( AdaptivePageLayout.of(context).pushNamedAndRemoveUntilIsFirst(route);
AppRoute.defaultRoute(
context,
view,
),
(r) => r.isFirst,
);
} }
void _setStatus(BuildContext context) async { void _setStatus(BuildContext context) async {
@ -64,12 +53,12 @@ class DefaultDrawer extends StatelessWidget {
ListTile( ListTile(
leading: Icon(Icons.people_outline), leading: Icon(Icons.people_outline),
title: Text(L10n.of(context).createNewGroup), title: Text(L10n.of(context).createNewGroup),
onTap: () => _drawerTapAction(context, NewGroupView()), onTap: () => _drawerTapAction(context, '/newgroup'),
), ),
ListTile( ListTile(
leading: Icon(Icons.person_add_outlined), leading: Icon(Icons.person_add_outlined),
title: Text(L10n.of(context).newPrivateChat), title: Text(L10n.of(context).newPrivateChat),
onTap: () => _drawerTapAction(context, NewPrivateChatView()), onTap: () => _drawerTapAction(context, '/newprivatechat'),
), ),
Divider(height: 1), Divider(height: 1),
ListTile( ListTile(
@ -77,7 +66,7 @@ class DefaultDrawer extends StatelessWidget {
title: Text(L10n.of(context).archive), title: Text(L10n.of(context).archive),
onTap: () => _drawerTapAction( onTap: () => _drawerTapAction(
context, context,
Archive(), '/archive',
), ),
), ),
ListTile( ListTile(
@ -85,7 +74,7 @@ class DefaultDrawer extends StatelessWidget {
title: Text(L10n.of(context).discoverGroups), title: Text(L10n.of(context).discoverGroups),
onTap: () => _drawerTapAction( onTap: () => _drawerTapAction(
context, context,
DiscoverView(), '/discover',
), ),
), ),
Divider(height: 1), Divider(height: 1),
@ -94,7 +83,7 @@ class DefaultDrawer extends StatelessWidget {
title: Text(L10n.of(context).settings), title: Text(L10n.of(context).settings),
onTap: () => _drawerTapAction( onTap: () => _drawerTapAction(
context, context,
SettingsView(), '/settings',
), ),
), ),
], ],

View File

@ -1,10 +1,9 @@
import 'dart:async'; import 'dart:async';
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:flushbar/flushbar_helper.dart'; import 'package:flushbar/flushbar_helper.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/views/chat_encryption_settings.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -23,12 +22,8 @@ class _EncryptionButtonState extends State<EncryptionButton> {
void _enableEncryptionAction() async { void _enableEncryptionAction() async {
if (widget.room.encrypted) { if (widget.room.encrypted) {
await Navigator.of(context).push( await AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .pushNamed('/rooms/${widget.room.id}/encryption');
context,
ChatEncryptionSettingsView(widget.room.id),
),
);
return; return;
} }
if (!widget.room.client.encryptionEnabled) { if (!widget.room.client.encryptionEnabled) {

View File

@ -1,19 +1,17 @@
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:circular_check_box/circular_check_box.dart'; import 'package:circular_check_box/circular_check_box.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/utils/event_extension.dart'; import 'package:fluffychat/utils/event_extension.dart';
import 'package:fluffychat/utils/matrix_locals.dart'; import 'package:fluffychat/utils/matrix_locals.dart';
import 'package:fluffychat/utils/room_status_extension.dart'; import 'package:fluffychat/utils/room_status_extension.dart';
import 'package:fluffychat/views/chat.dart';
import 'package:flushbar/flushbar_helper.dart'; import 'package:flushbar/flushbar_helper.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:pedantic/pedantic.dart'; import 'package:pedantic/pedantic.dart';
import '../../utils/app_route.dart';
import '../../utils/date_time_extension.dart'; import '../../utils/date_time_extension.dart';
import '../../views/chat.dart';
import '../avatar.dart'; import '../avatar.dart';
import '../dialogs/send_file_dialog.dart'; import '../dialogs/send_file_dialog.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
@ -102,11 +100,8 @@ class ChatListItem extends StatelessWidget {
} }
Matrix.of(context).shareContent = null; Matrix.of(context).shareContent = null;
} }
await Navigator.pushAndRemoveUntil( await AdaptivePageLayout.of(context)
context, .pushNamedAndRemoveUntilIsFirst('/rooms/${room.id}');
AppRoute.defaultRoute(context, ChatView(room.id)),
(r) => r.isFirst,
);
} }
} }
} }

View File

@ -1,12 +1,12 @@
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.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';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/utils/date_time_extension.dart'; import 'package:fluffychat/utils/date_time_extension.dart';
import 'package:fluffychat/utils/event_extension.dart'; import 'package:fluffychat/utils/event_extension.dart';
import 'package:fluffychat/utils/string_color.dart'; import 'package:fluffychat/utils/string_color.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../adaptive_page_layout.dart';
import '../avatar.dart'; import '../avatar.dart';
import '../matrix.dart'; import '../matrix.dart';
import '../message_reactions.dart'; import '../message_reactions.dart';
@ -88,8 +88,7 @@ class Message extends StatelessWidget {
color: color, color: color,
borderRadius: BorderRadius.circular(radius), borderRadius: BorderRadius.circular(radius),
), ),
constraints: constraints: BoxConstraints(maxWidth: FluffyThemes.columnWidth),
BoxConstraints(maxWidth: AdaptivePageLayout.defaultMinWidth),
child: Stack( child: Stack(
children: <Widget>[ children: <Widget>[
Column( Column(

View File

@ -1,10 +1,9 @@
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../../utils/app_route.dart';
import '../../views/chat.dart';
import '../avatar.dart'; import '../avatar.dart';
import '../matrix.dart'; import '../matrix.dart';
@ -19,12 +18,8 @@ class PublicRoomListItem extends StatelessWidget {
future: () => _joinRoomAndWait(context), future: () => _joinRoomAndWait(context),
); );
if (success.error == null) { if (success.error == null) {
await Navigator.of(context).push( await AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .pushNamed('/rooms/${success.result}');
context,
ChatView(success.result),
),
);
} }
} }

View File

@ -3,14 +3,13 @@ import 'dart:io';
import 'dart:convert'; import 'dart:convert';
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:famedlysdk/encryption.dart'; import 'package:famedlysdk/encryption.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/utils/firebase_controller.dart'; 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/views/settings_3pid.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';
@ -38,7 +37,16 @@ class Matrix extends StatefulWidget {
final Widget child; final Widget child;
Matrix({this.child, Key key}) : super(key: key); final GlobalKey<AdaptivePageLayoutState> apl;
final BuildContext context;
Matrix({
this.child,
@required this.apl,
@required this.context,
Key key,
}) : super(key: key);
@override @override
MatrixState createState() => MatrixState(); MatrixState createState() => MatrixState();
@ -52,7 +60,7 @@ class MatrixState extends State<Matrix> {
Client client; Client client;
Store store = Store(); Store store = Store();
@override @override
BuildContext context; BuildContext get context => widget.context;
Map<String, dynamic> get shareContent => _shareContent; Map<String, dynamic> get shareContent => _shareContent;
set shareContent(Map<String, dynamic> content) { set shareContent(Map<String, dynamic> content) {
@ -76,29 +84,16 @@ class MatrixState extends State<Matrix> {
} }
void _initWithStore() async { void _initWithStore() async {
var initLoginState = client.onLoginStateChanged.stream.first;
try { try {
client.init(); client.init();
final firstLoginState = await initLoginState;
if (firstLoginState == LoginState.logged) {
if (PlatformInfos.isMobile) {
await FirebaseController.setupFirebase(
this,
clientName,
);
}
}
final storeItem = await store.getItem(SettingKeys.showNoPid); final storeItem = await store.getItem(SettingKeys.showNoPid);
final configOptionMissing = storeItem == null || storeItem.isEmpty; final configOptionMissing = storeItem == null || storeItem.isEmpty;
if (configOptionMissing || (!configOptionMissing && storeItem == '1')) { if (configOptionMissing || (!configOptionMissing && storeItem == '1')) {
if (configOptionMissing) { if (configOptionMissing) {
await store.setItem(SettingKeys.showNoPid, '0'); await store.setItem(SettingKeys.showNoPid, '0');
} }
await Matrix.of(context) await client.requestThirdPartyIdentifiers().then((l) {
.client
.requestThirdPartyIdentifiers()
.then((l) {
if (l.isEmpty) { if (l.isEmpty) {
Flushbar( Flushbar(
title: L10n.of(context).warning, title: L10n.of(context).warning,
@ -110,12 +105,8 @@ class MatrixState extends State<Matrix> {
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
), ),
child: Text(L10n.of(context).edit), child: Text(L10n.of(context).edit),
onPressed: () => Navigator.of(context).push( onPressed: () =>
AppRoute.defaultRoute( AdaptivePageLayout.of(context).pushNamed('/settings/3pid'),
context,
Settings3PidView(),
),
),
), ),
flushbarStyle: FlushbarStyle.FLOATING, flushbarStyle: FlushbarStyle.FLOATING,
).show(context); ).show(context);
@ -133,6 +124,7 @@ class MatrixState extends State<Matrix> {
StreamSubscription onKeyVerificationRequestSub; StreamSubscription onKeyVerificationRequestSub;
StreamSubscription onJitsiCallSub; StreamSubscription onJitsiCallSub;
StreamSubscription onNotification; StreamSubscription onNotification;
StreamSubscription<LoginState> onLoginStateChanged;
StreamSubscription<UiaRequest> onUiaRequest; StreamSubscription<UiaRequest> onUiaRequest;
StreamSubscription<html.Event> onFocusSub; StreamSubscription<html.Event> onFocusSub;
StreamSubscription<html.Event> onBlurSub; StreamSubscription<html.Event> onBlurSub;
@ -301,6 +293,8 @@ class MatrixState extends State<Matrix> {
} }
} }
LoginState loginState;
void initMatrix() { void initMatrix() {
clientName = clientName =
'${AppConfig.applicationName} ${kIsWeb ? 'Web' : Platform.operatingSystem}'; '${AppConfig.applicationName} ${kIsWeb ? 'Web' : Platform.operatingSystem}';
@ -380,6 +374,19 @@ class MatrixState extends State<Matrix> {
onFocusSub = html.window.onFocus.listen((_) => webHasFocus = true); onFocusSub = html.window.onFocus.listen((_) => webHasFocus = true);
onBlurSub = html.window.onBlur.listen((_) => webHasFocus = false); onBlurSub = html.window.onBlur.listen((_) => webHasFocus = false);
} }
onLoginStateChanged ??= client.onLoginStateChanged.stream.listen((state) {
if (loginState != state) {
loginState = state;
widget.apl.currentState.pushNamedAndRemoveAllOthers('/');
if (loginState == LoginState.logged) {
FirebaseController.context = context;
FirebaseController.setupFirebase(
this,
clientName,
).catchError(SentryController.captureException);
}
}
});
onUiaRequest ??= client.onUiaRequest.stream.listen(_onUiaRequest); onUiaRequest ??= client.onUiaRequest.stream.listen(_onUiaRequest);
if (kIsWeb || Platform.isLinux) { if (kIsWeb || Platform.isLinux) {
client.onSync.stream.first.then((s) { client.onSync.stream.first.then((s) {

View File

@ -1,12 +1,11 @@
import 'dart:math'; import 'dart:math';
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:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/dialogs/permission_slider_dialog.dart'; import 'package:fluffychat/components/dialogs/permission_slider_dialog.dart';
import 'package:fluffychat/utils/app_route.dart'; import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/utils/fluffy_share.dart';
import 'package:fluffychat/views/chat.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'content_banner.dart'; import 'content_banner.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -15,7 +14,6 @@ import '../utils/presence_extension.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'matrix.dart'; import 'matrix.dart';
import 'dialogs/key_verification_dialog.dart'; import 'dialogs/key_verification_dialog.dart';
import '../utils/app_route.dart';
class UserBottomSheet extends StatelessWidget { class UserBottomSheet extends StatelessWidget {
final User user; final User user;
@ -76,12 +74,8 @@ class UserBottomSheet extends StatelessWidget {
break; break;
case 'message': case 'message':
final roomId = await user.startDirectChat(); final roomId = await user.startDirectChat();
await Navigator.of(context).pushAndRemoveUntil( await AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .pushNamedAndRemoveUntilIsFirst('/rooms/${roomId}');
context,
ChatView(roomId),
),
(Route r) => r.isFirst);
break; break;
} }
} }
@ -161,8 +155,8 @@ class UserBottomSheet extends StatelessWidget {
} }
return Center( return Center(
child: Container( child: Container(
width: min(MediaQuery.of(context).size.width, width: min(
AdaptivePageLayout.defaultMinWidth * 1.5), MediaQuery.of(context).size.width, FluffyThemes.columnWidth * 1.5),
child: SafeArea( child: SafeArea(
child: Material( child: Material(
elevation: 4, elevation: 4,

228
lib/config/routes.dart Normal file
View File

@ -0,0 +1,228 @@
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/views/archive.dart';
import 'package:fluffychat/views/auth_web_view.dart';
import 'package:fluffychat/views/chat.dart';
import 'package:fluffychat/views/chat_details.dart';
import 'package:fluffychat/views/chat_encryption_settings.dart';
import 'package:fluffychat/views/chat_list.dart';
import 'package:fluffychat/views/chat_permissions_settings.dart';
import 'package:fluffychat/views/discover_view.dart';
import 'package:fluffychat/views/empty_page.dart';
import 'package:fluffychat/views/homeserver_picker.dart';
import 'package:fluffychat/views/invitation_selection.dart';
import 'package:fluffychat/views/loading_view.dart';
import 'package:fluffychat/views/log_view.dart';
import 'package:fluffychat/views/login.dart';
import 'package:fluffychat/views/new_group.dart';
import 'package:fluffychat/views/new_private_chat.dart';
import 'package:fluffychat/views/settings.dart';
import 'package:fluffychat/views/settings_3pid.dart';
import 'package:fluffychat/views/settings_devices.dart';
import 'package:fluffychat/views/settings_emotes.dart';
import 'package:fluffychat/views/settings_ignore_list.dart';
import 'package:fluffychat/views/settings_multiple_emotes.dart';
import 'package:fluffychat/views/settings_notifications.dart';
import 'package:fluffychat/views/settings_style.dart';
import 'package:fluffychat/views/sign_up.dart';
import 'package:fluffychat/views/sign_up_password.dart';
import 'package:flutter/material.dart';
class FluffyRoutes {
final BuildContext context;
const FluffyRoutes(this.context);
ViewData onGenerateRoute(RouteSettings settings) {
final parts = settings.name.split('/');
Logs().v(settings.name);
// Routes if the app is loading
if (Matrix.of(context).loginState == null) {
return ViewData(mainView: (_) => LoadingView());
// Routes if user is NOT logged in
} else if (Matrix.of(context).loginState == LoginState.loggedOut) {
switch (parts[1]) {
case '':
return ViewData(mainView: (_) => HomeserverPicker());
case 'login':
return ViewData(mainView: (_) => Login());
case 'signup':
if (parts.length == 5 && parts[2] == 'password') {
return ViewData(
mainView: (_) => SignUpPassword(
parts[3],
displayname: parts[4],
avatar: settings.arguments,
),
);
}
return ViewData(mainView: (_) => SignUp());
case 'authwebview':
if (parts.length == 4) {
return ViewData(
mainView: (_) => AuthWebView(
parts[2],
Uri.decodeComponent(parts[3]),
settings.arguments,
),
);
}
}
}
// Routes IF user is logged in
else {
switch (parts[1]) {
case '':
return ViewData(
mainView: (_) => ChatList(),
emptyView: (_) => EmptyPage(),
);
case 'rooms':
if (parts.length == 3) {
return ViewData(
leftView: (_) => ChatList(),
mainView: (_) => Chat(parts[2]),
);
} else if (parts.length == 4) {
final roomId = parts[2];
final action = parts[3];
switch (action) {
case 'details':
return ViewData(
leftView: (_) => ChatList(),
mainView: (_) => Chat(parts[2]),
rightView: (_) => ChatDetails(roomId),
);
case 'encryption':
return ViewData(
leftView: (_) => ChatList(),
mainView: (_) => Chat(parts[2]),
rightView: (_) => ChatEncryptionSettings(roomId),
);
case 'permissions':
return ViewData(
leftView: (_) => ChatList(),
mainView: (_) => Chat(parts[2]),
rightView: (_) => ChatPermissionsSettings(roomId),
);
case 'invite':
return ViewData(
leftView: (_) => ChatList(),
mainView: (_) => Chat(parts[2]),
rightView: (_) => InvitationSelection(roomId),
);
case 'emotes':
return ViewData(
leftView: (_) => ChatList(),
mainView: (_) => Chat(parts[2]),
rightView: (_) => MultipleEmotesSettings(roomId),
);
}
}
return ViewData(
mainView: (_) => ChatList(),
emptyView: (_) => EmptyPage(),
);
case 'archive':
return ViewData(
mainView: (_) => Archive(),
emptyView: (_) => Chat(parts[2]),
);
case 'discover':
return ViewData(
mainView: (_) =>
DiscoverPage(alias: parts.length == 3 ? parts[2] : null),
emptyView: (_) => EmptyPage(),
);
case 'logs':
return ViewData(
mainView: (_) => LogViewer(),
);
case 'newgroup':
return ViewData(
leftView: (_) => ChatList(),
mainView: (_) => NewGroup(),
);
case 'newprivatechat':
return ViewData(
leftView: (_) => ChatList(),
mainView: (_) => NewPrivateChat(),
);
case 'settings':
if (parts.length == 3) {
final action = parts[2];
switch (action) {
case '3pid':
return ViewData(
leftView: (_) => Settings(),
mainView: (_) => Settings3Pid(),
);
case 'devices':
return ViewData(
leftView: (_) => Settings(),
mainView: (_) => DevicesSettings(),
);
case 'emotes':
return ViewData(
leftView: (_) => Settings(),
mainView: (_) => EmotesSettings(room: settings.arguments),
);
case 'ignore':
return ViewData(
leftView: (_) => Settings(),
mainView: (_) => SettingsIgnoreList(),
);
case 'notifications':
return ViewData(
leftView: (_) => Settings(),
mainView: (_) => SettingsNotifications(),
);
case 'style':
return ViewData(
leftView: (_) => Settings(),
mainView: (_) => SettingsStyle(),
);
}
}
return ViewData(
mainView: (_) => Settings(),
emptyView: (_) => EmptyPage(),
);
}
}
// If route cant be found:
return ViewData(
mainView: (_) => Center(
child: Text('Route "${settings.name}" not found...'),
),
);
}
}
class SettingsDevices {}
class FadeRoute extends PageRouteBuilder {
final Widget page;
FadeRoute({this.page})
: super(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) =>
page,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) =>
FadeTransition(
opacity: animation,
child: child,
),
);
}

View File

@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
abstract class FluffyThemes { abstract class FluffyThemes {
static const double columnWidth = 360.0;
static ThemeData light = ThemeData( static ThemeData light = ThemeData(
primaryColorDark: Colors.white, primaryColorDark: Colors.white,
primaryColorLight: Color(0xff121212), primaryColorLight: Color(0xff121212),

View File

@ -2,22 +2,19 @@
import 'dart:async'; import 'dart:async';
import 'package:adaptive_theme/adaptive_theme.dart'; import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:fluffychat/config/routes.dart';
import 'package:fluffychat/utils/sentry_controller.dart'; import 'package:fluffychat/utils/sentry_controller.dart';
import 'package:fluffychat/views/homeserver_picker.dart'; import 'package:flutter/cupertino.dart';
import 'package:flushbar/flushbar_helper.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:universal_html/prefer_universal/html.dart' as html; import 'package:universal_html/prefer_universal/html.dart' as html;
import 'components/matrix.dart'; import 'components/matrix.dart';
import 'config/themes.dart'; import 'config/themes.dart';
import 'utils/localized_exception_extension.dart';
import 'app_config.dart'; import 'app_config.dart';
import 'views/chat_list.dart';
void main() async { void main() async {
SystemChrome.setSystemUIOverlayStyle( SystemChrome.setSystemUIOverlayStyle(
@ -31,11 +28,11 @@ void main() async {
} }
class App extends StatelessWidget { class App extends StatelessWidget {
final GlobalKey<AdaptivePageLayoutState> _apl =
GlobalKey<AdaptivePageLayoutState>();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Matrix( return AdaptiveTheme(
child: Builder(
builder: (BuildContext context) => AdaptiveTheme(
light: FluffyThemes.light, light: FluffyThemes.light,
dark: FluffyThemes.dark, dark: FluffyThemes.dark,
initial: AdaptiveThemeMode.system, initial: AdaptiveThemeMode.system,
@ -48,34 +45,21 @@ class App extends StatelessWidget {
locale: kIsWeb locale: kIsWeb
? Locale(html.window.navigator.language.split('-').first) ? Locale(html.window.navigator.language.split('-').first)
: null, : null,
home: FutureBuilder<LoginState>( home: Builder(
future: builder: (context) => Matrix(
Matrix.of(context).client.onLoginStateChanged.stream.first, context: context,
builder: (context, snapshot) { apl: _apl,
LoadingDialog.defaultTitle = L10n.of(context).loadingPleaseWait; child: Builder(
LoadingDialog.defaultBackLabel = L10n.of(context).close; builder: (context) => AdaptivePageLayout(
LoadingDialog.defaultOnError = key: _apl,
(Object e) => e.toLocalizedString(context); onGenerateRoute: FluffyRoutes(context).onGenerateRoute,
if (snapshot.hasError) { dividerColor: Theme.of(context).dividerColor,
WidgetsBinding.instance columnWidth: FluffyThemes.columnWidth,
.addPostFrameCallback((_) => FlushbarHelper.createError( routeBuilder: (builder, settings) =>
title: L10n.of(context).oopsSomethingWentWrong, _apl.currentState.columnMode(context)
message: snapshot.error.toString(), ? FadeRoute(page: builder(context))
).show(context)); : CupertinoPageRoute(builder: builder),
return HomeserverPicker();
}
if (!snapshot.hasData) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
), ),
);
}
if (Matrix.of(context).client.isLogged()) {
return ChatListView();
}
return HomeserverPicker();
},
), ),
), ),
), ),

View File

@ -1,10 +1,11 @@
import 'package:fluffychat/components/adaptive_page_layout.dart'; import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class AppRoute extends PageRouteBuilder { class AppRoute extends PageRouteBuilder {
static Route defaultRoute(BuildContext context, Widget page) { static Route defaultRoute(BuildContext context, Widget page) {
return context != null && !AdaptivePageLayout.columnMode(context) return context != null &&
!AdaptivePageLayout.of(context).columnMode(context)
? CupertinoPageRoute( ? CupertinoPageRoute(
builder: (BuildContext context) => page, builder: (BuildContext context) => page,
) )

View File

@ -7,8 +7,6 @@ import 'package:flushbar/flushbar_helper.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/views/chat.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -112,12 +110,8 @@ abstract class FirebaseController {
roomId = (message['data'] ?? message)['room_id']; roomId = (message['data'] ?? message)['room_id'];
} }
if (roomId?.isEmpty ?? true) throw ('Bad roomId'); if (roomId?.isEmpty ?? true) throw ('Bad roomId');
await Navigator.of(context).pushAndRemoveUntil( await matrix.widget.apl.currentState
AppRoute.defaultRoute( .pushNamedAndRemoveUntilIsFirst('/rooms/${roomId}');
context,
ChatView(roomId),
),
(r) => r.isFirst);
} catch (_) { } catch (_) {
await FlushbarHelper.createError(message: 'Failed to open chat...') await FlushbarHelper.createError(message: 'Failed to open chat...')
.show(context); .show(context);

View File

@ -1,11 +1,9 @@
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:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/app_config.dart'; import 'package:fluffychat/app_config.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/views/chat.dart';
import 'package:fluffychat/views/discover_view.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@ -74,12 +72,8 @@ class UrlLauncher {
} }
if (room != null) { if (room != null) {
// we have the room, so....just open it! // we have the room, so....just open it!
await Navigator.pushAndRemoveUntil( await AdaptivePageLayout.of(context)
context, .pushNamedAndRemoveUntilIsFirst('/rooms/${room.id}/$event');
AppRoute.defaultRoute(
context, ChatView(room.id, scrollToEventId: event)),
(r) => r.isFirst,
);
return; return;
} }
if (roomIdOrAlias.sigil == '!') { if (roomIdOrAlias.sigil == '!') {
@ -101,21 +95,12 @@ class UrlLauncher {
await showFutureLoadingDialog( await showFutureLoadingDialog(
context: context, context: context,
future: () => Future.delayed(const Duration(seconds: 2))); future: () => Future.delayed(const Duration(seconds: 2)));
await Navigator.pushAndRemoveUntil( await AdaptivePageLayout.of(context).pushNamedAndRemoveUntilIsFirst(
context, '/rooms/${response.result}/$event');
AppRoute.defaultRoute(
context, ChatView(response.result, scrollToEventId: event)),
(r) => r.isFirst,
);
} }
} else { } else {
await Navigator.of(context).pushAndRemoveUntil( await AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .pushNamedAndRemoveUntilIsFirst('/discover/${roomIdOrAlias}');
context,
DiscoverView(alias: roomIdOrAlias),
),
(r) => r.isFirst,
);
} }
} else if (identityParts.primaryIdentifier.sigil == '@') { } else if (identityParts.primaryIdentifier.sigil == '@') {
final user = User( final user = User(
@ -124,11 +109,9 @@ class UrlLauncher {
); );
var roomId = matrix.client.getDirectChatFromUserId(user.id); var roomId = matrix.client.getDirectChatFromUserId(user.id);
if (roomId != null) { if (roomId != null) {
await Navigator.pushAndRemoveUntil( await AdaptivePageLayout.of(context)
context, .pushNamedAndRemoveUntilIsFirst('/rooms/${roomId}');
AppRoute.defaultRoute(context, ChatView(roomId)),
(r) => r.isFirst,
);
return; return;
} }
@ -142,14 +125,10 @@ class UrlLauncher {
future: () => user.startDirectChat(), future: () => user.startDirectChat(),
)) ))
.result; .result;
Navigator.of(context).pop();
if (roomId != null) { if (roomId != null) {
await Navigator.pushAndRemoveUntil( await AdaptivePageLayout.of(context)
context, .pushNamedAndRemoveUntilIsFirst('/rooms/${roomId}');
AppRoute.defaultRoute(context, ChatView(roomId)),
(r) => r.isFirst,
);
} }
} }
} }

View File

@ -1,5 +1,4 @@
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/list_items/chat_list_item.dart'; import 'package:fluffychat/components/list_items/chat_list_item.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -35,8 +34,7 @@ class _ArchiveState extends State<Archive> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AdaptivePageLayout( return Scaffold(
firstScaffold: Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(L10n.of(context).archive), title: Text(L10n.of(context).archive),
elevation: _scrolledToTop ? 0 : null, elevation: _scrolledToTop ? 0 : null,
@ -58,13 +56,6 @@ class _ArchiveState extends State<Archive> {
} }
}, },
), ),
),
secondScaffold: Scaffold(
body: Center(
child: Image.asset('assets/logo.png', width: 100, height: 100),
),
),
primaryPage: FocusPage.FIRST,
); );
} }
} }

View File

@ -1,3 +1,4 @@
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -23,7 +24,7 @@ class AuthWebView extends StatelessWidget {
leading: IconButton( leading: IconButton(
icon: Icon(Icons.close), icon: Icon(Icons.close),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); AdaptivePageLayout.of(context).pop();
onAuthDone(); onAuthDone();
}, },
), ),

View File

@ -3,14 +3,15 @@ import 'dart:io';
import 'dart:math'; import 'dart:math';
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:emoji_picker/emoji_picker.dart'; import 'package:emoji_picker/emoji_picker.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:file_picker_cross/file_picker_cross.dart'; import 'package:file_picker_cross/file_picker_cross.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/chat_settings_popup_menu.dart'; import 'package:fluffychat/components/chat_settings_popup_menu.dart';
import 'package:fluffychat/components/connection_status_header.dart'; import 'package:fluffychat/components/connection_status_header.dart';
import 'package:fluffychat/components/dialogs/recording_dialog.dart'; import 'package:fluffychat/components/dialogs/recording_dialog.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:flushbar/flushbar_helper.dart'; import 'package:flushbar/flushbar_helper.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/encryption_button.dart'; import 'package:fluffychat/components/encryption_button.dart';
@ -19,7 +20,6 @@ import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/components/reply_content.dart'; import 'package:fluffychat/components/reply_content.dart';
import 'package:fluffychat/components/user_bottom_sheet.dart'; import 'package:fluffychat/components/user_bottom_sheet.dart';
import 'package:fluffychat/config/app_emojis.dart'; import 'package:fluffychat/config/app_emojis.dart';
import 'package:fluffychat/utils/app_route.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/room_status_extension.dart'; import 'package:fluffychat/utils/room_status_extension.dart';
@ -38,39 +38,19 @@ import '../components/dialogs/send_file_dialog.dart';
import '../components/input_bar.dart'; import '../components/input_bar.dart';
import '../utils/filtered_timeline_extension.dart'; import '../utils/filtered_timeline_extension.dart';
import '../utils/matrix_file_extension.dart'; import '../utils/matrix_file_extension.dart';
import 'chat_details.dart';
import 'chat_list.dart';
class ChatView extends StatelessWidget { class Chat extends StatefulWidget {
final String id; final String id;
final String scrollToEventId; final String scrollToEventId;
const ChatView(this.id, {Key key, this.scrollToEventId}) : super(key: key); Chat(this.id, {Key key, this.scrollToEventId})
: super(key: key ?? Key('chatroom-$id'));
@override
Widget build(BuildContext context) {
// TODO: implement build
return AdaptivePageLayout(
primaryPage: FocusPage.SECOND,
firstScaffold: ChatList(
activeChat: id,
),
secondScaffold: _Chat(id, scrollToEventId: scrollToEventId),
);
}
}
class _Chat extends StatefulWidget {
final String id;
final String scrollToEventId;
const _Chat(this.id, {Key key, this.scrollToEventId}) : super(key: key);
@override @override
_ChatState createState() => _ChatState(); _ChatState createState() => _ChatState();
} }
class _ChatState extends State<_Chat> { class _ChatState extends State<Chat> {
Room room; Room room;
Timeline timeline; Timeline timeline;
@ -343,7 +323,7 @@ class _ChatState extends State<_Chat> {
}; };
} }
setState(() => selectedEvents.clear()); setState(() => selectedEvents.clear());
Navigator.of(context).popUntil((r) => r.isFirst); AdaptivePageLayout.of(context).popUntilIsFirst();
} }
void sendAgainAction(Timeline timeline) { void sendAgainAction(Timeline timeline) {
@ -509,12 +489,8 @@ class _ChatState extends State<_Chat> {
'${room.directChatMatrixID} ', '${room.directChatMatrixID} ',
), ),
) )
: () => Navigator.of(context).push( : () => AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .pushNamed('/rooms/${room.id}/details'),
context,
ChatDetails(room),
),
),
title: Text( title: Text(
room.getLocalizedDisplayname( room.getLocalizedDisplayname(
MatrixLocals(L10n.of(context))), MatrixLocals(L10n.of(context))),
@ -643,8 +619,7 @@ class _ChatState extends State<_Chat> {
horizontal: max( horizontal: max(
0, 0,
(MediaQuery.of(context).size.width - (MediaQuery.of(context).size.width -
AdaptivePageLayout.defaultMinWidth * FluffyThemes.columnWidth * 3.5) /
3.5) /
2), 2),
), ),
reverse: true, reverse: true,

View File

@ -1,40 +1,36 @@
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:fluffychat/app_config.dart'; import 'package:fluffychat/app_config.dart';
import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/utils/fluffy_share.dart';
import 'package:fluffychat/views/chat_permissions_settings.dart';
import 'package:flushbar/flushbar_helper.dart'; import 'package:flushbar/flushbar_helper.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:file_picker_cross/file_picker_cross.dart'; import 'package:file_picker_cross/file_picker_cross.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';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/list_items/participant_list_item.dart'; import 'package:fluffychat/components/list_items/participant_list_item.dart';
import 'package:fluffychat/utils/app_route.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/views/chat_list.dart';
import 'package:fluffychat/views/invitation_selection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:matrix_link_text/link_text.dart'; import 'package:matrix_link_text/link_text.dart';
import './settings_emotes.dart';
import './settings_multiple_emotes.dart';
import '../utils/url_launcher.dart'; import '../utils/url_launcher.dart';
class ChatDetails extends StatefulWidget { class ChatDetails extends StatefulWidget {
final Room room; final String roomId;
const ChatDetails(this.room); const ChatDetails(this.roomId);
@override @override
_ChatDetailsState createState() => _ChatDetailsState(); _ChatDetailsState createState() => _ChatDetailsState();
} }
class _ChatDetailsState extends State<ChatDetails> { class _ChatDetailsState extends State<ChatDetails> {
Room room;
List<User> members; List<User> members;
void setDisplaynameAction(BuildContext context) async { void setDisplaynameAction(BuildContext context) async {
final input = await showTextInputDialog( final input = await showTextInputDialog(
@ -42,7 +38,7 @@ class _ChatDetailsState extends State<ChatDetails> {
title: L10n.of(context).changeTheNameOfTheGroup, title: L10n.of(context).changeTheNameOfTheGroup,
textFields: [ textFields: [
DialogTextField( DialogTextField(
initialText: widget.room.getLocalizedDisplayname( initialText: room.getLocalizedDisplayname(
MatrixLocals( MatrixLocals(
L10n.of(context), L10n.of(context),
), ),
@ -53,7 +49,7 @@ class _ChatDetailsState extends State<ChatDetails> {
if (input == null) return; if (input == null) return;
final success = await showFutureLoadingDialog( final success = await showFutureLoadingDialog(
context: context, context: context,
future: () => widget.room.setName(input.single), future: () => room.setName(input.single),
); );
if (success.error == null) { if (success.error == null) {
await FlushbarHelper.createSuccess( await FlushbarHelper.createSuccess(
@ -74,9 +70,9 @@ class _ChatDetailsState extends State<ChatDetails> {
], ],
); );
if (input == null) return; if (input == null) return;
final domain = widget.room.client.userID.domain; final domain = room.client.userID.domain;
final canonicalAlias = '%23' + input.single + '%3A' + domain; final canonicalAlias = '%23' + input.single + '%3A' + domain;
final aliasEvent = widget.room.getState('m.room.aliases', domain); final aliasEvent = room.getState('m.room.aliases', domain);
final aliases = final aliases =
aliasEvent != null ? aliasEvent.content['aliases'] ?? [] : []; aliasEvent != null ? aliasEvent.content['aliases'] ?? [] : [];
if (aliases.indexWhere((s) => s == canonicalAlias) == -1) { if (aliases.indexWhere((s) => s == canonicalAlias) == -1) {
@ -84,22 +80,19 @@ class _ChatDetailsState extends State<ChatDetails> {
newAliases.add(canonicalAlias); newAliases.add(canonicalAlias);
final response = await showFutureLoadingDialog( final response = await showFutureLoadingDialog(
context: context, context: context,
future: () => future: () => room.client.requestRoomAliasInformations(canonicalAlias),
widget.room.client.requestRoomAliasInformations(canonicalAlias),
); );
if (response.error != null) { if (response.error != null) {
final success = await showFutureLoadingDialog( final success = await showFutureLoadingDialog(
context: context, context: context,
future: () => widget.room.client future: () => room.client.createRoomAlias(canonicalAlias, room.id),
.createRoomAlias(canonicalAlias, widget.room.id),
); );
if (success.error != null) return; if (success.error != null) return;
} }
} }
await showFutureLoadingDialog( await showFutureLoadingDialog(
context: context, context: context,
future: () => widget.room.client future: () => room.client.sendState(room.id, 'm.room.canonical_alias', {
.sendState(widget.room.id, 'm.room.canonical_alias', {
'alias': input.single, 'alias': input.single,
}), }),
); );
@ -112,7 +105,7 @@ class _ChatDetailsState extends State<ChatDetails> {
textFields: [ textFields: [
DialogTextField( DialogTextField(
hintText: L10n.of(context).setGroupDescription, hintText: L10n.of(context).setGroupDescription,
initialText: widget.room.topic, initialText: room.topic,
minLines: 1, minLines: 1,
maxLines: 4, maxLines: 4,
) )
@ -121,7 +114,7 @@ class _ChatDetailsState extends State<ChatDetails> {
if (input == null) return; if (input == null) return;
final success = await showFutureLoadingDialog( final success = await showFutureLoadingDialog(
context: context, context: context,
future: () => widget.room.setDescription(input.single), future: () => room.setDescription(input.single),
); );
if (success.error == null) { if (success.error == null) {
await FlushbarHelper.createSuccess( await FlushbarHelper.createSuccess(
@ -156,7 +149,7 @@ class _ChatDetailsState extends State<ChatDetails> {
final success = await showFutureLoadingDialog( final success = await showFutureLoadingDialog(
context: context, context: context,
future: () => widget.room.setAvatar(file), future: () => room.setAvatar(file),
); );
if (success.error == null) { if (success.error == null) {
await FlushbarHelper.createSuccess( await FlushbarHelper.createSuccess(
@ -167,7 +160,7 @@ class _ChatDetailsState extends State<ChatDetails> {
void requestMoreMembersAction(BuildContext context) async { void requestMoreMembersAction(BuildContext context) async {
final participants = await showFutureLoadingDialog( final participants = await showFutureLoadingDialog(
context: context, future: () => widget.room.requestParticipants()); context: context, future: () => room.requestParticipants());
if (participants.error == null) { if (participants.error == null) {
setState(() => members = participants.result); setState(() => members = participants.result);
} }
@ -175,7 +168,8 @@ class _ChatDetailsState extends State<ChatDetails> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (widget.room == null) { room ??= Matrix.of(context).client.getRoomById(widget.roomId);
if (room == null) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(L10n.of(context).oopsSomethingWentWrong), title: Text(L10n.of(context).oopsSomethingWentWrong),
@ -185,18 +179,13 @@ class _ChatDetailsState extends State<ChatDetails> {
), ),
); );
} }
members ??= widget.room.getParticipants(); members ??= room.getParticipants();
members.removeWhere((u) => u.membership == Membership.leave); members.removeWhere((u) => u.membership == Membership.leave);
final actualMembersCount = final actualMembersCount =
widget.room.mInvitedMemberCount + widget.room.mJoinedMemberCount; room.mInvitedMemberCount + room.mJoinedMemberCount;
final canRequestMoreMembers = members.length < actualMembersCount; final canRequestMoreMembers = members.length < actualMembersCount;
return AdaptivePageLayout( return StreamBuilder(
primaryPage: FocusPage.SECOND, stream: room.onUpdate.stream,
firstScaffold: ChatList(
activeChat: widget.room.id,
),
secondScaffold: StreamBuilder(
stream: widget.room.onUpdate.stream,
builder: (context, snapshot) { builder: (context, snapshot) {
return Scaffold( return Scaffold(
body: NestedScrollView( body: NestedScrollView(
@ -207,18 +196,17 @@ class _ChatDetailsState extends State<ChatDetails> {
floating: true, floating: true,
pinned: true, pinned: true,
actions: <Widget>[ actions: <Widget>[
if (widget.room.canonicalAlias?.isNotEmpty ?? false) if (room.canonicalAlias?.isNotEmpty ?? false)
IconButton( IconButton(
icon: Icon(Icons.share_outlined), icon: Icon(Icons.share_outlined),
onPressed: () => FluffyShare.share( onPressed: () => FluffyShare.share(
AppConfig.inviteLinkPrefix + AppConfig.inviteLinkPrefix + room.canonicalAlias,
widget.room.canonicalAlias,
context), context),
), ),
ChatSettingsPopupMenu(widget.room, false) ChatSettingsPopupMenu(room, false)
], ],
title: Text( title: Text(
widget.room.getLocalizedDisplayname( room.getLocalizedDisplayname(
MatrixLocals(L10n.of(context))), MatrixLocals(L10n.of(context))),
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context)
@ -228,22 +216,21 @@ class _ChatDetailsState extends State<ChatDetails> {
.color)), .color)),
backgroundColor: Theme.of(context).appBarTheme.color, backgroundColor: Theme.of(context).appBarTheme.color,
flexibleSpace: FlexibleSpaceBar( flexibleSpace: FlexibleSpaceBar(
background: ContentBanner(widget.room.avatar, background: ContentBanner(room.avatar,
onEdit: widget.room.canSendEvent('m.room.avatar') onEdit: room.canSendEvent('m.room.avatar')
? () => setAvatarAction(context) ? () => setAvatarAction(context)
: null), : null),
), ),
), ),
], ],
body: ListView.builder( body: ListView.builder(
itemCount: itemCount: members.length + 1 + (canRequestMoreMembers ? 1 : 0),
members.length + 1 + (canRequestMoreMembers ? 1 : 0),
itemBuilder: (BuildContext context, int i) => i == 0 itemBuilder: (BuildContext context, int i) => i == 0
? Column( ? Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
ListTile( ListTile(
leading: widget.room.canSendEvent('m.room.topic') leading: room.canSendEvent('m.room.topic')
? CircleAvatar( ? CircleAvatar(
backgroundColor: Theme.of(context) backgroundColor: Theme.of(context)
.scaffoldBackgroundColor, .scaffoldBackgroundColor,
@ -251,27 +238,24 @@ class _ChatDetailsState extends State<ChatDetails> {
child: Icon(Icons.edit_outlined), child: Icon(Icons.edit_outlined),
) )
: null, : null,
title: Text( title: Text('${L10n.of(context).groupDescription}:',
'${L10n.of(context).groupDescription}:',
style: TextStyle( style: TextStyle(
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold)), fontWeight: FontWeight.bold)),
subtitle: LinkText( subtitle: LinkText(
text: widget.room.topic?.isEmpty ?? true text: room.topic?.isEmpty ?? true
? L10n.of(context).addGroupDescription ? L10n.of(context).addGroupDescription
: widget.room.topic, : room.topic,
linkStyle: TextStyle(color: Colors.blueAccent), linkStyle: TextStyle(color: Colors.blueAccent),
textStyle: TextStyle( textStyle: TextStyle(
fontSize: 14, fontSize: 14,
color: Theme.of(context) color:
.textTheme Theme.of(context).textTheme.bodyText2.color,
.bodyText2
.color,
), ),
onLinkTap: (url) => onLinkTap: (url) =>
UrlLauncher(context, url).launchUrl(), UrlLauncher(context, url).launchUrl(),
), ),
onTap: widget.room.canSendEvent('m.room.topic') onTap: room.canSendEvent('m.room.topic')
? () => setTopicAction(context) ? () => setTopicAction(context)
: null, : null,
), ),
@ -285,7 +269,7 @@ class _ChatDetailsState extends State<ChatDetails> {
), ),
), ),
), ),
if (widget.room.canSendEvent('m.room.name')) if (room.canSendEvent('m.room.name'))
ListTile( ListTile(
leading: CircleAvatar( leading: CircleAvatar(
backgroundColor: backgroundColor:
@ -295,14 +279,12 @@ class _ChatDetailsState extends State<ChatDetails> {
), ),
title: Text( title: Text(
L10n.of(context).changeTheNameOfTheGroup), L10n.of(context).changeTheNameOfTheGroup),
subtitle: Text(widget.room subtitle: Text(room.getLocalizedDisplayname(
.getLocalizedDisplayname(
MatrixLocals(L10n.of(context)))), MatrixLocals(L10n.of(context)))),
onTap: () => setDisplaynameAction(context), onTap: () => setDisplaynameAction(context),
), ),
if (widget.room if (room.canSendEvent('m.room.canonical_alias') &&
.canSendEvent('m.room.canonical_alias') && room.joinRules == JoinRules.public)
widget.room.joinRules == JoinRules.public)
ListTile( ListTile(
leading: CircleAvatar( leading: CircleAvatar(
backgroundColor: backgroundColor:
@ -313,9 +295,8 @@ class _ChatDetailsState extends State<ChatDetails> {
onTap: () => setCanonicalAliasAction(context), onTap: () => setCanonicalAliasAction(context),
title: Text(L10n.of(context).setInvitationLink), title: Text(L10n.of(context).setInvitationLink),
subtitle: Text( subtitle: Text(
(widget.room.canonicalAlias?.isNotEmpty ?? (room.canonicalAlias?.isNotEmpty ?? false)
false) ? room.canonicalAlias
? widget.room.canonicalAlias
: L10n.of(context).none), : L10n.of(context).none),
), ),
ListTile( ListTile(
@ -331,58 +312,48 @@ class _ChatDetailsState extends State<ChatDetails> {
// okay, we need to test if there are any emote state events other than the default one // okay, we need to test if there are any emote state events other than the default one
// if so, we need to be directed to a selection screen for which pack we want to look at // if so, we need to be directed to a selection screen for which pack we want to look at
// otherwise, we just open the normal one. // otherwise, we just open the normal one.
if ((widget.room.states if ((room.states
.states['im.ponies.room_emotes'] ?? .states['im.ponies.room_emotes'] ??
<String, Event>{}) <String, Event>{})
.keys .keys
.any((String s) => s.isNotEmpty)) { .any((String s) => s.isNotEmpty)) {
await Navigator.of(context).push( await AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .pushNamed('/rooms/${room.id}/emotes');
context,
MultipleEmotesSettingsView(
room: widget.room),
),
);
} else { } else {
await Navigator.of(context).push( await AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .pushNamed('/settings/emotes');
context,
EmotesSettingsView(room: widget.room),
),
);
} }
}, },
), ),
PopupMenuButton( PopupMenuButton(
child: ListTile( child: ListTile(
leading: CircleAvatar( leading: CircleAvatar(
backgroundColor: Theme.of(context) backgroundColor:
.scaffoldBackgroundColor, Theme.of(context).scaffoldBackgroundColor,
foregroundColor: Colors.grey, foregroundColor: Colors.grey,
child: Icon(Icons.public_outlined)), child: Icon(Icons.public_outlined)),
title: Text(L10n.of(context) title: Text(
.whoIsAllowedToJoinThisGroup), L10n.of(context).whoIsAllowedToJoinThisGroup),
subtitle: Text( subtitle: Text(
widget.room.joinRules.getLocalizedString( room.joinRules.getLocalizedString(
MatrixLocals(L10n.of(context))), MatrixLocals(L10n.of(context))),
), ),
), ),
onSelected: (JoinRules joinRule) => onSelected: (JoinRules joinRule) =>
showFutureLoadingDialog( showFutureLoadingDialog(
context: context, context: context,
future: () => future: () => room.setJoinRules(joinRule),
widget.room.setJoinRules(joinRule),
), ),
itemBuilder: (BuildContext context) => itemBuilder: (BuildContext context) =>
<PopupMenuEntry<JoinRules>>[ <PopupMenuEntry<JoinRules>>[
if (widget.room.canChangeJoinRules) if (room.canChangeJoinRules)
PopupMenuItem<JoinRules>( PopupMenuItem<JoinRules>(
value: JoinRules.public, value: JoinRules.public,
child: Text(JoinRules.public child: Text(JoinRules.public
.getLocalizedString( .getLocalizedString(
MatrixLocals(L10n.of(context)))), MatrixLocals(L10n.of(context)))),
), ),
if (widget.room.canChangeJoinRules) if (room.canChangeJoinRules)
PopupMenuItem<JoinRules>( PopupMenuItem<JoinRules>(
value: JoinRules.invite, value: JoinRules.invite,
child: Text(JoinRules.invite child: Text(JoinRules.invite
@ -399,45 +370,43 @@ class _ChatDetailsState extends State<ChatDetails> {
foregroundColor: Colors.grey, foregroundColor: Colors.grey,
child: Icon(Icons.visibility_outlined), child: Icon(Icons.visibility_outlined),
), ),
title: Text(L10n.of(context) title: Text(
.visibilityOfTheChatHistory), L10n.of(context).visibilityOfTheChatHistory),
subtitle: Text( subtitle: Text(
widget.room.historyVisibility room.historyVisibility.getLocalizedString(
.getLocalizedString(
MatrixLocals(L10n.of(context))), MatrixLocals(L10n.of(context))),
), ),
), ),
onSelected: onSelected: (HistoryVisibility historyVisibility) =>
(HistoryVisibility historyVisibility) =>
showFutureLoadingDialog( showFutureLoadingDialog(
context: context, context: context,
future: () => widget.room future: () =>
.setHistoryVisibility(historyVisibility), room.setHistoryVisibility(historyVisibility),
), ),
itemBuilder: (BuildContext context) => itemBuilder: (BuildContext context) =>
<PopupMenuEntry<HistoryVisibility>>[ <PopupMenuEntry<HistoryVisibility>>[
if (widget.room.canChangeHistoryVisibility) if (room.canChangeHistoryVisibility)
PopupMenuItem<HistoryVisibility>( PopupMenuItem<HistoryVisibility>(
value: HistoryVisibility.invited, value: HistoryVisibility.invited,
child: Text(HistoryVisibility.invited child: Text(HistoryVisibility.invited
.getLocalizedString( .getLocalizedString(
MatrixLocals(L10n.of(context)))), MatrixLocals(L10n.of(context)))),
), ),
if (widget.room.canChangeHistoryVisibility) if (room.canChangeHistoryVisibility)
PopupMenuItem<HistoryVisibility>( PopupMenuItem<HistoryVisibility>(
value: HistoryVisibility.joined, value: HistoryVisibility.joined,
child: Text(HistoryVisibility.joined child: Text(HistoryVisibility.joined
.getLocalizedString( .getLocalizedString(
MatrixLocals(L10n.of(context)))), MatrixLocals(L10n.of(context)))),
), ),
if (widget.room.canChangeHistoryVisibility) if (room.canChangeHistoryVisibility)
PopupMenuItem<HistoryVisibility>( PopupMenuItem<HistoryVisibility>(
value: HistoryVisibility.shared, value: HistoryVisibility.shared,
child: Text(HistoryVisibility.shared child: Text(HistoryVisibility.shared
.getLocalizedString( .getLocalizedString(
MatrixLocals(L10n.of(context)))), MatrixLocals(L10n.of(context)))),
), ),
if (widget.room.canChangeHistoryVisibility) if (room.canChangeHistoryVisibility)
PopupMenuItem<HistoryVisibility>( PopupMenuItem<HistoryVisibility>(
value: HistoryVisibility.world_readable, value: HistoryVisibility.world_readable,
child: Text(HistoryVisibility.world_readable child: Text(HistoryVisibility.world_readable
@ -446,31 +415,30 @@ class _ChatDetailsState extends State<ChatDetails> {
), ),
], ],
), ),
if (widget.room.joinRules == JoinRules.public) if (room.joinRules == JoinRules.public)
PopupMenuButton( PopupMenuButton(
child: ListTile( child: ListTile(
leading: CircleAvatar( leading: CircleAvatar(
backgroundColor: Theme.of(context) backgroundColor:
.scaffoldBackgroundColor, Theme.of(context).scaffoldBackgroundColor,
foregroundColor: Colors.grey, foregroundColor: Colors.grey,
child: Icon(Icons.info_outline), child: Icon(Icons.info_outline),
), ),
title: Text( title: Text(
L10n.of(context).areGuestsAllowedToJoin), L10n.of(context).areGuestsAllowedToJoin),
subtitle: Text( subtitle: Text(
widget.room.guestAccess.getLocalizedString( room.guestAccess.getLocalizedString(
MatrixLocals(L10n.of(context))), MatrixLocals(L10n.of(context))),
), ),
), ),
onSelected: (GuestAccess guestAccess) => onSelected: (GuestAccess guestAccess) =>
showFutureLoadingDialog( showFutureLoadingDialog(
context: context, context: context,
future: () => future: () => room.setGuestAccess(guestAccess),
widget.room.setGuestAccess(guestAccess),
), ),
itemBuilder: (BuildContext context) => itemBuilder: (BuildContext context) =>
<PopupMenuEntry<GuestAccess>>[ <PopupMenuEntry<GuestAccess>>[
if (widget.room.canChangeGuestAccess) if (room.canChangeGuestAccess)
PopupMenuItem<GuestAccess>( PopupMenuItem<GuestAccess>(
value: GuestAccess.can_join, value: GuestAccess.can_join,
child: Text( child: Text(
@ -478,12 +446,11 @@ class _ChatDetailsState extends State<ChatDetails> {
MatrixLocals(L10n.of(context))), MatrixLocals(L10n.of(context))),
), ),
), ),
if (widget.room.canChangeGuestAccess) if (room.canChangeGuestAccess)
PopupMenuItem<GuestAccess>( PopupMenuItem<GuestAccess>(
value: GuestAccess.forbidden, value: GuestAccess.forbidden,
child: Text( child: Text(
GuestAccess.forbidden GuestAccess.forbidden.getLocalizedString(
.getLocalizedString(
MatrixLocals(L10n.of(context))), MatrixLocals(L10n.of(context))),
), ),
), ),
@ -491,21 +458,16 @@ class _ChatDetailsState extends State<ChatDetails> {
), ),
ListTile( ListTile(
title: Text(L10n.of(context).editChatPermissions), title: Text(L10n.of(context).editChatPermissions),
subtitle: Text( subtitle:
L10n.of(context).whoCanPerformWhichAction), Text(L10n.of(context).whoCanPerformWhichAction),
leading: CircleAvatar( leading: CircleAvatar(
backgroundColor: backgroundColor:
Theme.of(context).scaffoldBackgroundColor, Theme.of(context).scaffoldBackgroundColor,
foregroundColor: Colors.grey, foregroundColor: Colors.grey,
child: Icon(Icons.edit_attributes_outlined), child: Icon(Icons.edit_attributes_outlined),
), ),
onTap: () => Navigator.of(context).push( onTap: () => AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .pushNamed('/rooms/${room.id}/permissions'),
context,
ChatPermissionsSettingsView(
roomId: widget.room.id),
),
),
), ),
Divider(thickness: 1), Divider(thickness: 1),
ListTile( ListTile(
@ -520,7 +482,7 @@ class _ChatDetailsState extends State<ChatDetails> {
), ),
), ),
), ),
widget.room.canInvite room.canInvite
? ListTile( ? ListTile(
title: Text(L10n.of(context).inviteContact), title: Text(L10n.of(context).inviteContact),
leading: CircleAvatar( leading: CircleAvatar(
@ -529,12 +491,8 @@ class _ChatDetailsState extends State<ChatDetails> {
Theme.of(context).primaryColor, Theme.of(context).primaryColor,
foregroundColor: Colors.white, foregroundColor: Colors.white,
), ),
onTap: () => Navigator.of(context).push( onTap: () => AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .pushNamed('/rooms/${room.id}/invite'),
context,
InvitationSelection(widget.room),
),
),
) )
: Container(), : Container(),
], ],
@ -559,7 +517,6 @@ class _ChatDetailsState extends State<ChatDetails> {
), ),
), ),
); );
}), });
);
} }
} }

View File

@ -1,32 +1,14 @@
import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:famedlysdk/encryption.dart'; import 'package:famedlysdk/encryption.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.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/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/utils/beautify_string_extension.dart'; import 'package:fluffychat/utils/beautify_string_extension.dart';
import 'package:fluffychat/views/chat_list.dart';
import 'package:flushbar/flushbar_helper.dart'; import 'package:flushbar/flushbar_helper.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../components/dialogs/key_verification_dialog.dart'; import '../components/dialogs/key_verification_dialog.dart';
class ChatEncryptionSettingsView extends StatelessWidget {
final String id;
const ChatEncryptionSettingsView(this.id, {Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
firstScaffold: ChatList(
activeChat: id,
),
secondScaffold: ChatEncryptionSettings(id),
primaryPage: FocusPage.SECOND,
);
}
}
class ChatEncryptionSettings extends StatefulWidget { class ChatEncryptionSettings extends StatefulWidget {
final String id; final String id;

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
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:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/connection_status_header.dart'; import 'package:fluffychat/components/connection_status_header.dart';
import 'package:fluffychat/components/default_app_bar_search_field.dart'; import 'package:fluffychat/components/default_app_bar_search_field.dart';
@ -14,29 +15,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:receive_sharing_intent/receive_sharing_intent.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart';
import '../components/adaptive_page_layout.dart';
import '../components/list_items/chat_list_item.dart'; import '../components/list_items/chat_list_item.dart';
import '../components/matrix.dart'; import '../components/matrix.dart';
import '../utils/app_route.dart';
import '../utils/matrix_file_extension.dart'; import '../utils/matrix_file_extension.dart';
import '../utils/url_launcher.dart'; import '../utils/url_launcher.dart';
import 'empty_page.dart';
import 'homeserver_picker.dart';
import 'new_private_chat.dart';
enum SelectMode { normal, share, select } enum SelectMode { normal, share, select }
class ChatListView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
primaryPage: FocusPage.FIRST,
firstScaffold: ChatList(),
secondScaffold: EmptyPage(),
);
}
}
class ChatList extends StatefulWidget { class ChatList extends StatefulWidget {
final String activeChat; final String activeChat;
@ -86,9 +71,7 @@ class _ChatListState extends State<ChatList> {
void _processIncomingSharedFiles(List<SharedMediaFile> files) { void _processIncomingSharedFiles(List<SharedMediaFile> files) {
if (files?.isEmpty ?? true) return; if (files?.isEmpty ?? true) return;
if (Navigator.of(context).canPop()) { AdaptivePageLayout.of(context).popUntilIsFirst();
Navigator.of(context).popUntil((r) => r.isFirst);
}
final file = File(files.first.path); final file = File(files.first.path);
Matrix.of(context).shareContent = { Matrix.of(context).shareContent = {
@ -102,9 +85,7 @@ class _ChatListState extends State<ChatList> {
void _processIncomingSharedText(String text) { void _processIncomingSharedText(String text) {
if (text == null) return; if (text == null) return;
if (Navigator.of(context).canPop()) { AdaptivePageLayout.of(context).popUntilIsFirst();
Navigator.of(context).popUntil((r) => r.isFirst);
}
if (text.toLowerCase().startsWith(AppConfig.inviteLinkPrefix) || if (text.toLowerCase().startsWith(AppConfig.inviteLinkPrefix) ||
(text.toLowerCase().startsWith(AppConfig.schemePrefix) && (text.toLowerCase().startsWith(AppConfig.schemePrefix) &&
!RegExp(r'\s').hasMatch(text))) { !RegExp(r'\s').hasMatch(text))) {
@ -194,17 +175,6 @@ class _ChatListState extends State<ChatList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return StreamBuilder<LoginState>(
stream: Matrix.of(context).client.onLoginStateChanged.stream,
builder: (context, snapshot) {
if (snapshot.data == LoginState.loggedOut) {
Timer(Duration(seconds: 1), () {
Matrix.of(context).clean();
Navigator.of(context).pushAndRemoveUntil(
AppRoute.defaultRoute(context, HomeserverPicker()),
(r) => false);
});
}
return StreamBuilder( return StreamBuilder(
stream: Matrix.of(context).onShareContentChanged.stream, stream: Matrix.of(context).onShareContentChanged.stream,
builder: (context, snapshot) { builder: (context, snapshot) {
@ -218,27 +188,23 @@ class _ChatListState extends State<ChatList> {
} }
Room selectedRoom; Room selectedRoom;
if (_selectedRoomIds.length == 1) { if (_selectedRoomIds.length == 1) {
selectedRoom = Matrix.of(context) selectedRoom =
.client Matrix.of(context).client.getRoomById(_selectedRoomIds.single);
.getRoomById(_selectedRoomIds.single);
} }
return Scaffold( return Scaffold(
drawer: drawer: selectMode != SelectMode.normal ? null : DefaultDrawer(),
selectMode != SelectMode.normal ? null : DefaultDrawer(),
appBar: AppBar( appBar: AppBar(
centerTitle: false, centerTitle: false,
elevation: _scrolledToTop ? 0 : null, elevation: _scrolledToTop ? 0 : null,
leading: selectMode == SelectMode.share leading: selectMode == SelectMode.share
? IconButton( ? IconButton(
icon: Icon(Icons.close), icon: Icon(Icons.close),
onPressed: () => onPressed: () => Matrix.of(context).shareContent = null,
Matrix.of(context).shareContent = null,
) )
: selectMode == SelectMode.select : selectMode == SelectMode.select
? IconButton( ? IconButton(
icon: Icon(Icons.close), icon: Icon(Icons.close),
onPressed: () => onPressed: () => setState(_selectedRoomIds.clear),
setState(_selectedRoomIds.clear),
) )
: null, : null,
titleSpacing: 0, titleSpacing: 0,
@ -261,8 +227,8 @@ class _ChatListState extends State<ChatList> {
), ),
if (_selectedRoomIds.length == 1) if (_selectedRoomIds.length == 1)
IconButton( IconButton(
icon: Icon(selectedRoom.pushRuleState == icon: Icon(
PushRuleState.notify selectedRoom.pushRuleState == PushRuleState.notify
? Icons.notifications_off_outlined ? Icons.notifications_off_outlined
: Icons.notifications_outlined), : Icons.notifications_outlined),
tooltip: L10n.of(context).toggleMuted, tooltip: L10n.of(context).toggleMuted,
@ -284,16 +250,14 @@ class _ChatListState extends State<ChatList> {
onChanged: (_) => setState(() => null), onChanged: (_) => setState(() => null),
), ),
), ),
floatingActionButton: AdaptivePageLayout.columnMode(context) floatingActionButton:
AdaptivePageLayout.of(context).columnMode(context)
? null ? null
: FloatingActionButton( : FloatingActionButton(
child: Icon(Icons.add_outlined), child: Icon(Icons.add_outlined),
backgroundColor: Theme.of(context).primaryColor, backgroundColor: Theme.of(context).primaryColor,
onPressed: () => Navigator.of(context) onPressed: () => AdaptivePageLayout.of(context)
.pushAndRemoveUntil( .pushNamedAndRemoveUntilIsFirst('/newprivatechat'),
AppRoute.defaultRoute(
context, NewPrivateChatView()),
(r) => r.isFirst),
), ),
body: Column( body: Column(
children: [ children: [
@ -315,10 +279,8 @@ class _ChatListState extends State<ChatList> {
rooms.removeWhere((Room room) => rooms.removeWhere((Room room) =>
room.lastEvent == null || room.lastEvent == null ||
(searchMode && (searchMode &&
!room.displayname !room.displayname.toLowerCase().contains(
.toLowerCase() searchController.text.toLowerCase() ??
.contains(searchController.text
.toLowerCase() ??
''))); '')));
if (rooms.isEmpty && (!searchMode)) { if (rooms.isEmpty && (!searchMode)) {
return Center( return Center(
@ -343,17 +305,15 @@ class _ChatListState extends State<ChatList> {
final totalCount = rooms.length; final totalCount = rooms.length;
return ListView.separated( return ListView.separated(
controller: _scrollController, controller: _scrollController,
separatorBuilder: (BuildContext context, separatorBuilder:
int i) => (BuildContext context, int i) =>
i == totalCount i == totalCount
? ListTile( ? ListTile(
title: Text( title: Text(
L10n.of(context) L10n.of(context).publicRooms +
.publicRooms +
':', ':',
style: TextStyle( style: TextStyle(
fontWeight: fontWeight: FontWeight.bold,
FontWeight.bold,
color: Theme.of(context) color: Theme.of(context)
.primaryColor, .primaryColor,
), ),
@ -361,23 +321,18 @@ class _ChatListState extends State<ChatList> {
) )
: Container(), : Container(),
itemCount: totalCount, itemCount: totalCount,
itemBuilder: itemBuilder: (BuildContext context, int i) =>
(BuildContext context, int i) =>
ChatListItem( ChatListItem(
rooms[i], rooms[i],
selected: _selectedRoomIds selected:
.contains(rooms[i].id), _selectedRoomIds.contains(rooms[i].id),
onTap: selectMode == SelectMode.select onTap: selectMode == SelectMode.select
? () => ? () => _toggleSelection(rooms[i].id)
_toggleSelection(rooms[i].id)
: null, : null,
onLongPress: selectMode != onLongPress: selectMode != SelectMode.share
SelectMode.share ? () => _toggleSelection(rooms[i].id)
? () =>
_toggleSelection(rooms[i].id)
: null, : null,
activeChat: activeChat: widget.activeChat == rooms[i].id,
widget.activeChat == rooms[i].id,
), ),
); );
} else { } else {
@ -393,6 +348,5 @@ class _ChatListState extends State<ChatList> {
), ),
); );
}); });
});
} }
} }

View File

@ -1,6 +1,5 @@
import 'dart:developer'; import 'dart:developer';
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/dialogs/permission_slider_dialog.dart'; import 'package:fluffychat/components/dialogs/permission_slider_dialog.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
@ -9,29 +8,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'chat_list.dart';
class ChatPermissionsSettingsView extends StatelessWidget {
final String roomId;
const ChatPermissionsSettingsView({Key key, this.roomId}) : super(key: key);
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
firstScaffold: ChatList(
activeChat: roomId,
),
secondScaffold: ChatPermissionsSettings(roomId: roomId),
primaryPage: FocusPage.SECOND,
);
}
}
class ChatPermissionsSettings extends StatelessWidget { class ChatPermissionsSettings extends StatelessWidget {
final String roomId; final String roomId;
const ChatPermissionsSettings({Key key, @required this.roomId}) const ChatPermissionsSettings(this.roomId, {Key key}) : super(key: key);
: super(key: key);
void _editPowerLevel(BuildContext context, String key, int currentLevel, void _editPowerLevel(BuildContext context, String key, int currentLevel,
{String category}) async { {String category}) async {

View File

@ -1,32 +1,15 @@
import 'dart:async'; import 'dart:async';
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:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.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/default_app_bar_search_field.dart'; import 'package:fluffychat/components/default_app_bar_search_field.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/views/chat.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'empty_page.dart';
class DiscoverView extends StatelessWidget {
final String alias;
const DiscoverView({Key key, this.alias}) : super(key: key);
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
firstScaffold: DiscoverPage(alias: alias),
secondScaffold: EmptyPage(),
);
}
}
class DiscoverPage extends StatefulWidget { class DiscoverPage extends StatefulWidget {
final String alias; final String alias;
@ -110,12 +93,8 @@ class _DiscoverPageState extends State<DiscoverPage> {
), ),
); );
if (success.error == null) { if (success.error == null) {
await Navigator.of(context).push( await AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .pushNamedAndRemoveUntilIsFirst('/rooms/${success.result}');
context,
ChatView(success.result),
),
);
} }
} }

View File

@ -1,19 +1,16 @@
import 'dart:math'; import 'dart:math';
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:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/app_config.dart'; import 'package:fluffychat/app_config.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/utils/sentry_controller.dart'; import 'package:fluffychat/utils/sentry_controller.dart';
import 'package:fluffychat/views/sign_up.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'login.dart';
class HomeserverPicker extends StatelessWidget { class HomeserverPicker extends StatelessWidget {
Future<void> _setHomeserverAction(BuildContext context) async { Future<void> _setHomeserverAction(BuildContext context) async {
const prefix = 'https://'; const prefix = 'https://';
@ -45,8 +42,8 @@ class HomeserverPicker extends StatelessWidget {
context: context, context: context,
future: () => checkHomeserver(homeserver, Matrix.of(context).client)); future: () => checkHomeserver(homeserver, Matrix.of(context).client));
if (success.result == true) { if (success.result == true) {
await Navigator.of(context) await AdaptivePageLayout.of(context)
.push(AppRoute(AppConfig.enableRegistration ? SignUp() : Login())); .pushNamed(AppConfig.enableRegistration ? '/signup' : '/login');
} }
} }

View File

@ -1,3 +1,4 @@
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/image_bubble.dart'; import 'package:fluffychat/components/image_bubble.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
@ -13,7 +14,7 @@ class ImageView extends StatelessWidget {
void _forwardAction(BuildContext context) async { void _forwardAction(BuildContext context) async {
Matrix.of(context).shareContent = event.content; Matrix.of(context).shareContent = event.content;
Navigator.of(context).popUntil((r) => r.isFirst); AdaptivePageLayout.of(context).popUntilIsFirst();
} }
@override @override

View File

@ -3,7 +3,6 @@ import 'dart:async';
import 'package:fluffychat/components/default_app_bar_search_field.dart'; import 'package:fluffychat/components/default_app_bar_search_field.dart';
import 'package:flushbar/flushbar_helper.dart'; import 'package:flushbar/flushbar_helper.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/avatar.dart'; import 'package:fluffychat/components/avatar.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
@ -11,11 +10,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../utils/localized_exception_extension.dart'; import '../utils/localized_exception_extension.dart';
import 'chat_list.dart';
class InvitationSelection extends StatefulWidget { class InvitationSelection extends StatefulWidget {
final Room room; final String roomId;
const InvitationSelection(this.room, {Key key}) : super(key: key); const InvitationSelection(this.roomId, {Key key}) : super(key: key);
@override @override
_InvitationSelectionState createState() => _InvitationSelectionState(); _InvitationSelectionState createState() => _InvitationSelectionState();
@ -27,11 +25,12 @@ class _InvitationSelectionState extends State<InvitationSelection> {
bool loading = false; bool loading = false;
List<Profile> foundProfiles = []; List<Profile> foundProfiles = [];
Timer coolDown; Timer coolDown;
Room room;
Future<List<User>> getContacts(BuildContext context) async { Future<List<User>> getContacts(BuildContext context) async {
var client2 = Matrix.of(context).client; var client2 = Matrix.of(context).client;
final client = client2; final client = client2;
var participants = await widget.room.requestParticipants(); var participants = await room.requestParticipants();
participants.removeWhere( participants.removeWhere(
(u) => ![Membership.join, Membership.invite].contains(u.membership), (u) => ![Membership.join, Membership.invite].contains(u.membership),
); );
@ -59,7 +58,7 @@ class _InvitationSelectionState extends State<InvitationSelection> {
void inviteAction(BuildContext context, String id) async { void inviteAction(BuildContext context, String id) async {
final success = await showFutureLoadingDialog( final success = await showFutureLoadingDialog(
context: context, context: context,
future: () => widget.room.invite(id), future: () => room.invite(id),
); );
if (success.error == null) { if (success.error == null) {
await FlushbarHelper.createSuccess( await FlushbarHelper.createSuccess(
@ -107,7 +106,7 @@ class _InvitationSelectionState extends State<InvitationSelection> {
Profile.fromJson({'user_id': '@$text'}), Profile.fromJson({'user_id': '@$text'}),
]); ]);
} }
final participants = widget.room final participants = room
.getParticipants() .getParticipants()
.where((user) => .where((user) =>
[Membership.join, Membership.invite].contains(user.membership)) [Membership.join, Membership.invite].contains(user.membership))
@ -119,13 +118,10 @@ class _InvitationSelectionState extends State<InvitationSelection> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final groupName = widget.room.name?.isEmpty ?? false room ??= Matrix.of(context).client.getRoomById(widget.roomId);
? L10n.of(context).group final groupName =
: widget.room.name; room.name?.isEmpty ?? false ? L10n.of(context).group : room.name;
return AdaptivePageLayout( return Scaffold(
primaryPage: FocusPage.SECOND,
firstScaffold: ChatList(activeChat: widget.room.id),
secondScaffold: Scaffold(
appBar: AppBar( appBar: AppBar(
titleSpacing: 0, titleSpacing: 0,
title: DefaultAppBarSearchField( title: DefaultAppBarSearchField(
@ -172,7 +168,7 @@ class _InvitationSelectionState extends State<InvitationSelection> {
), ),
); );
}, },
)), ),
); );
} }
} }

View File

@ -0,0 +1,38 @@
import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/matrix.dart';
import 'package:flushbar/flushbar_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'chat_list.dart';
import 'homeserver_picker.dart';
class LoadingView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FutureBuilder<LoginState>(
future: Matrix.of(context).client.onLoginStateChanged.stream.first,
builder: (context, snapshot) {
if (snapshot.hasError) {
WidgetsBinding.instance
.addPostFrameCallback((_) => FlushbarHelper.createError(
title: L10n.of(context).oopsSomethingWentWrong,
message: snapshot.error.toString(),
).show(context));
return HomeserverPicker();
}
if (!snapshot.hasData) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
if (Matrix.of(context).client.isLogged()) {
return ChatList();
}
return HomeserverPicker();
},
);
}
}

View File

@ -5,15 +5,10 @@ import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/utils/firebase_controller.dart';
import 'package:fluffychat/utils/sentry_controller.dart';
import 'package:flushbar/flushbar_helper.dart'; import 'package:flushbar/flushbar_helper.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'chat_list.dart';
class Login extends StatefulWidget { class Login extends StatefulWidget {
@override @override
_LoginState createState() => _LoginState(); _LoginState createState() => _LoginState();
@ -57,14 +52,8 @@ class _LoginState extends State<Login> {
setState(() => passwordError = exception.toString()); setState(() => passwordError = exception.toString());
return setState(() => loading = false); return setState(() => loading = false);
} }
await FirebaseController.setupFirebase(
matrix,
matrix.clientName,
).catchError(SentryController.captureException);
setState(() => loading = false); if (mounted) setState(() => loading = false);
await Navigator.of(context).pushAndRemoveUntil(
AppRoute.defaultRoute(context, ChatListView()), (r) => false);
} }
Timer _coolDown; Timer _coolDown;

View File

@ -1,33 +1,16 @@
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:famedlysdk/famedlysdk.dart' as sdk; import 'package:famedlysdk/famedlysdk.dart' as sdk;
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:pedantic/pedantic.dart';
import 'chat.dart'; class NewGroup extends StatefulWidget {
import 'chat_list.dart';
import 'invitation_selection.dart';
class NewGroupView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
primaryPage: FocusPage.SECOND,
firstScaffold: ChatList(),
secondScaffold: _NewGroup(),
);
}
}
class _NewGroup extends StatefulWidget {
@override @override
_NewGroupState createState() => _NewGroupState(); _NewGroupState createState() => _NewGroupState();
} }
class _NewGroupState extends State<_NewGroup> { class _NewGroupState extends State<NewGroup> {
TextEditingController controller = TextEditingController(); TextEditingController controller = TextEditingController();
bool publicGroup = false; bool publicGroup = false;
@ -45,24 +28,11 @@ class _NewGroupState extends State<_NewGroup> {
name: controller.text.isNotEmpty ? controller.text : null, name: controller.text.isNotEmpty ? controller.text : null,
), ),
); );
Navigator.of(context).pop(); AdaptivePageLayout.of(context).popUntilIsFirst();
if (roomID != null) { if (roomID != null) {
unawaited( await AdaptivePageLayout.of(context).pushNamed('/rooms/${roomID.result}');
Navigator.of(context).push( await AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .pushNamed('/rooms/${roomID.result}/invite');
context,
ChatView(roomID.result),
),
),
);
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InvitationSelection(
matrix.client.getRoomById(roomID.result),
),
),
);
} }
} }

View File

@ -1,35 +1,20 @@
import 'dart:async'; import 'dart:async';
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/avatar.dart'; import 'package:fluffychat/components/avatar.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/utils/fluffy_share.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'chat.dart'; class NewPrivateChat extends StatefulWidget {
import 'chat_list.dart';
class NewPrivateChatView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
primaryPage: FocusPage.SECOND,
firstScaffold: ChatList(),
secondScaffold: _NewPrivateChat(),
);
}
}
class _NewPrivateChat extends StatefulWidget {
@override @override
_NewPrivateChatState createState() => _NewPrivateChatState(); _NewPrivateChatState createState() => _NewPrivateChatState();
} }
class _NewPrivateChatState extends State<_NewPrivateChat> { class _NewPrivateChatState extends State<NewPrivateChat> {
TextEditingController controller = TextEditingController(); TextEditingController controller = TextEditingController();
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
bool loading = false; bool loading = false;
@ -59,15 +44,10 @@ class _NewPrivateChatState extends State<_NewPrivateChat> {
context: context, context: context,
future: () => user.startDirectChat(), future: () => user.startDirectChat(),
); );
Navigator.of(context).pop();
if (roomID.error == null) { if (roomID.error == null) {
await Navigator.of(context).push( await AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .popAndPushNamed('/rooms/${roomID.result}');
context,
ChatView(roomID.result),
),
);
} }
} }

View File

@ -1,9 +1,6 @@
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:fluffychat/components/dialogs/bootstrap_dialog.dart'; import 'package:fluffychat/components/dialogs/bootstrap_dialog.dart';
import 'package:fluffychat/views/log_view.dart';
import 'package:fluffychat/views/settings_3pid.dart';
import 'package:fluffychat/views/settings_notifications.dart';
import 'package:fluffychat/views/settings_style.dart';
import 'package:flushbar/flushbar_helper.dart'; import 'package:flushbar/flushbar_helper.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:file_picker_cross/file_picker_cross.dart'; import 'package:file_picker_cross/file_picker_cross.dart';
@ -12,33 +9,16 @@ import 'package:fluffychat/utils/beautify_string_extension.dart';
import 'package:fluffychat/app_config.dart'; import 'package:fluffychat/app_config.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/views/settings_devices.dart';
import 'package:fluffychat/views/settings_ignore_list.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../components/adaptive_page_layout.dart';
import '../components/content_banner.dart'; import '../components/content_banner.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import '../components/matrix.dart'; import '../components/matrix.dart';
import '../utils/app_route.dart';
import '../app_config.dart'; import '../app_config.dart';
import '../config/setting_keys.dart'; import '../config/setting_keys.dart';
import 'chat_list.dart';
import 'settings_emotes.dart';
class SettingsView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
primaryPage: FocusPage.SECOND,
firstScaffold: ChatList(),
secondScaffold: Settings(),
);
}
}
class Settings extends StatefulWidget { class Settings extends StatefulWidget {
@override @override
@ -333,12 +313,8 @@ class _SettingsState extends State<Settings> {
ListTile( ListTile(
trailing: Icon(Icons.notifications_outlined), trailing: Icon(Icons.notifications_outlined),
title: Text(L10n.of(context).notifications), title: Text(L10n.of(context).notifications),
onTap: () async => await Navigator.of(context).push( onTap: () => AdaptivePageLayout.of(context)
AppRoute.defaultRoute( .pushNamed('/settings/notifications'),
context,
SettingsNotificationsView(),
),
),
), ),
ListTile( ListTile(
title: Text( title: Text(
@ -351,12 +327,8 @@ class _SettingsState extends State<Settings> {
), ),
ListTile( ListTile(
title: Text(L10n.of(context).changeTheme), title: Text(L10n.of(context).changeTheme),
onTap: () async => await Navigator.of(context).push( onTap: () =>
AppRoute.defaultRoute( AdaptivePageLayout.of(context).pushNamed('/settings/style'),
context,
SettingsStyleView(),
),
),
trailing: Icon(Icons.style_outlined), trailing: Icon(Icons.style_outlined),
), ),
SwitchListTile( SwitchListTile(
@ -392,12 +364,8 @@ class _SettingsState extends State<Settings> {
), ),
ListTile( ListTile(
title: Text(L10n.of(context).emoteSettings), title: Text(L10n.of(context).emoteSettings),
onTap: () async => await Navigator.of(context).push( onTap: () =>
AppRoute.defaultRoute( AdaptivePageLayout.of(context).pushNamed('/settings/emotes'),
context,
EmotesSettingsView(),
),
),
trailing: Icon(Icons.insert_emoticon_outlined), trailing: Icon(Icons.insert_emoticon_outlined),
), ),
Divider(thickness: 1), Divider(thickness: 1),
@ -425,22 +393,14 @@ class _SettingsState extends State<Settings> {
ListTile( ListTile(
trailing: Icon(Icons.devices_other_outlined), trailing: Icon(Icons.devices_other_outlined),
title: Text(L10n.of(context).devices), title: Text(L10n.of(context).devices),
onTap: () async => await Navigator.of(context).push( onTap: () =>
AppRoute.defaultRoute( AdaptivePageLayout.of(context).pushNamed('/settings/devices'),
context,
DevicesSettingsView(),
),
),
), ),
ListTile( ListTile(
trailing: Icon(Icons.block_outlined), trailing: Icon(Icons.block_outlined),
title: Text(L10n.of(context).ignoredUsers), title: Text(L10n.of(context).ignoredUsers),
onTap: () async => await Navigator.of(context).push( onTap: () =>
AppRoute.defaultRoute( AdaptivePageLayout.of(context).pushNamed('/settings/ignore'),
context,
SettingsIgnoreListView(),
),
),
), ),
ListTile( ListTile(
trailing: Icon(Icons.bug_report_outlined), trailing: Icon(Icons.bug_report_outlined),
@ -458,12 +418,8 @@ class _SettingsState extends State<Settings> {
ListTile( ListTile(
trailing: Icon(Icons.email_outlined), trailing: Icon(Icons.email_outlined),
title: Text(L10n.of(context).passwordRecovery), title: Text(L10n.of(context).passwordRecovery),
onTap: () => Navigator.of(context).push( onTap: () =>
AppRoute.defaultRoute( AdaptivePageLayout.of(context).pushNamed('/settings/3pid'),
context,
Settings3PidView(),
),
),
), ),
ListTile( ListTile(
trailing: Icon(Icons.exit_to_app_outlined), trailing: Icon(Icons.exit_to_app_outlined),
@ -607,9 +563,7 @@ class _SettingsState extends State<Settings> {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
onTap: () => Navigator.of(context).push( onTap: () => AdaptivePageLayout.of(context).pushNamed('/logs'),
AppRoute.defaultRoute(context, LogViewer()),
),
), ),
ListTile( ListTile(
trailing: Icon(Icons.help_outlined), trailing: Icon(Icons.help_outlined),

View File

@ -1,24 +1,10 @@
import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'chat_list.dart';
class Settings3PidView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
primaryPage: FocusPage.SECOND,
firstScaffold: ChatList(),
secondScaffold: Settings3Pid(),
);
}
}
class Settings3Pid extends StatefulWidget { class Settings3Pid extends StatefulWidget {
static int sendAttempt = 0; static int sendAttempt = 0;

View File

@ -4,21 +4,8 @@ import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../components/adaptive_page_layout.dart';
import '../components/matrix.dart'; import '../components/matrix.dart';
import '../utils/date_time_extension.dart'; import '../utils/date_time_extension.dart';
import 'chat_list.dart';
class DevicesSettingsView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
primaryPage: FocusPage.SECOND,
firstScaffold: ChatList(),
secondScaffold: DevicesSettings(),
);
}
}
class DevicesSettings extends StatefulWidget { class DevicesSettings extends StatefulWidget {
@override @override

View File

@ -10,26 +10,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import '../components/adaptive_page_layout.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import '../components/matrix.dart'; import '../components/matrix.dart';
import 'chat_list.dart';
class EmotesSettingsView extends StatelessWidget {
final Room room;
final String stateKey;
EmotesSettingsView({this.room, this.stateKey});
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
primaryPage: FocusPage.SECOND,
firstScaffold: ChatList(),
secondScaffold: EmotesSettings(room: room, stateKey: stateKey),
);
}
}
class EmotesSettings extends StatefulWidget { class EmotesSettings extends StatefulWidget {
final Room room; final Room room;

View File

@ -1,23 +1,10 @@
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/avatar.dart'; import 'package:fluffychat/components/avatar.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../components/matrix.dart'; import '../components/matrix.dart';
import 'chat_list.dart';
class SettingsIgnoreListView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
primaryPage: FocusPage.SECOND,
firstScaffold: ChatList(),
secondScaffold: SettingsIgnoreList(),
);
}
}
class SettingsIgnoreList extends StatelessWidget { class SettingsIgnoreList extends StatelessWidget {
final controller = TextEditingController(); final controller = TextEditingController();

View File

@ -1,33 +1,17 @@
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:fluffychat/components/matrix.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../components/adaptive_page_layout.dart';
import '../utils/app_route.dart';
import 'chat_list.dart';
import 'settings_emotes.dart';
class MultipleEmotesSettingsView extends StatelessWidget {
final Room room;
MultipleEmotesSettingsView({this.room});
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
primaryPage: FocusPage.SECOND,
firstScaffold: ChatList(),
secondScaffold: MultipleEmotesSettings(room: room),
);
}
}
class MultipleEmotesSettings extends StatelessWidget { class MultipleEmotesSettings extends StatelessWidget {
final Room room; final String roomId;
MultipleEmotesSettings({this.room}); MultipleEmotesSettings(this.roomId, {Key key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final room = Matrix.of(context).client.getRoomById(roomId);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(L10n.of(context).emotePacks), title: Text(L10n.of(context).emotePacks),
@ -58,11 +42,9 @@ class MultipleEmotesSettings extends StatelessWidget {
return ListTile( return ListTile(
title: Text(packName), title: Text(packName),
onTap: () async { onTap: () async {
await Navigator.of(context).push( await AdaptivePageLayout.of(context).pushNamed(
AppRoute.defaultRoute( '/settings/emotes',
context, arguments: room,
EmotesSettingsView(room: room, stateKey: keys[i]),
),
); );
}, },
); );

View File

@ -1,7 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/app_config.dart'; import 'package:fluffychat/app_config.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -11,7 +10,6 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:open_noti_settings/open_noti_settings.dart'; import 'package:open_noti_settings/open_noti_settings.dart';
import '../components/matrix.dart'; import '../components/matrix.dart';
import 'chat_list.dart';
class NotificationSettingsItem { class NotificationSettingsItem {
final PushRuleKind type; final PushRuleKind type;
@ -20,17 +18,6 @@ class NotificationSettingsItem {
NotificationSettingsItem(this.type, this.key, this.title); NotificationSettingsItem(this.type, this.key, this.title);
} }
class SettingsNotificationsView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
primaryPage: FocusPage.SECOND,
firstScaffold: ChatList(),
secondScaffold: SettingsNotifications(),
);
}
}
class SettingsNotifications extends StatelessWidget { class SettingsNotifications extends StatelessWidget {
static List<NotificationSettingsItem> items = [ static List<NotificationSettingsItem> items = [
NotificationSettingsItem( NotificationSettingsItem(

View File

@ -1,25 +1,12 @@
import 'dart:io'; import 'dart:io';
import 'package:adaptive_theme/adaptive_theme.dart'; import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/config/setting_keys.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import '../components/matrix.dart'; import '../components/matrix.dart';
import 'chat_list.dart';
class SettingsStyleView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AdaptivePageLayout(
primaryPage: FocusPage.SECOND,
firstScaffold: ChatList(),
secondScaffold: SettingsStyle(),
);
}
}
class SettingsStyle extends StatefulWidget { class SettingsStyle extends StatefulWidget {
@override @override

View File

@ -1,12 +1,10 @@
import 'dart:math'; import 'dart:math';
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:file_picker_cross/file_picker_cross.dart'; import 'package:file_picker_cross/file_picker_cross.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/views/login.dart';
import 'package:fluffychat/views/sign_up_password.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -61,11 +59,9 @@ class _SignUpState extends State<SignUp> {
return setState(() => loading = false); return setState(() => loading = false);
} }
setState(() => loading = false); setState(() => loading = false);
await Navigator.of(context).push( await AdaptivePageLayout.of(context).pushNamed(
AppRoute( '/signup/password/${Uri.encodeComponent(preferredUsername)}/${Uri.encodeComponent(usernameController.text)}',
SignUpPassword(preferredUsername, arguments: avatar,
avatar: avatar, displayname: usernameController.text),
),
); );
} }
@ -171,9 +167,8 @@ class _SignUpState extends State<SignUp> {
fontSize: 16, fontSize: 16,
), ),
), ),
onPressed: () => Navigator.of(context).push( onPressed: () =>
AppRoute(Login()), AdaptivePageLayout.of(context).pushNamed('/login'),
),
), ),
), ),
]), ]),

View File

@ -1,16 +1,13 @@
import 'dart:math'; import 'dart:math';
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:flushbar/flushbar_helper.dart'; import 'package:flushbar/flushbar_helper.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/views/auth_web_view.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'chat_list.dart';
class SignUpPassword extends StatefulWidget { class SignUpPassword extends StatefulWidget {
final MatrixFile avatar; final MatrixFile avatar;
final String username; final String username;
@ -69,18 +66,12 @@ class _SignUpPasswordState extends State<SignUpPassword> {
), ),
); );
} else { } else {
await Navigator.of(context).push( await AdaptivePageLayout.of(context).pushNamed(
AppRoute.defaultRoute( '/authwebview',
context, arguments: () => _signUpAction(
AuthWebView(
currentStage,
exception.session,
() => _signUpAction(
context, context,
auth: AuthenticationData(session: exception.session), auth: AuthenticationData(session: exception.session),
), ),
),
),
); );
return; return;
} }
@ -111,9 +102,7 @@ class _SignUpPasswordState extends State<SignUpPassword> {
.show(context); .show(context);
} }
} }
await Navigator.of(context).pushAndRemoveUntil( if (mounted) setState(() => loading = false);
AppRoute.defaultRoute(context, ChatListView()), (r) => false);
setState(() => loading = false);
} }
@override @override