Merge branch 'krille/enhance-config' into 'main'

feat: Enhanced configuration

See merge request ChristianPauly/fluffychat-flutter!306
This commit is contained in:
Christian Pauly 2020-12-11 16:57:31 +00:00
commit 240fcfb788
22 changed files with 191 additions and 236 deletions

View File

@ -67,6 +67,8 @@ sudo apt install ninja-build
* Enable web support in Flutter: https://flutter.dev/docs/get-started/web * Enable web support in Flutter: https://flutter.dev/docs/get-started/web
* Optionally edit the file `lib/app_config.dart`. If you e.g. only want to change the default homeserver, then only modify the `defaultHomeserver` key.
* Build with: * Build with:
```bash ```bash
./scripts/prepare-web.sh ./scripts/prepare-web.sh
@ -75,11 +77,6 @@ flutter pub get
flutter build web --release --verbose flutter build web --release --verbose
``` ```
* Optionally configure by serving a `config.json` at the same path as fluffychat.
An example can be found at `config.sample.json`. None of these
values have to exist, the ones stated here are the default ones. If you e.g. only want
to change the default homeserver, then only modify the `default_homeserver` key.
### Desktop (Linux, Windows, macOS) ### Desktop (Linux, Windows, macOS)
* Enable Desktop support in Flutter: https://flutter.dev/desktop * Enable Desktop support in Flutter: https://flutter.dev/desktop

View File

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

@ -1,11 +0,0 @@
{
"application_name": "FluffyChat",
"default_homeserver": "matrix.tchncsde",
"privacy_url": "https://fluffychat.im/en/privacy.html",
"source_code_url": "https://gitlab.com/ChristianPauly/fluffychat-flutter",
"support_url": "https://gitlab.com/ChristianPauly/fluffychat-flutter/issues",
"sentry_dns": "https://8591d0d863b646feb4f3dda7e5dcab38@o256755.ingest.sentry.io/5243143",
"render_html": false,
"hide_redacted_events": false,
"hide_unknown_events": false
}

27
lib/app_config.dart Normal file
View File

@ -0,0 +1,27 @@
abstract class AppConfig {
static const String applicationName = 'FluffyChat';
static const String applicationWelcomeMessage = null;
static const String defaultHomeserver = 'matrix.org';
static String jitsiInstance = 'https://meet.jit.si/';
static const bool allowOtherHomeservers = true;
static const bool enableRegistration = true;
static const String privacyUrl = 'https://fluffychat.im/en/privacy.html';
static const String sourceCodeUrl =
'https://gitlab.com/ChristianPauly/fluffychat-flutter';
static const String supportUrl =
'https://gitlab.com/ChristianPauly/fluffychat-flutter/issues';
static const bool enableSentry = true;
static const String sentryDns =
'https://8591d0d863b646feb4f3dda7e5dcab38@o256755.ingest.sentry.io/5243143';
static bool renderHtml = false;
static bool hideRedactedEvents = false;
static bool hideUnknownEvents = false;
static const String inviteLinkPrefix = 'https://matrix.to/#/';
static const String pushNotificationsChannelId = 'fluffychat_push';
static const String pushNotificationsChannelName = 'FluffyChat push channel';
static const String pushNotificationsChannelDescription =
'Push notifications for FluffyChat';
static const String pushNotificationsAppId = 'chat.fluffy.fluffychat';
static const String pushNotificationsGatewayUrl = 'https://janian.de:7023/';
static const String pushNotificationsPusherFormat = 'event_id_only';
}

View File

@ -9,6 +9,7 @@ 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';
import '../app_config.dart';
import 'dialogs/simple_dialogs.dart'; import 'dialogs/simple_dialogs.dart';
import 'matrix.dart'; import 'matrix.dart';
@ -33,7 +34,7 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
void startCallAction(BuildContext context) async { void startCallAction(BuildContext context) async {
final url = final url =
'${Matrix.of(context).jitsiInstance}${Uri.encodeComponent(widget.room.id.localpart)}'; '${AppConfig.jitsiInstance}${Uri.encodeComponent(widget.room.id.localpart)}';
final success = await SimpleDialogs(context) final success = await SimpleDialogs(context)
.tryRequestWithLoadingDialog(widget.room.sendEvent({ .tryRequestWithLoadingDialog(widget.room.sendEvent({
'msgtype': Matrix.callNamespace, 'msgtype': Matrix.callNamespace,

View File

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:convert';
import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:famedlysdk/encryption.dart'; import 'package:famedlysdk/encryption.dart';
@ -17,9 +16,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:universal_html/prefer_universal/html.dart' as html; import 'package:universal_html/prefer_universal/html.dart' as html;
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:path_provider/path_provider.dart';
/*import 'package:fluffychat/views/chat.dart'; /*import 'package:fluffychat/views/chat.dart';
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/app_config.dart';
import 'package:dbus/dbus.dart'; import 'package:dbus/dbus.dart';
import 'package:desktop_notifications/desktop_notifications.dart';*/ import 'package:desktop_notifications/desktop_notifications.dart';*/
@ -27,22 +25,16 @@ import '../utils/beautify_string_extension.dart';
import '../utils/famedlysdk_store.dart'; import '../utils/famedlysdk_store.dart';
import 'dialogs/key_verification_dialog.dart'; import 'dialogs/key_verification_dialog.dart';
import '../utils/platform_infos.dart'; import '../utils/platform_infos.dart';
import '../config/app_config.dart'; import '../app_config.dart';
import '../config/setting_keys.dart'; import '../config/setting_keys.dart';
import 'avatar.dart'; import 'avatar.dart';
import 'package:http/http.dart' as http;
class Matrix extends StatefulWidget { class Matrix extends StatefulWidget {
static const String callNamespace = 'chat.fluffy.jitsi_call'; static const String callNamespace = 'chat.fluffy.jitsi_call';
final Widget child; final Widget child;
final String clientName; Matrix({this.child, Key key}) : super(key: key);
final Store store;
Matrix({this.child, this.clientName, this.store, Key key}) : super(key: key);
@override @override
MatrixState createState() => MatrixState(); MatrixState createState() => MatrixState();
@ -58,7 +50,7 @@ class Matrix extends StatefulWidget {
class MatrixState extends State<Matrix> { class MatrixState extends State<Matrix> {
Client client; Client client;
Store store; Store store = Store();
@override @override
BuildContext context; BuildContext context;
@ -77,13 +69,12 @@ class MatrixState extends State<Matrix> {
String activeRoomId; String activeRoomId;
File wallpaper; File wallpaper;
String clientName;
String jitsiInstance = 'https://meet.jit.si/';
void clean() async { void clean() async {
if (!kIsWeb) return; if (!kIsWeb) return;
await store.deleteItem(widget.clientName); await store.deleteItem(clientName);
} }
void _initWithStore() async { void _initWithStore() async {
@ -96,7 +87,7 @@ class MatrixState extends State<Matrix> {
if (PlatformInfos.isMobile) { if (PlatformInfos.isMobile) {
await FirebaseController.setupFirebase( await FirebaseController.setupFirebase(
this, this,
widget.clientName, clientName,
); );
} }
} }
@ -284,38 +275,11 @@ class MatrixState extends State<Matrix> {
void initState() { void initState() {
super.initState(); super.initState();
initMatrix(); initMatrix();
initConfig().then((_) => initSettings());
}
Future<void> initConfig() async {
if (PlatformInfos.isMobile) {
return;
}
try {
var configJsonString = '';
if (PlatformInfos.isWeb) {
configJsonString =
utf8.decode((await http.get('config.json')).bodyBytes);
} else if (PlatformInfos.isBetaDesktop) {
final appDocDir = await getApplicationSupportDirectory();
configJsonString =
await File('${appDocDir.path}/config.json').readAsString();
} else {
final appDocDir = await getApplicationDocumentsDirectory();
configJsonString =
await File('${appDocDir.path}/config.json').readAsString();
}
final configJson = json.decode(configJsonString);
AppConfig.loadFromJson(configJson);
} catch (error) {
debugPrint(
'[ConfigLoader] Failed to load config.json: ' + error.toString());
}
} }
void initMatrix() { void initMatrix() {
store = widget.store ?? Store(); clientName =
'${AppConfig.applicationName} ${kIsWeb ? 'Web' : Platform.operatingSystem}';
final Set verificationMethods = <KeyVerificationMethod>{ final Set verificationMethods = <KeyVerificationMethod>{
KeyVerificationMethod.numbers KeyVerificationMethod.numbers
}; };
@ -324,7 +288,7 @@ class MatrixState extends State<Matrix> {
verificationMethods.add(KeyVerificationMethod.emoji); verificationMethods.add(KeyVerificationMethod.emoji);
} }
client = Client( client = Client(
widget.clientName, clientName,
enableE2eeRecovery: true, enableE2eeRecovery: true,
verificationMethods: verificationMethods, verificationMethods: verificationMethods,
importantStateEvents: <String>{ importantStateEvents: <String>{
@ -405,13 +369,13 @@ class MatrixState extends State<Matrix> {
.listen(_showLocalNotification); .listen(_showLocalNotification);
}); });
} }
initSettings();
} }
void initSettings() { void initSettings() {
if (store != null) { if (store != null) {
store store.getItem(SettingKeys.jitsiInstance).then((final instance) =>
.getItem(SettingKeys.jitsiInstance) AppConfig.jitsiInstance = instance ?? AppConfig.jitsiInstance);
.then((final instance) => jitsiInstance = instance ?? jitsiInstance);
store.getItem(SettingKeys.wallpaper).then((final path) async { store.getItem(SettingKeys.wallpaper).then((final path) async {
if (path == null) return; if (path == null) return;
final file = File(path); final file = File(path);

View File

@ -13,7 +13,7 @@ import 'package:matrix_link_text/link_text.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../utils/url_launcher.dart'; import '../utils/url_launcher.dart';
import '../config/app_config.dart'; import '../app_config.dart';
import 'html_message.dart'; import 'html_message.dart';
import 'matrix.dart'; import 'matrix.dart';
import 'message_download_content.dart'; import 'message_download_content.dart';

View File

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'html_message.dart'; import 'html_message.dart';
import '../config/app_config.dart'; import '../app_config.dart';
class ReplyContent extends StatelessWidget { class ReplyContent extends StatelessWidget {
final Event replyEvent; final Event replyEvent;

View File

@ -1,52 +0,0 @@
abstract class AppConfig {
static String get applicationName => _applicationName;
static String _applicationName = 'FluffyChat';
static String get defaultHomeserver => _defaultHomeserver;
static String _defaultHomeserver = 'matrix-client.matrix.org';
static String get privacyUrl => _privacyUrl;
static String _privacyUrl = 'https://fluffychat.im/en/privacy.html';
static String get sourceCodeUrl => _sourceCodeUrl;
static String _sourceCodeUrl =
'https://gitlab.com/ChristianPauly/fluffychat-flutter';
static String get supportUrl => _supportUrl;
static String _supportUrl =
'https://gitlab.com/ChristianPauly/fluffychat-flutter/issues';
static String get sentryDsn => _sentryDsn;
static String _sentryDsn =
'https://8591d0d863b646feb4f3dda7e5dcab38@o256755.ingest.sentry.io/5243143';
// these settings can be re-set at runtime depending on what the in-app settings are
static bool renderHtml = false;
static bool hideRedactedEvents = false;
static bool hideUnknownEvents = false;
static String matrixToLinkPrefix = 'https://matrix.to/#/';
static void loadFromJson(Map<String, dynamic> json) {
if (json['application_name'] is String) {
_applicationName = json['application_name'];
}
if (json['default_homeserver'] is String) {
_defaultHomeserver = json['default_homeserver'];
}
if (json['privacy_url'] is String) {
_privacyUrl = json['privacy_url'];
}
if (json['source_code_url'] is String) {
_sourceCodeUrl = json['source_code_url'];
}
if (json['support_url'] is String) {
_supportUrl = json['support_url'];
}
if (json['sentry_dsn'] is String) {
_sentryDsn = json['sentry_dsn'];
}
if (json['render_html'] is bool) {
renderHtml = json['render_html'];
}
if (json['hide_redacted_events'] is bool) {
hideRedactedEvents = json['hide_redacted_events'];
}
if (json['hide_unknown_events'] is bool) {
hideUnknownEvents = json['hide_unknown_events'];
}
}
}

View File

@ -1,5 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/utils/sentry_controller.dart'; import 'package:fluffychat/utils/sentry_controller.dart';
@ -13,9 +12,10 @@ import 'package:universal_html/prefer_universal/html.dart' as html;
import 'components/matrix.dart'; import 'components/matrix.dart';
import 'components/theme_switcher.dart'; import 'components/theme_switcher.dart';
import 'app_config.dart';
import 'views/chat_list.dart'; import 'views/chat_list.dart';
void main() { void main() async {
SystemChrome.setSystemUIOverlayStyle( SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: Colors.transparent)); SystemUiOverlayStyle(statusBarColor: Colors.transparent));
FlutterError.onError = (FlutterErrorDetails details) => FlutterError.onError = (FlutterErrorDetails details) =>
@ -27,49 +27,50 @@ void main() {
} }
class App extends StatelessWidget { class App extends StatelessWidget {
final String platform = kIsWeb ? 'Web' : Platform.operatingSystem;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Matrix( return Matrix(
clientName: 'FluffyChat $platform',
child: Builder( child: Builder(
builder: (BuildContext context) => ThemeSwitcherWidget( builder: (BuildContext context) => ThemeSwitcherWidget(
child: Builder( child: Builder(
builder: (BuildContext context) => MaterialApp( builder: (context) => MaterialApp(
title: 'FluffyChat', title: '${AppConfig.applicationName}',
theme: ThemeSwitcherWidget.of(context).themeData, theme: ThemeSwitcherWidget.of(context).themeData,
localizationsDelegates: L10n.localizationsDelegates, localizationsDelegates: L10n.localizationsDelegates,
supportedLocales: L10n.supportedLocales, supportedLocales: L10n.supportedLocales,
locale: kIsWeb locale: kIsWeb
? Locale(html.window.navigator.language.split('-').first) ? Locale(
: null, html.window.navigator.language.split('-').first)
home: FutureBuilder<LoginState>( : null,
future: home: FutureBuilder<LoginState>(
Matrix.of(context).client.onLoginStateChanged.stream.first, future: Matrix.of(context)
builder: (context, snapshot) { .client
if (snapshot.hasError) { .onLoginStateChanged
WidgetsBinding.instance .stream
.addPostFrameCallback((_) => FlushbarHelper.createError( .first,
title: L10n.of(context).oopsSomethingWentWrong, builder: (context, snapshot) {
message: snapshot.error.toString(), if (snapshot.hasError) {
).show(context)); WidgetsBinding.instance.addPostFrameCallback((_) =>
return HomeserverPicker(); FlushbarHelper.createError(
} title: L10n.of(context).oopsSomethingWentWrong,
if (!snapshot.hasData) { message: snapshot.error.toString(),
return Scaffold( ).show(context));
body: Center( return HomeserverPicker();
child: CircularProgressIndicator(), }
), if (!snapshot.hasData) {
); return Scaffold(
} body: Center(
if (Matrix.of(context).client.isLogged()) { child: CircularProgressIndicator(),
return ChatListView(); ),
} );
return HomeserverPicker(); }
}, if (Matrix.of(context).client.isLogged()) {
), return ChatListView();
), }
), return HomeserverPicker();
},
),
)),
), ),
), ),
); );

View File

@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:fluffychat/app_config.dart';
import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/platform_infos.dart';
import 'package:flushbar/flushbar_helper.dart'; import 'package:flushbar/flushbar_helper.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
@ -25,12 +26,6 @@ abstract class FirebaseController {
static final FlutterLocalNotificationsPlugin static final FlutterLocalNotificationsPlugin
_flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
static BuildContext context; static BuildContext context;
static const String CHANNEL_ID = 'fluffychat_push';
static const String CHANNEL_NAME = 'FluffyChat push channel';
static const String CHANNEL_DESCRIPTION = 'Push notifications for FluffyChat';
static const String APP_ID = 'chat.fluffy.fluffychat';
static const String GATEWAY_URL = 'https://janian.de:7023/';
static const String PUSHER_FORMAT = 'event_id_only';
static Future<void> setupFirebase( static Future<void> setupFirebase(
MatrixState matrix, String clientName) async { MatrixState matrix, String clientName) async {
@ -65,12 +60,14 @@ abstract class FirebaseController {
final currentPushers = pushers.where((pusher) => pusher.pushkey == token); final currentPushers = pushers.where((pusher) => pusher.pushkey == token);
if (currentPushers.length == 1 && if (currentPushers.length == 1 &&
currentPushers.first.kind == 'http' && currentPushers.first.kind == 'http' &&
currentPushers.first.appId == APP_ID && currentPushers.first.appId == AppConfig.pushNotificationsAppId &&
currentPushers.first.appDisplayName == clientName && currentPushers.first.appDisplayName == clientName &&
currentPushers.first.deviceDisplayName == client.deviceName && currentPushers.first.deviceDisplayName == client.deviceName &&
currentPushers.first.lang == 'en' && currentPushers.first.lang == 'en' &&
currentPushers.first.data.url.toString() == GATEWAY_URL && currentPushers.first.data.url.toString() ==
currentPushers.first.data.format == PUSHER_FORMAT) { AppConfig.pushNotificationsGatewayUrl &&
currentPushers.first.data.format ==
AppConfig.pushNotificationsPusherFormat) {
debugPrint('[Push] Pusher already set'); debugPrint('[Push] Pusher already set');
} else { } else {
if (currentPushers.isNotEmpty) { if (currentPushers.isNotEmpty) {
@ -88,13 +85,13 @@ abstract class FirebaseController {
.setPusher( .setPusher(
Pusher( Pusher(
token, token,
APP_ID, AppConfig.pushNotificationsAppId,
clientName, clientName,
client.deviceName, client.deviceName,
'en', 'en',
PusherData( PusherData(
url: Uri.parse(GATEWAY_URL), url: Uri.parse(AppConfig.pushNotificationsGatewayUrl),
format: PUSHER_FORMAT, format: AppConfig.pushNotificationsPusherFormat,
), ),
kind: 'http', kind: 'http',
), ),
@ -255,7 +252,9 @@ abstract class FirebaseController {
// Show notification // Show notification
var androidPlatformChannelSpecifics = AndroidNotificationDetails( var androidPlatformChannelSpecifics = AndroidNotificationDetails(
CHANNEL_ID, CHANNEL_NAME, CHANNEL_DESCRIPTION, AppConfig.pushNotificationsChannelId,
AppConfig.pushNotificationsChannelName,
AppConfig.pushNotificationsChannelDescription,
styleInformation: MessagingStyleInformation( styleInformation: MessagingStyleInformation(
person, person,
conversationTitle: title, conversationTitle: title,
@ -328,8 +327,11 @@ abstract class FirebaseController {
// Display notification // Display notification
var androidPlatformChannelSpecifics = AndroidNotificationDetails( var androidPlatformChannelSpecifics = AndroidNotificationDetails(
CHANNEL_ID, CHANNEL_NAME, CHANNEL_DESCRIPTION, AppConfig.pushNotificationsChannelId,
importance: Importance.max, priority: Priority.high); AppConfig.pushNotificationsChannelName,
AppConfig.pushNotificationsChannelDescription,
importance: Importance.max,
priority: Priority.high);
var iOSPlatformChannelSpecifics = IOSNotificationDetails(); var iOSPlatformChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails( var platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics, android: androidPlatformChannelSpecifics,

View File

@ -1,6 +1,6 @@
import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:flushbar/flushbar_helper.dart'; import 'package:flushbar/flushbar_helper.dart';
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/app_config.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -11,6 +11,7 @@ import '../config/setting_keys.dart';
abstract class SentryController { abstract class SentryController {
static Future<void> toggleSentryAction(BuildContext context) async { static Future<void> toggleSentryAction(BuildContext context) async {
if (!AppConfig.enableSentry) return;
final enableSentry = await showOkCancelAlertDialog( final enableSentry = await showOkCancelAlertDialog(
context: context, context: context,
title: L10n.of(context).sendBugReports, title: L10n.of(context).sendBugReports,
@ -28,11 +29,12 @@ abstract class SentryController {
} }
static Future<bool> getSentryStatus() async { static Future<bool> getSentryStatus() async {
if (!AppConfig.enableSentry) return false;
final storage = Store(); final storage = Store();
return await storage.getItemBool(SettingKeys.sentry); return await storage.getItemBool(SettingKeys.sentry);
} }
static final sentry = SentryClient(dsn: AppConfig.sentryDsn); static final sentry = SentryClient(dsn: AppConfig.sentryDns);
static void captureException(error, stackTrace) async { static void captureException(error, stackTrace) async {
debugPrint(error.toString()); debugPrint(error.toString());

View File

@ -2,7 +2,7 @@ import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/app_config.dart';
import 'package:fluffychat/utils/app_route.dart'; import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/views/chat.dart'; import 'package:fluffychat/views/chat.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -15,7 +15,7 @@ class UrlLauncher {
const UrlLauncher(this.context, this.url); const UrlLauncher(this.context, this.url);
void launchUrl() { void launchUrl() {
if (url.startsWith(AppConfig.matrixToLinkPrefix) || if (url.startsWith(AppConfig.inviteLinkPrefix) ||
{'#', '@', '!', '+', '\$'}.contains(url[0])) { {'#', '@', '!', '+', '\$'}.contains(url[0])) {
return openMatrixToUrl(); return openMatrixToUrl();
} }
@ -24,7 +24,7 @@ class UrlLauncher {
void openMatrixToUrl() async { void openMatrixToUrl() async {
final matrix = Matrix.of(context); final matrix = Matrix.of(context);
final identifier = url.replaceAll(AppConfig.matrixToLinkPrefix, ''); final identifier = url.replaceAll(AppConfig.inviteLinkPrefix, '');
if (identifier[0] == '#' || identifier[0] == '!') { if (identifier[0] == '#' || identifier[0] == '!') {
// sometimes we have identifiers which have an event id and additional query parameters // sometimes we have identifiers which have an event id and additional query parameters
// we want to separate those. // we want to separate those.

View File

@ -33,7 +33,7 @@ import 'package:swipe_to_action/swipe_to_action.dart';
import '../components/dialogs/send_file_dialog.dart'; import '../components/dialogs/send_file_dialog.dart';
import '../components/input_bar.dart'; import '../components/input_bar.dart';
import '../config/app_config.dart'; import '../app_config.dart';
import '../utils/matrix_file_extension.dart'; import '../utils/matrix_file_extension.dart';
import 'chat_details.dart'; import 'chat_details.dart';
import 'chat_list.dart'; import 'chat_list.dart';

View File

@ -1,5 +1,5 @@
import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/app_config.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:fluffychat/views/chat_permissions_settings.dart';
import 'package:flushbar/flushbar_helper.dart'; import 'package:flushbar/flushbar_helper.dart';
@ -202,7 +202,7 @@ class _ChatDetailsState extends State<ChatDetails> {
IconButton( IconButton(
icon: Icon(Icons.share_outlined), icon: Icon(Icons.share_outlined),
onPressed: () => FluffyShare.share( onPressed: () => FluffyShare.share(
AppConfig.matrixToLinkPrefix + AppConfig.inviteLinkPrefix +
widget.room.canonicalAlias, widget.room.canonicalAlias,
context), context),
), ),

View File

@ -7,7 +7,7 @@ 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';
import 'package:fluffychat/components/default_drawer.dart'; import 'package:fluffychat/components/default_drawer.dart';
import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart';
import 'package:fluffychat/config/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:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -105,7 +105,7 @@ class _ChatListState extends State<ChatList> {
if (Navigator.of(context).canPop()) { if (Navigator.of(context).canPop()) {
Navigator.of(context).popUntil((r) => r.isFirst); Navigator.of(context).popUntil((r) => r.isFirst);
} }
if (text.startsWith(AppConfig.matrixToLinkPrefix)) { if (text.startsWith(AppConfig.inviteLinkPrefix)) {
UrlLauncher(context, text).openMatrixToUrl(); UrlLauncher(context, text).openMatrixToUrl();
return; return;
} }

View File

@ -4,7 +4,7 @@ import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/config/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/app_route.dart';
import 'package:fluffychat/utils/sentry_controller.dart'; import 'package:fluffychat/utils/sentry_controller.dart';
@ -12,6 +12,8 @@ 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://';
@ -42,7 +44,8 @@ class HomeserverPicker extends StatelessWidget {
final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( final success = await SimpleDialogs(context).tryRequestWithLoadingDialog(
checkHomeserver(homeserver, Matrix.of(context).client)); checkHomeserver(homeserver, Matrix.of(context).client));
if (success == true) { if (success == true) {
await Navigator.of(context).push(AppRoute(SignUp())); await Navigator.of(context)
.push(AppRoute(AppConfig.enableRegistration ? SignUp() : Login()));
} }
} }
@ -61,35 +64,42 @@ class HomeserverPicker extends StatelessWidget {
max((MediaQuery.of(context).size.width - 600) / 2, 0)), max((MediaQuery.of(context).size.width - 600) / 2, 0)),
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Hero( Expanded(
tag: 'loginBanner', child: ListView(
child: InkWell( children: [
onTap: () => showAboutDialog( Hero(
context: context, tag: 'loginBanner',
children: [ child: InkWell(
RaisedButton( onTap: () => showAboutDialog(
child: Text(L10n.of(context).privacy), context: context,
onPressed: () => launch(AppConfig.privacyUrl), children: [
) RaisedButton(
], child: Text(L10n.of(context).privacy),
applicationIcon: onPressed: () => launch(AppConfig.privacyUrl),
Image.asset('assets/logo.png', width: 100, height: 100), )
applicationName: AppConfig.applicationName, ],
), applicationIcon: Image.asset('assets/logo.png',
child: Image.asset('assets/fluffychat-banner.png'), width: 100, height: 100),
applicationName: AppConfig.applicationName,
),
child: Image.asset('assets/banner.png'),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
AppConfig.applicationWelcomeMessage ??
L10n.of(context).welcomeText,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
),
),
),
],
), ),
), ),
Padding( SizedBox(height: 16),
padding: const EdgeInsets.all(16.0),
child: Text(
L10n.of(context).welcomeText,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
),
),
),
Spacer(),
Hero( Hero(
tag: 'loginButton', tag: 'loginButton',
child: Container( child: Container(
@ -123,16 +133,31 @@ class HomeserverPicker extends StatelessWidget {
), ),
), ),
), ),
FlatButton( Wrap(
child: Text( children: [
L10n.of(context).changeTheHomeserver, if (AppConfig.allowOtherHomeservers)
style: TextStyle( FlatButton(
decoration: TextDecoration.underline, child: Text(
color: Colors.blue, L10n.of(context).changeTheHomeserver,
fontSize: 16, style: TextStyle(
decoration: TextDecoration.underline,
color: Theme.of(context).primaryColor,
fontSize: 16,
),
),
onPressed: () => _setHomeserverAction(context),
),
FlatButton(
child: Text(
L10n.of(context).privacy,
style: TextStyle(
decoration: TextDecoration.underline,
fontSize: 16,
),
),
onPressed: () => launch(AppConfig.privacyUrl),
), ),
), ],
onPressed: () => _setHomeserverAction(context),
), ),
SizedBox(height: 16), SizedBox(height: 16),
], ],

View File

@ -49,7 +49,7 @@ class _LoginState extends State<Login> {
await matrix.client.login( await matrix.client.login(
user: usernameController.text, user: usernameController.text,
password: passwordController.text, password: passwordController.text,
initialDeviceDisplayName: matrix.widget.clientName); initialDeviceDisplayName: matrix.clientName);
} on MatrixException catch (exception) { } on MatrixException catch (exception) {
setState(() => passwordError = exception.errorMessage); setState(() => passwordError = exception.errorMessage);
return setState(() => loading = false); return setState(() => loading = false);
@ -59,7 +59,7 @@ class _LoginState extends State<Login> {
} }
await FirebaseController.setupFirebase( await FirebaseController.setupFirebase(
matrix, matrix,
matrix.widget.clientName, matrix.clientName,
).catchError(SentryController.captureException); ).catchError(SentryController.captureException);
setState(() => loading = false); setState(() => loading = false);

View File

@ -7,7 +7,7 @@ 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/config/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_devices.dart';
@ -22,7 +22,7 @@ import '../components/content_banner.dart';
import '../components/dialogs/simple_dialogs.dart'; import '../components/dialogs/simple_dialogs.dart';
import '../components/matrix.dart'; import '../components/matrix.dart';
import '../utils/app_route.dart'; import '../utils/app_route.dart';
import '../config/app_config.dart'; import '../app_config.dart';
import '../config/setting_keys.dart'; import '../config/setting_keys.dart';
import 'app_info.dart'; import 'app_info.dart';
import 'chat_list.dart'; import 'chat_list.dart';
@ -141,8 +141,7 @@ class _SettingsState extends State<Settings> {
title: L10n.of(context).editJitsiInstance, title: L10n.of(context).editJitsiInstance,
textFields: [ textFields: [
DialogTextField( DialogTextField(
initialText: initialText: AppConfig.jitsiInstance.replaceFirst(prefix, ''),
Matrix.of(context).jitsiInstance.replaceFirst(prefix, ''),
prefixText: prefix, prefixText: prefix,
), ),
], ],
@ -154,7 +153,7 @@ class _SettingsState extends State<Settings> {
} }
final matrix = Matrix.of(context); final matrix = Matrix.of(context);
await matrix.store.setItem(SettingKeys.jitsiInstance, jitsi); await matrix.store.setItem(SettingKeys.jitsiInstance, jitsi);
matrix.jitsiInstance = jitsi; AppConfig.jitsiInstance = jitsi;
} }
void setDisplaynameAction(BuildContext context) async { void setDisplaynameAction(BuildContext context) async {
@ -411,7 +410,7 @@ class _SettingsState extends State<Settings> {
ListTile( ListTile(
trailing: Icon(Icons.phone_outlined), trailing: Icon(Icons.phone_outlined),
title: Text(L10n.of(context).editJitsiInstance), title: Text(L10n.of(context).editJitsiInstance),
subtitle: Text(Matrix.of(context).jitsiInstance), subtitle: Text(AppConfig.jitsiInstance),
onTap: () => setJitsiInstanceAction(context), onTap: () => setJitsiInstanceAction(context),
), ),
ListTile( ListTile(

View File

@ -3,7 +3,7 @@ import 'dart:io';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart'; import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart';
import 'package:fluffychat/utils/firebase_controller.dart'; import 'package:fluffychat/app_config.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';
@ -68,9 +68,9 @@ class SettingsNotifications extends StatelessWidget {
await NotificationSetting.configureChannel( await NotificationSetting.configureChannel(
NotificationDetails( NotificationDetails(
android: AndroidNotificationDetails( android: AndroidNotificationDetails(
FirebaseController.CHANNEL_ID, AppConfig.pushNotificationsChannelId,
FirebaseController.CHANNEL_NAME, AppConfig.pushNotificationsChannelName,
FirebaseController.CHANNEL_DESCRIPTION, AppConfig.pushNotificationsChannelDescription,
), ),
), ),
); );

View File

@ -90,7 +90,7 @@ class _SignUpState extends State<SignUp> {
children: <Widget>[ children: <Widget>[
Hero( Hero(
tag: 'loginBanner', tag: 'loginBanner',
child: Image.asset('assets/fluffychat-banner.png'), child: Image.asset('assets/banner.png'),
), ),
ListTile( ListTile(
leading: CircleAvatar( leading: CircleAvatar(

View File

@ -44,7 +44,7 @@ class _SignUpPasswordState extends State<SignUpPassword> {
await matrix.client.register( await matrix.client.register(
username: widget.username, username: widget.username,
password: passwordController.text, password: passwordController.text,
initialDeviceDisplayName: matrix.widget.clientName, initialDeviceDisplayName: matrix.clientName,
auth: auth, auth: auth,
); );
await waitForLogin; await waitForLogin;