fluffychat merge

This commit is contained in:
ggurdin 2026-02-04 13:46:14 -05:00
commit 913edd9f35
No known key found for this signature in database
GPG key ID: A01CB41737CBB478
79 changed files with 1120 additions and 1046 deletions

View file

@ -17,7 +17,6 @@
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"
android:maxSdkVersion="29" />
@ -161,16 +160,6 @@
android:foregroundServiceType="camera|microphone|mediaProjection">
</service>
<service android:name="io.wazo.callkeep.VoiceConnectionService"
android:label="Wazo"
android:foregroundServiceType="camera|microphone|mediaProjection"
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
android:exported="true">
<intent-filter>
<action android:name="android.telecom.ConnectionService" />
</intent-filter>
</service>
<!-- From flutter_local_notifications package for notification actions -->
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ActionBroadcastReceiver" />

View file

@ -1,10 +1,29 @@
{
"application_name": "PangeaChat",
"application_welcome_message": null,
"default_homeserver": "matrix.pangea.chat",
"web_base_url": "https://web.pangea.chat",
"privacy_url": "https://pangea.chat/privacy",
"render_html": false,
"hide_redacted_events": false,
"hide_unknown_events": false
"applicationName": "PangeaChat",
"defaultHomeserver": "matrix.pangea.chat",
"privacyUrl": "https://pangea.chat/privacy",
"audioRecordingNumChannels": 1,
"audioRecordingAutoGain": true,
"audioRecordingEchoCancel": false,
"audioRecordingNoiseSuppress": true,
"audioRecordingBitRate": 64000,
"audioRecordingSamplingRate": 44100,
"renderHtml": true,
"fontSizeFactor": 1,
"hideRedactedEvents": false,
"hideUnknownEvents": true,
"separateChatTypes": false,
"autoplayImages": true,
"sendTypingNotifications": true,
"sendPublicReadReceipts": true,
"swipeRightToLeftToReply": true,
"sendOnEnter": false,
"showPresences": true,
"displayNavigationRail": false,
"experimentalVoip": false,
"shareKeysWith": "all",
"noEncryptionWarningShown": false,
"displayChatDetailsColumn": false,
"colorSchemeSeedInt": 4283835834,
"enableSoftLogout": false
}

View file

@ -1,4 +1,3 @@
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/pages/chat/chat_view.dart';
import 'package:fluffychat/pages/chat_list/chat_list_body.dart';
import 'package:fluffychat/pages/chat_list/search_title.dart';
@ -25,7 +24,7 @@ void main() {
() async {
// this random dialog popping up is super hard to cover in tests
SharedPreferences.setMockInitialValues({
SettingKeys.showNoGoogle: false,
'chat.fluffy.show_no_google': false,
});
},
);

View file

@ -2,97 +2,41 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
abstract class AppConfig {
// #Pangea
// static String _applicationName = 'FluffyChat';
static String _applicationName = 'Pangea Chat';
static String get defaultHomeserver => Environment.synapseURL;
// Pangea#
// Const and final configuration values (immutable)
// #Pangea
static String get applicationName => _applicationName;
static String? _applicationWelcomeMessage;
static String? get applicationWelcomeMessage => _applicationWelcomeMessage;
// #Pangea
// static String _defaultHomeserver = 'matrix.org';
static String get _defaultHomeserver => Environment.synapseURL;
// static const Color primaryColor = Color(0xFF5625BA);
// static const Color primaryColorLight = Color(0xFFCCBDEA);
// static const Color secondaryColor = Color(0xFF41a2bc);
static const Color primaryColor = Color(0xFF8560E0);
static const Color primaryColorLight = Color(0xFFDBC9FF);
static const Color secondaryColor = Color.fromARGB(255, 253, 191, 1);
// Pangea#
static String get defaultHomeserver => _defaultHomeserver;
static double fontSizeFactor = 1;
static const Color chatColor = primaryColor;
static Color? colorSchemeSeed = primaryColor;
static const double messageFontSize = 16.0;
static const bool allowOtherHomeservers = true;
static const bool enableRegistration = true;
static const bool hideTypingUsernames = false;
static const String inviteLinkPrefix = 'https://matrix.to/#/';
static const String deepLinkPrefix = 'im.fluffychat://chat/';
static const String schemePrefix = 'matrix:';
// #Pangea
static const double toolbarMaxHeight = 250.0;
static const double toolbarMinHeight = 150.0;
static const double toolbarMinWidth = 350.0;
static const double toolbarMenuHeight = 50.0;
static const double defaultHeaderHeight = 56.0;
static const double toolbarButtonsHeight = 50.0;
static const double toolbarSpacing = 8.0;
static const double toolbarIconSize = 24.0;
static const double readingAssistanceInputBarHeight = 175.0;
static const double reactionsPickerHeight = 48.0;
static const double chatInputRowOverlayPadding = 8.0;
static const double selectModeInputBarHeight = 0;
// reactionsPickerHeight + (chatInputRowOverlayPadding * 2) + toolbarSpacing;
static const double practiceModeInputBarHeight =
readingAssistanceInputBarHeight +
toolbarButtonsHeight +
(chatInputRowOverlayPadding * 2) +
toolbarSpacing;
// static const String pushNotificationsChannelId = 'fluffychat_push';
// static const String pushNotificationsAppId = 'chat.fluffy.fluffychat';
static const String pushNotificationsChannelId = 'pangeachat_push';
static const String pushNotificationsAppId = 'com.talktolearn.chat';
// Pangea#
static const double borderRadius = 18.0;
static const double columnWidth = 360.0;
static TextStyle messageTextStyle(
Event? event,
Color textColor,
) {
final fontSize = messageFontSize * fontSizeFactor;
final bigEmotes = event != null &&
event.onlyEmotes &&
event.numberEmotes > 0 &&
event.numberEmotes <= 3;
return TextStyle(
color: textColor,
fontSize: bigEmotes ? fontSize * 5 : fontSize,
decoration:
(event?.redacted ?? false) ? TextDecoration.lineThrough : null,
height: 1.3,
);
}
// static const Color primaryColor = Color(0xFF5625BA);
// static const Color primaryColorLight = Color(0xFFCCBDEA);
static const Color primaryColor = Color(0xFF8560E0);
static const Color primaryColorLight = Color(0xFFDBC9FF);
// static const Color secondaryColor = Color(0xFF41a2bc);
static const Color secondaryColor = Color.fromARGB(255, 253, 191, 1);
static const Color activeToggleColor = Color(0xFF33D057);
static const Color success = Color(0xFF33D057);
static const Color warning = Color.fromARGB(255, 210, 124, 12);
static const Color gold = Color.fromARGB(255, 253, 191, 1);
static const Color silver = Color.fromARGB(255, 192, 192, 192);
static const Color bronze = Color.fromARGB(255, 205, 127, 50);
static const Color goldLight = Color.fromARGB(255, 254, 223, 73);
static const Color yellowLight = Color.fromARGB(255, 247, 218, 120);
static const Color yellowDark = Color.fromARGB(255, 253, 191, 1);
static const Color error = Colors.red;
static const int overlayAnimationDuration = 250;
static const int roomCreationTimeoutSeconds = 15;
// static String _privacyUrl =
// 'https://gitlab.com/famedly/fluffychat/-/blob/main/PRIVACY.md';
static String _privacyUrl = "https://www.pangeachat.com/privacy";
//Pangea#
static const Set<String> defaultReactions = {'👍', '❤️', '😂', '😮', '😢'};
static String get privacyUrl => _privacyUrl;
// #Pangea
// static const String website = 'https://fluffychat.im';
static const String website = "https://pangea.chat/";
@ -108,9 +52,7 @@ abstract class AppConfig {
// static const String appOpenUrlScheme = 'im.fluffychat';
static const String appOpenUrlScheme = 'matrix.pangea.chat';
// Pangea#
static String _webBaseUrl = 'https://fluffychat.im/web';
static String get webBaseUrl => _webBaseUrl;
static const String sourceCodeUrl =
'https://github.com/krille-chan/fluffychat';
// #Pangea
@ -118,126 +60,81 @@ abstract class AppConfig {
// 'https://github.com/krille-chan/fluffychat/issues';
// static const String changelogUrl =
// 'https://github.com/krille-chan/fluffychat/blob/main/CHANGELOG.md';
// static const String donationUrl = 'https://ko-fi.com/krille';
static const String supportUrl = 'https://www.pangeachat.com/faqs';
static const String termsOfServiceUrl =
'https://www.pangeachat.com/terms-of-service';
// Pangea#
static const Set<String> defaultReactions = {'👍', '❤️', '😂', '😮', '😢'};
static final Uri newIssueUrl = Uri(
scheme: 'https',
host: 'github.com',
path: '/krille-chan/fluffychat/issues/new',
);
// #Pangea
static const bool enableSentry = true;
static const String sentryDns =
'https://8591d0d863b646feb4f3dda7e5dcab38@o256755.ingest.sentry.io/5243143';
// Pangea#
static bool renderHtml = true;
// #Pangea
// static bool hideRedactedEvents = false;
static bool hideRedactedEvents = true;
// Pangea#
static bool hideUnknownEvents = true;
static bool separateChatTypes = false;
static bool autoplayImages = true;
static bool sendTypingNotifications = true;
static bool sendPublicReadReceipts = true;
static bool swipeRightToLeftToReply = true;
static bool? sendOnEnter;
static bool useActivityImageAsChatBackground = true;
static bool showPresences = true;
// #Pangea
// static bool displayNavigationRail = false;
static bool displayNavigationRail = true;
// Pangea#
static bool experimentalVoip = false;
static const bool hideTypingUsernames = false;
static const String inviteLinkPrefix = 'https://matrix.to/#/';
static const String deepLinkPrefix = 'im.fluffychat://chat/';
static const String schemePrefix = 'matrix:';
// #Pangea
// static const String pushNotificationsChannelId = 'fluffychat_push';
// static const String pushNotificationsAppId = 'chat.fluffy.fluffychat';
static const String pushNotificationsChannelId = 'pangeachat_push';
static const String pushNotificationsAppId = 'com.talktolearn.chat';
// Pangea#
static const double borderRadius = 18.0;
static const double columnWidth = 360.0;
static final Uri homeserverList = Uri(
scheme: 'https',
host: 'servers.joinmatrix.org',
path: 'servers.json',
);
static final Uri privacyUrl = Uri(
scheme: 'https',
host: 'github.com',
path: '/krille-chan/fluffychat/blob/main/PRIVACY.md',
);
// #Pangea
static String googlePlayMangementUrl =
"https://play.google.com/store/account/subscriptions";
static String googlePlayHistoryUrl =
"https://play.google.com/store/account/orderhistory";
static String assetsBaseURL =
"https://pangea-chat-client-assets.s3.us-east-1.amazonaws.com";
static String androidUpdateURL =
"https://play.google.com/store/apps/details?id=com.talktolearn.chat";
static String iosUpdateURL = "itms-apps://itunes.apple.com/app/id1445118630";
static String googlePlayPaymentMethodUrl =
"https://play.google.com/store/paymentmethods";
static String appleMangementUrl =
"https://apps.apple.com/account/subscriptions";
static String stripePerMonth =
"https://buy.stripe.com/test_bIY6ssd8z5Uz8ec8ww";
static String iosPromoCode =
"https://apps.apple.com/redeem?ctx=offercodes&id=1445118630&code=";
static String androidUpdateURL =
"https://play.google.com/store/apps/details?id=com.talktolearn.chat";
static String iosUpdateURL = "itms-apps://itunes.apple.com/app/id1445118630";
static String windowsTTSDownloadInstructions =
"https://support.microsoft.com/en-us/topic/download-languages-and-voices-for-immersive-reader-read-mode-and-read-aloud-4c83a8d8-7486-42f7-8e46-2b0fdf753130";
static String androidTTSDownloadInstructions =
"https://support.google.com/accessibility/android/answer/6006983?hl=en";
static String assetsBaseURL =
"https://pangea-chat-client-assets.s3.us-east-1.amazonaws.com";
static String googlePlayMangementUrl =
"https://play.google.com/store/account/subscriptions";
static String googlePlayHistoryUrl =
"https://play.google.com/store/account/orderhistory";
static bool useActivityImageAsChatBackground = true;
static const int overlayAnimationDuration = 250;
static double volume = 1.0;
static const Color gold = Color.fromARGB(255, 253, 191, 1);
static const Color goldLight = Color.fromARGB(255, 254, 223, 73);
static const Color success = Color(0xFF33D057);
static const Color error = Colors.red;
static const Color warning = Color.fromARGB(255, 210, 124, 12);
static const Color activeToggleColor = Color(0xFF33D057);
static const Color yellowLight = Color.fromARGB(255, 247, 218, 120);
static const Color yellowDark = Color.fromARGB(255, 253, 191, 1);
static const double toolbarMaxHeight = 250.0;
static const double toolbarMinWidth = 350.0;
static const double toolbarMinHeight = 150.0;
static const double toolbarMenuHeight = 50.0;
static const double readingAssistanceInputBarHeight = 175.0;
static String errorSubscriptionId = "pangea_subscription_error";
static double volume = 1.0;
static bool showedActivityMenu = false;
// Pangea#
static TextStyle messageTextStyle(
Event? event,
Color textColor,
) {
final fontSize = messageFontSize * AppSettings.fontSizeFactor.value;
final bigEmotes = event != null &&
event.onlyEmotes &&
event.numberEmotes > 0 &&
event.numberEmotes <= 3;
static void loadFromJson(Map<String, dynamic> json) {
if (json['chat_color'] != null) {
try {
colorSchemeSeed = Color(json['chat_color']);
} catch (e) {
Logs().w(
'Invalid color in config.json! Please make sure to define the color in this format: "0xffdd0000"',
e,
);
}
}
if (json['application_name'] is String) {
_applicationName = json['application_name'];
}
if (json['application_welcome_message'] is String) {
_applicationWelcomeMessage = json['application_welcome_message'];
}
// #Pangea
// if (json['default_homeserver'] is String) {
// _defaultHomeserver = json['default_homeserver'];
// }
// Pangea#
if (json['privacy_url'] is String) {
_privacyUrl = json['privacy_url'];
}
if (json['web_base_url'] is String) {
_webBaseUrl = json['web_base_url'];
}
if (json['render_html'] is bool) {
// #Pangea
// this is interfering with our PangeaRichText functionality, removing it for now
renderHtml = false;
// renderHtml = json['render_html'];
// Pangea#
}
if (json['hide_redacted_events'] is bool) {
hideRedactedEvents = json['hide_redacted_events'];
}
if (json['hide_unknown_events'] is bool) {
hideUnknownEvents = json['hide_unknown_events'];
}
return TextStyle(
color: textColor,
fontSize: bigEmotes ? fontSize * 5 : fontSize,
decoration:
(event?.redacted ?? false) ? TextDecoration.lineThrough : null,
height: 1.3,
);
}
// Pangea#
}

View file

@ -260,6 +260,7 @@ abstract class AppRoutes {
// ? TwoColumnLayout(
// mainView: ChatList(
// activeChat: state.pathParameters['roomid'],
// activeSpace: state.uri.queryParameters['spaceId'],
// displayNavigationRail:
// state.path?.startsWith('/rooms/settings') != true,
// ),
@ -292,7 +293,10 @@ abstract class AppRoutes {
// Pangea#
: ChatList(
activeChat: state.pathParameters['roomid'],
activeSpaceId: state.pathParameters['spaceid'],
// #Pangea
// activeSpace: state.uri.queryParameters['spaceId'],
activeSpace: state.pathParameters['spaceid'],
// Pangea#
),
),
routes: [

View file

@ -1,45 +1,12 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:matrix/matrix_api_lite/utils/logs.dart';
import 'package:shared_preferences/shared_preferences.dart';
abstract class SettingKeys {
static const String renderHtml = 'chat.fluffy.renderHtml';
static const String hideRedactedEvents = 'chat.fluffy.hideRedactedEvents';
static const String hideUnknownEvents = 'chat.fluffy.hideUnknownEvents';
static const String hideUnimportantStateEvents =
'chat.fluffy.hideUnimportantStateEvents';
static const String separateChatTypes = 'chat.fluffy.separateChatTypes';
static const String sentry = 'sentry';
static const String theme = 'theme';
static const String amoledEnabled = 'amoled_enabled';
static const String codeLanguage = 'code_language';
static const String showNoGoogle = 'chat.fluffy.show_no_google';
static const String fontSizeFactor = 'chat.fluffy.font_size_factor';
static const String showNoPid = 'chat.fluffy.show_no_pid';
static const String databasePassword = 'database-password';
static const String appLockKey = 'chat.fluffy.app_lock';
static const String unifiedPushRegistered =
'chat.fluffy.unifiedpush.registered';
static const String unifiedPushEndpoint = 'chat.fluffy.unifiedpush.endpoint';
static const String ownStatusMessage = 'chat.fluffy.status_msg';
static const String dontAskForBootstrapKey =
'chat.fluffychat.dont_ask_bootstrap';
static const String autoplayImages = 'chat.fluffy.autoplay_images';
static const String sendTypingNotifications =
'chat.fluffy.send_typing_notifications';
static const String sendPublicReadReceipts =
'chat.fluffy.send_public_read_receipts';
static const String sendOnEnter = 'chat.fluffy.send_on_enter';
static const String swipeRightToLeftToReply =
'chat.fluffy.swipeRightToLeftToReply';
static const String experimentalVoip = 'chat.fluffy.experimental_voip';
static const String showPresences = 'chat.fluffy.show_presences';
static const String displayNavigationRail =
'chat.fluffy.display_navigation_rail';
// #Pangea
static const String volume = 'pangea.volume';
static const String showedActivityMenu =
'pangea.showed_activity_menu_tutorial';
// Pangea#
}
import 'package:fluffychat/utils/platform_infos.dart';
enum AppSettings<T> {
textMessageMaxLength<int>('textMessageMaxLength', 16384),
@ -52,6 +19,9 @@ enum AppSettings<T> {
// audioRecordingSamplingRate<int>('audioRecordingSamplingRate', 44100),
audioRecordingSamplingRate<int>('audioRecordingSamplingRate', 22050),
// Pangea#
showNoGoogle<bool>('chat.fluffy.show_no_google', false),
unifiedPushRegistered<bool>('chat.fluffy.unifiedpush.registered', false),
unifiedPushEndpoint<String>('chat.fluffy.unifiedpush.endpoint', ''),
pushNotificationsGatewayUrl<String>(
'pushNotificationsGatewayUrl',
// #Pangea
@ -65,6 +35,19 @@ enum AppSettings<T> {
// 'event_id_only',
// ),
// Pangea#
renderHtml<bool>('chat.fluffy.renderHtml', true),
fontSizeFactor<double>('chat.fluffy.font_size_factor', 1.0),
hideRedactedEvents<bool>('chat.fluffy.hideRedactedEvents', false),
hideUnknownEvents<bool>('chat.fluffy.hideUnknownEvents', true),
separateChatTypes<bool>('chat.fluffy.separateChatTypes', false),
autoplayImages<bool>('chat.fluffy.autoplay_images', true),
sendTypingNotifications<bool>('chat.fluffy.send_typing_notifications', true),
sendPublicReadReceipts<bool>('chat.fluffy.send_public_read_receipts', true),
swipeRightToLeftToReply<bool>('chat.fluffy.swipeRightToLeftToReply', true),
sendOnEnter<bool>('chat.fluffy.send_on_enter', false),
showPresences<bool>('chat.fluffy.show_presences', true),
displayNavigationRail<bool>('chat.fluffy.display_navigation_rail', false),
experimentalVoip<bool>('chat.fluffy.experimental_voip', false),
shareKeysWith<String>('chat.fluffy.share_keys_with_2', 'all'),
noEncryptionWarningShown<bool>(
'chat.fluffy.no_encryption_warning_shown',
@ -74,40 +57,95 @@ enum AppSettings<T> {
'chat.fluffy.display_chat_details_column',
false,
),
// AppConfig-mirrored settings
// #Pangea
// applicationName<String>('chat.fluffy.application_name', 'FluffyChat'),
// defaultHomeserver<String>('chat.fluffy.default_homeserver', 'matrix.org'),
applicationName<String>('chat.fluffy.application_name', 'Pangea Chat'),
// Pangea#
// colorSchemeSeed stored as ARGB int
colorSchemeSeedInt<int>(
'chat.fluffy.color_scheme_seed',
// #Pangea
// 0xFF5625BA,
0xFF8560E0,
// Pangea#
),
// #Pangea
volume<double>('pangea.value', 1.0),
// Pangea#
enableSoftLogout<bool>('chat.fluffy.enable_soft_logout', false);
final String key;
final T defaultValue;
const AppSettings(this.key, this.defaultValue);
static SharedPreferences get store => _store!;
static SharedPreferences? _store;
static Future<SharedPreferences> init({loadWebConfigFile = true}) async {
if (AppSettings._store != null) return AppSettings.store;
final store = AppSettings._store = await SharedPreferences.getInstance();
if (store.getBool(AppSettings.sendOnEnter.key) == null) {
await store.setBool(AppSettings.sendOnEnter.key, !PlatformInfos.isMobile);
}
if (kIsWeb && loadWebConfigFile) {
try {
final configJsonString =
utf8.decode((await http.get(Uri.parse('config.json'))).bodyBytes);
final configJson =
json.decode(configJsonString) as Map<String, Object?>;
for (final setting in AppSettings.values) {
if (store.get(setting.key) != null) continue;
final configValue = configJson[setting.name];
if (configValue == null) continue;
if (configValue is bool) {
await store.setBool(setting.key, configValue);
}
if (configValue is String) {
await store.setString(setting.key, configValue);
}
if (configValue is int) {
await store.setInt(setting.key, configValue);
}
if (configValue is double) {
await store.setDouble(setting.key, configValue);
}
}
} on FormatException catch (_) {
Logs().v('[ConfigLoader] config.json not found');
} catch (e) {
Logs().v('[ConfigLoader] config.json not found', e);
}
}
return store;
}
}
extension AppSettingsBoolExtension on AppSettings<bool> {
bool getItem(SharedPreferences store) => store.getBool(key) ?? defaultValue;
bool get value => AppSettings.store.getBool(key) ?? defaultValue;
Future<void> setItem(SharedPreferences store, bool value) =>
store.setBool(key, value);
Future<void> setItem(bool value) => AppSettings.store.setBool(key, value);
}
extension AppSettingsStringExtension on AppSettings<String> {
String getItem(SharedPreferences store) =>
store.getString(key) ?? defaultValue;
String get value => AppSettings.store.getString(key) ?? defaultValue;
Future<void> setItem(SharedPreferences store, String value) =>
store.setString(key, value);
Future<void> setItem(String value) => AppSettings.store.setString(key, value);
}
extension AppSettingsIntExtension on AppSettings<int> {
int getItem(SharedPreferences store) => store.getInt(key) ?? defaultValue;
int get value => AppSettings.store.getInt(key) ?? defaultValue;
Future<void> setItem(SharedPreferences store, int value) =>
store.setInt(key, value);
Future<void> setItem(int value) => AppSettings.store.setInt(key, value);
}
extension AppSettingsDoubleExtension on AppSettings<double> {
double getItem(SharedPreferences store) =>
store.getDouble(key) ?? defaultValue;
double get value => AppSettings.store.getDouble(key) ?? defaultValue;
Future<void> setItem(SharedPreferences store, double value) =>
store.setDouble(key, value);
Future<void> setItem(double value) => AppSettings.store.setDouble(key, value);
}

View file

@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'app_config.dart';
abstract class FluffyThemes {
@ -49,11 +50,7 @@ abstract class FluffyThemes {
]) {
final colorScheme = ColorScheme.fromSeed(
brightness: brightness,
seedColor: seed ??
AppConfig.colorSchemeSeed ??
Theme.of(context).colorScheme.primary,
// primary: AppConfig.primaryColor,
// secondary: AppConfig.gold,
seedColor: seed ?? Color(AppSettings.colorSchemeSeedInt.value),
);
final isColumnMode = FluffyThemes.isColumnMode(context);
return ThemeData(

View file

@ -3379,6 +3379,39 @@
"longPressToRecordVoiceMessage": "Long press to record voice message.",
"pause": "Pause",
"resume": "Resume",
"newSubSpace": "New sub space",
"moveToDifferentSpace": "Move to different space",
"moveUp": "Move up",
"moveDown": "Move down",
"removeFromSpaceDescription": "The chat will be removed from the space but still appear in your chat list.",
"countChats": "{chats} chats",
"@countChats": {
"type": "String",
"placeholders": {
"chats": {
"type": "int"
}
}
},
"spaceMemberOf": "Space member of {spaces}",
"@spaceMemberOf": {
"type": "String",
"placeholders": {
"spaces": {
"type": "String"
}
}
},
"spaceMemberOfCanKnock": "Space member of {spaces} can knock",
"@spaceMemberOfCanKnock": {
"type": "String",
"placeholders": {
"spaces": {
"type": "String"
}
}
},
"donate": "Donate",
"ignore": "Block",
"ignoredUsers": "Blocked users",
"writeAMessageLangCodes": "Type in {l1} or {l2}...",
@ -3947,6 +3980,9 @@
"grammarCopyPOSpropn": "Proper Noun",
"grammarCopyPOSnoun": "Noun",
"grammarCopyPOSintj": "Interjection",
"grammarCopyPOSidiom": "Idiom",
"grammarCopyPOSphrasalv": "Phrasal Verb",
"grammarCopyPOScompn": "Compound",
"grammarCopyPOSx": "Other",
"grammarCopyGENDERfem": "Feminine",
"grammarCopyPERSON2": "Second Person",

View file

@ -9,7 +9,6 @@ import 'package:matrix/matrix.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart';
@ -22,8 +21,6 @@ import 'utils/background_push.dart';
import 'widgets/fluffy_chat_app.dart';
void main() async {
Logs().i('Welcome to ${AppConfig.applicationName} <3');
// #Pangea
try {
await dotenv.load(fileName: ".env");
@ -55,12 +52,14 @@ void main() async {
// widget bindings are initialized already.
WidgetsFlutterBinding.ensureInitialized();
final store = await AppSettings.init();
Logs().i('Welcome to ${AppSettings.applicationName.value} <3');
// #Pangea
// await vod.init(wasmPath: './assets/assets/vodozemac/');
// Pangea#
Logs().nativeColors = !PlatformInfos.isIOS;
final store = await SharedPreferences.getInstance();
final clients = await ClientManager.getClients(store: store);
// If the app starts in detached mode, we assume that it is in
@ -80,14 +79,14 @@ void main() async {
// To start the flutter engine afterwards we add an custom observer.
WidgetsBinding.instance.addObserver(AppStarter(clients, store));
Logs().i(
'${AppConfig.applicationName} started in background-fetch mode. No GUI will be created unless the app is no longer detached.',
'${AppSettings.applicationName.value} started in background-fetch mode. No GUI will be created unless the app is no longer detached.',
);
return;
}
// Started in foreground mode.
Logs().i(
'${AppConfig.applicationName} started in foreground mode. Rendering GUI...',
'${AppSettings.applicationName.value} started in foreground mode. Rendering GUI...',
);
await startGui(clients, store);
}
@ -99,7 +98,7 @@ Future<void> startGui(List<Client> clients, SharedPreferences store) async {
if (PlatformInfos.isMobile) {
try {
pin =
await const FlutterSecureStorage().read(key: SettingKeys.appLockKey);
await const FlutterSecureStorage().read(key: 'chat.fluffy.app_lock');
} catch (e, s) {
Logs().d('Unable to read PIN from Secure storage', e, s);
}
@ -152,7 +151,7 @@ class AppStarter with WidgetsBindingObserver {
if (state == AppLifecycleState.detached) return;
Logs().i(
'${AppConfig.applicationName} switches from the detached background-fetch mode to ${state.name} mode. Rendering GUI...',
'${AppSettings.applicationName.value} switches from the detached background-fetch mode to ${state.name} mode. Rendering GUI...',
);
// Switching to foreground mode needs to reenable send online sync presence.
for (final client in clients) {

View file

@ -15,10 +15,8 @@ import 'package:matrix/matrix.dart';
import 'package:path_provider/path_provider.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:universal_html/html.dart' as html;
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
@ -341,7 +339,7 @@ class ChatController extends State<ChatPageWithRoom>
}
void _loadDraft() async {
final prefs = await SharedPreferences.getInstance();
final prefs = Matrix.of(context).store;
final draft = prefs.getString('draft_$roomId');
if (draft != null && draft.isNotEmpty) {
// #Pangea
@ -394,7 +392,7 @@ class ChatController extends State<ChatPageWithRoom>
KeyEventResult _customEnterKeyHandling(FocusNode node, KeyEvent evt) {
if (!HardwareKeyboard.instance.isShiftPressed &&
evt.logicalKey.keyLabel == 'Enter' &&
(AppConfig.sendOnEnter ?? !PlatformInfos.isMobile)) {
AppSettings.sendOnEnter.value) {
if (evt is KeyDownEvent) {
// #Pangea
// send();
@ -450,7 +448,7 @@ class ChatController extends State<ChatPageWithRoom>
WidgetsBinding.instance.addPostFrameCallback(_shareItems);
super.initState();
_displayChatDetailsColumn = ValueNotifier(
AppSettings.displayChatDetailsColumn.getItem(Matrix.of(context).store),
AppSettings.displayChatDetailsColumn.value,
);
sendingClient = Matrix.of(context).client;
@ -588,7 +586,9 @@ class ChatController extends State<ChatPageWithRoom>
var readMarkerEventIndex = readMarkerEventId.isEmpty
? -1
: timeline!.events
.filterByVisibleInGui(exceptionEventId: readMarkerEventId)
.filterByVisibleInGui(
exceptionEventId: readMarkerEventId,
)
.indexWhere((e) => e.eventId == readMarkerEventId);
// Read marker is existing but not found in first events. Try a single
@ -596,7 +596,9 @@ class ChatController extends State<ChatPageWithRoom>
if (readMarkerEventId.isNotEmpty && readMarkerEventIndex == -1) {
await timeline?.requestHistory(historyCount: _loadHistoryCount);
readMarkerEventIndex = timeline!.events
.filterByVisibleInGui(exceptionEventId: readMarkerEventId)
.filterByVisibleInGui(
exceptionEventId: readMarkerEventId,
)
.indexWhere((e) => e.eventId == readMarkerEventId);
}
@ -772,7 +774,7 @@ class ChatController extends State<ChatPageWithRoom>
_setReadMarkerFuture = timeline
.setReadMarker(
eventId: eventId,
public: AppConfig.sendPublicReadReceipts,
public: AppSettings.sendPublicReadReceipts.value,
)
.then((_) {
_setReadMarkerFuture = null;
@ -938,7 +940,7 @@ class ChatController extends State<ChatPageWithRoom>
// if (sendController.text.trim().isEmpty) return;
// Pangea#
_storeInputTimeoutTimer?.cancel();
final prefs = await SharedPreferences.getInstance();
final prefs = Matrix.of(context).store;
prefs.remove('draft_$roomId');
var parseCommands = true;
@ -1564,7 +1566,9 @@ class ChatController extends State<ChatPageWithRoom>
final eventIndex = foundEvent == null
? -1
: timeline!.events
.filterByVisibleInGui(exceptionEventId: eventId)
.filterByVisibleInGui(
exceptionEventId: eventId,
)
.indexOf(foundEvent);
if (eventIndex == -1) {
@ -1884,7 +1888,7 @@ class ChatController extends State<ChatPageWithRoom>
_storeInputTimeoutTimer?.cancel();
_storeInputTimeoutTimer = Timer(_storeInputTimeout, () async {
final prefs = await SharedPreferences.getInstance();
final prefs = Matrix.of(context).store;
await prefs.setString('draft_$roomId', text);
});
// #Pangea
@ -1903,7 +1907,7 @@ class ChatController extends State<ChatPageWithRoom>
// }
// }
// Pangea#
if (AppConfig.sendTypingNotifications) {
if (AppSettings.sendTypingNotifications.value) {
typingCoolDown?.cancel();
typingCoolDown = Timer(const Duration(seconds: 2), () {
typingCoolDown = null;
@ -2392,12 +2396,8 @@ class ChatController extends State<ChatPageWithRoom>
inputFocus.unfocus();
activityController.toggleShowDropdown();
if (!AppConfig.showedActivityMenu) {
AppConfig.showedActivityMenu = true;
Matrix.of(context).store.setBool(
SettingKeys.showedActivityMenu,
AppConfig.showedActivityMenu,
);
if (!InstructionsEnum.showedActivityMenu.isToggledOff) {
InstructionsEnum.showedActivityMenu.setToggledOff(true);
}
}
@ -2462,7 +2462,6 @@ class ChatController extends State<ChatPageWithRoom>
void toggleDisplayChatDetailsColumn() async {
await AppSettings.displayChatDetailsColumn.setItem(
Matrix.of(context).store,
!_displayChatDetailsColumn.value,
);
_displayChatDetailsColumn.value = !_displayChatDetailsColumn.value;

View file

@ -1,5 +1,9 @@
// import 'package:flutter/material.dart';
// import 'package:animations/animations.dart';
// import 'package:fluffychat/config/app_config.dart';
// import 'package:matrix/matrix.dart';
// import 'package:fluffychat/config/setting_keys.dart';
// import 'package:fluffychat/l10n/l10n.dart';
// import 'package:fluffychat/pages/chat/recording_input_row.dart';
// import 'package:fluffychat/pages/chat/recording_view_model.dart';
@ -7,9 +11,6 @@
// import 'package:fluffychat/utils/platform_infos.dart';
// import 'package:fluffychat/widgets/avatar.dart';
// import 'package:fluffychat/widgets/matrix.dart';
// import 'package:flutter/material.dart';
// import 'package:matrix/matrix.dart';
// import '../../config/themes.dart';
// import 'chat.dart';
// import 'input_bar.dart';
@ -296,10 +297,11 @@
// maxLines: 8,
// autofocus: !PlatformInfos.isMobile,
// keyboardType: TextInputType.multiline,
// textInputAction: AppConfig.sendOnEnter == true &&
// PlatformInfos.isMobile
// ? TextInputAction.send
// : null,
// textInputAction:
// AppSettings.sendOnEnter.value == true &&
// PlatformInfos.isMobile
// ? TextInputAction.send
// : null,
// onSubmitted: controller.onInputBarSubmitted,
// onSubmitImage: controller.sendImageFromClipBoard,
// focusNode: controller.inputFocus,

View file

@ -130,7 +130,7 @@ class ChatView extends StatelessWidget {
// ];
// } else if (!controller.room.isArchived) {
// return [
// if (AppConfig.experimentalVoip &&
// if (AppSettings.experimentalVoip.value &&
// Matrix.of(context).voipPlugin != null &&
// controller.room.isDirectChat)
// IconButton(

View file

@ -21,6 +21,7 @@ class EncryptionButton extends StatelessWidget {
.stream
.where((s) => s.deviceLists != null),
builder: (context, snapshot) {
final shouldBeEncrypted = room.joinRules != JoinRules.public;
return FutureBuilder<EncryptionHealthState>(
future: room.encrypted
? room.calcEncryptionHealthState()
@ -46,9 +47,13 @@ class EncryptionButton extends StatelessWidget {
),
),
child: Icon(
room.encrypted ? Icons.lock_outlined : Icons.lock_open_outlined,
room.encrypted
? Icons.lock_outlined
: Icons.no_encryption_outlined,
size: 20,
color: theme.colorScheme.onSurface,
color: (shouldBeEncrypted && !room.encrypted)
? theme.colorScheme.error
: theme.colorScheme.onSurface,
),
),
onPressed: () => context.go('/rooms/${room.id}/encryption'),

View file

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
class CuteContent extends StatefulWidget {
@ -21,7 +21,7 @@ class _CuteContentState extends State<CuteContent> {
@override
void initState() {
if (AppConfig.autoplayImages && !_isOverlayShown) {
if (AppSettings.autoplayImages.value && !_isOverlayShown) {
addOverlay();
}
super.initState();

View file

@ -5,6 +5,7 @@ import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/pages/image_viewer/image_viewer.dart';
import 'package:fluffychat/utils/file_description.dart';
import 'package:fluffychat/utils/url_launcher.dart';
@ -162,14 +163,14 @@ class ImageBubble extends StatelessWidget {
textScaleFactor: MediaQuery.textScalerOf(context).scale(1),
style: TextStyle(
color: textColor,
fontSize:
AppConfig.fontSizeFactor * AppConfig.messageFontSize,
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
),
options: const LinkifyOptions(humanize: false),
linkStyle: TextStyle(
color: linkColor,
fontSize:
AppConfig.fontSizeFactor * AppConfig.messageFontSize,
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
decoration: TextDecoration.underline,
decorationColor: linkColor,
),

View file

@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:swipe_to_action/swipe_to_action.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/chat/chat.dart';
@ -308,7 +309,7 @@ class Message extends StatelessWidget {
child: Icon(Icons.check_outlined),
),
),
direction: AppConfig.swipeRightToLeftToReply
direction: AppSettings.swipeRightToLeftToReply.value
? SwipeDirection.endToStart
: SwipeDirection.startToEnd,
onSwipe: (_) => onSwipe(),
@ -350,7 +351,7 @@ class Message extends StatelessWidget {
child: Text(
event.originServerTs.localizedTime(context),
style: TextStyle(
fontSize: 12 * AppConfig.fontSizeFactor,
fontSize: 12 * AppSettings.fontSizeFactor.value,
fontWeight: FontWeight.bold,
color: theme.colorScheme.secondary,
),
@ -1137,7 +1138,7 @@ class Message extends StatelessWidget {
child: Text(
L10n.of(context).readUpToHere,
style: TextStyle(
fontSize: 12 * AppConfig.fontSizeFactor,
fontSize: 12 * AppSettings.fontSizeFactor.value,
),
),
),

View file

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pages/chat/events/video_player.dart';
@ -146,7 +147,8 @@ class MessageContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
final fontSize = AppConfig.messageFontSize * AppConfig.fontSizeFactor;
final fontSize =
AppConfig.messageFontSize * AppSettings.fontSizeFactor.value;
final buttonTextColor = textColor;
switch (event.type) {
case EventTypes.Message:
@ -306,7 +308,7 @@ class MessageContent extends StatelessWidget {
},
);
}
var html = AppConfig.renderHtml && event.isRichMessage
var html = AppSettings.renderHtml.value && event.isRichMessage
? event.formattedText
: event.body;
if (event.messageType == MessageTypes.Emote) {
@ -325,14 +327,14 @@ class MessageContent extends StatelessWidget {
html: html,
textColor: textColor,
room: event.room,
fontSize: AppConfig.fontSizeFactor *
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize *
(bigEmotes ? 5 : 1),
limitHeight: !selected,
linkStyle: TextStyle(
color: linkColor,
fontSize:
AppConfig.fontSizeFactor * AppConfig.messageFontSize,
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
decoration: TextDecoration.underline,
decorationColor: linkColor,
),

View file

@ -4,6 +4,7 @@ import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/utils/file_description.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
import 'package:fluffychat/utils/url_launcher.dart';
@ -92,12 +93,14 @@ class MessageDownloadContent extends StatelessWidget {
textScaleFactor: MediaQuery.textScalerOf(context).scale(1),
style: TextStyle(
color: textColor,
fontSize: AppConfig.fontSizeFactor * AppConfig.messageFontSize,
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
),
options: const LinkifyOptions(humanize: false),
linkStyle: TextStyle(
color: linkColor,
fontSize: AppConfig.fontSizeFactor * AppConfig.messageFontSize,
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
decoration: TextDecoration.underline,
decorationColor: linkColor,
),

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import '../../../config/app_config.dart';
@ -30,7 +31,8 @@ class ReplyContent extends StatelessWidget {
final timeline = this.timeline;
final displayEvent =
timeline != null ? replyEvent.getDisplayEvent(timeline) : replyEvent;
final fontSize = AppConfig.messageFontSize * AppConfig.fontSizeFactor;
final fontSize =
AppConfig.messageFontSize * AppSettings.fontSizeFactor.value;
final color = theme.brightness == Brightness.dark
// Pangea#
? ownMessage

View file

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
@ -79,7 +80,7 @@ class StateMessage extends StatelessWidget {
),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12 * AppConfig.fontSizeFactor,
fontSize: 12 * AppSettings.fontSizeFactor.value,
decoration: event.redacted
? TextDecoration.lineThrough
: null,

View file

@ -6,6 +6,7 @@ import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/utils/file_description.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart';
@ -148,14 +149,14 @@ class EventVideoPlayer extends StatelessWidget {
textScaleFactor: MediaQuery.textScalerOf(context).scale(1),
style: TextStyle(
color: textColor,
fontSize:
AppConfig.fontSizeFactor * AppConfig.messageFontSize,
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
),
options: const LinkifyOptions(humanize: false),
linkStyle: TextStyle(
color: linkColor,
fontSize:
AppConfig.fontSizeFactor * AppConfig.messageFontSize,
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
decoration: TextDecoration.underline,
decorationColor: linkColor,
),

View file

@ -15,7 +15,6 @@ import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'events/audio_player.dart';
// #Pangea
@ -72,8 +71,6 @@ class RecordingViewModelState extends State<RecordingViewModel> {
}
if (await AudioRecorder().hasPermission() == false) return;
final store = Matrix.of(context).store;
final audioRecorder = _audioRecorder ??= AudioRecorder();
setState(() {});
@ -109,12 +106,12 @@ class RecordingViewModelState extends State<RecordingViewModel> {
await audioRecorder.start(
RecordConfig(
bitRate: AppSettings.audioRecordingBitRate.getItem(store),
sampleRate: AppSettings.audioRecordingSamplingRate.getItem(store),
numChannels: AppSettings.audioRecordingNumChannels.getItem(store),
autoGain: AppSettings.audioRecordingAutoGain.getItem(store),
echoCancel: AppSettings.audioRecordingEchoCancel.getItem(store),
noiseSuppress: AppSettings.audioRecordingNoiseSuppress.getItem(store),
bitRate: AppSettings.audioRecordingBitRate.value,
sampleRate: AppSettings.audioRecordingSamplingRate.value,
numChannels: AppSettings.audioRecordingNumChannels.value,
autoGain: AppSettings.audioRecordingAutoGain.value,
echoCancel: AppSettings.audioRecordingEchoCancel.value,
noiseSuppress: AppSettings.audioRecordingNoiseSuppress.value,
encoder: codec,
),
path: path ?? '',

View file

@ -27,6 +27,16 @@ class ChatAccessSettingsController extends State<ChatAccessSettings> {
bool historyVisibilityLoading = false;
bool guestAccessLoading = false;
Room get room => Matrix.of(context).client.getRoomById(widget.roomId)!;
Set<Room> get knownSpaceParents => {
...room.client.rooms.where(
(space) =>
space.isSpace &&
space.spaceChildren.any((child) => child.roomId == room.id),
),
...room.spaceParents
.map((parent) => room.client.getRoomById(parent.roomId ?? ''))
.whereType<Room>(),
};
String get roomVersion =>
room
@ -45,11 +55,13 @@ class ChatAccessSettingsController extends State<ChatAccessSettings> {
// Knock is only supported for rooms up from version 7:
if (roomVersionInt != null && roomVersionInt <= 6) {
joinRules.remove(JoinRules.knock);
joinRules.remove(JoinRules.knockRestricted);
}
// Not yet supported in FluffyChat:
joinRules.remove(JoinRules.restricted);
joinRules.remove(JoinRules.knockRestricted);
if (knownSpaceParents.isEmpty) {
joinRules.remove(JoinRules.restricted);
joinRules.remove(JoinRules.knockRestricted);
}
// If an unsupported join rule is the current join rule, display it:
final currentJoinRule = room.joinRules;
@ -69,7 +81,13 @@ class ChatAccessSettingsController extends State<ChatAccessSettings> {
try {
// #Pangea
// await room.setJoinRules(newJoinRules);
// await room.setJoinRules(
// newJoinRules,
// allowConditionRoomId: {JoinRules.restricted, JoinRules.knockRestricted}
// .contains(newJoinRules)
// ? knownSpaceParents.first.id
// : null,
// );
await room.pangeaSetJoinRules(
newJoinRules.toString().replaceAll('JoinRules.', ''),
);

View file

@ -88,7 +88,10 @@ class ChatAccessSettingsPageView extends StatelessWidget {
enabled: !controller.joinRulesLoading &&
room.canChangeJoinRules,
title: Text(
joinRule.localizedString(L10n.of(context)),
joinRule.localizedString(
L10n.of(context),
controller.knownSpaceParents,
),
),
value: joinRule,
),
@ -280,7 +283,7 @@ class _AliasListTile extends StatelessWidget {
}
extension JoinRulesDisplayString on JoinRules {
String localizedString(L10n l10n) {
String localizedString(L10n l10n, Set<Room> spaceParents) {
switch (this) {
case JoinRules.public:
return l10n.anyoneCanJoin;
@ -291,9 +294,17 @@ extension JoinRulesDisplayString on JoinRules {
case JoinRules.private:
return l10n.noOneCanJoin;
case JoinRules.restricted:
return l10n.restricted;
return l10n.spaceMemberOf(
spaceParents
.map((space) => space.getLocalizedDisplayname(MatrixLocals(l10n)))
.join(', '),
);
case JoinRules.knockRestricted:
return l10n.knockRestricted;
return l10n.spaceMemberOfCanKnock(
spaceParents
.map((space) => space.getLocalizedDisplayname(MatrixLocals(l10n)))
.join(', '),
);
}
}
}

View file

@ -9,6 +9,7 @@ import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/chat_encryption_settings/chat_encryption_settings.dart';
import 'package:fluffychat/utils/beautify_string_extension.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
class ChatEncryptionSettingsView extends StatelessWidget {
@ -58,7 +59,6 @@ class ChatEncryptionSettingsView extends StatelessWidget {
size: 128,
color: theme.colorScheme.onInverseSurface,
),
const Divider(),
if (room.isDirectChat)
Padding(
padding: const EdgeInsets.all(16.0),
@ -107,72 +107,73 @@ class ChatEncryptionSettingsView extends StatelessWidget {
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: deviceKeys.length,
itemBuilder: (BuildContext context, int i) =>
SwitchListTile(
value: !deviceKeys[i].blocked,
activeThumbColor: deviceKeys[i].verified
? Colors.green
: Colors.orange,
onChanged: (_) =>
controller.toggleDeviceKey(deviceKeys[i]),
title: Row(
children: [
Icon(
deviceKeys[i].verified
? Icons.verified_outlined
: deviceKeys[i].blocked
? Icons.block_outlined
: Icons.info_outlined,
color: deviceKeys[i].verified
? Colors.green
: deviceKeys[i].blocked
? Colors.red
: Colors.orange,
size: 20,
),
const SizedBox(width: 4),
Text(
deviceKeys[i].deviceId ??
L10n.of(context).unknownDevice,
),
const SizedBox(width: 4),
Flexible(
fit: FlexFit.loose,
child: Material(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
AppConfig.borderRadius,
itemBuilder: (BuildContext context, int i) => Column(
mainAxisSize: MainAxisSize.min,
children: [
if (i == 0 ||
deviceKeys[i].userId !=
deviceKeys[i - 1].userId) ...[
const Divider(),
FutureBuilder(
future: room.client
.getUserProfile(deviceKeys[i].userId),
builder: (context, snapshot) {
final displayname =
snapshot.data?.displayname ??
deviceKeys[i].userId.localpart ??
deviceKeys[i].userId;
return ListTile(
leading: Avatar(
name: displayname,
mxContent: snapshot.data?.avatarUrl,
),
side: BorderSide(
color: theme.colorScheme.primary,
),
),
color: theme.colorScheme.primaryContainer,
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
deviceKeys[i].userId,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: theme.colorScheme.primary,
fontSize: 12,
fontStyle: FontStyle.italic,
),
),
),
),
title: Text(displayname),
subtitle: Text(deviceKeys[i].userId),
);
},
),
],
),
subtitle: Text(
deviceKeys[i].ed25519Key?.beautified ??
L10n.of(context).unknownEncryptionAlgorithm,
style: TextStyle(
fontFamily: 'RobotoMono',
color: theme.colorScheme.secondary,
SwitchListTile(
value: !deviceKeys[i].blocked,
activeThumbColor: deviceKeys[i].verified
? Colors.green
: Colors.orange,
onChanged: (_) =>
controller.toggleDeviceKey(deviceKeys[i]),
title: Row(
children: [
Text(
deviceKeys[i].verified
? L10n.of(context).verified
: deviceKeys[i].blocked
? L10n.of(context).blocked
: L10n.of(context).unverified,
style: TextStyle(
color: deviceKeys[i].verified
? Colors.green
: deviceKeys[i].blocked
? Colors.red
: Colors.orange,
),
),
const Text(' | ID: '),
Text(
deviceKeys[i].deviceId ??
L10n.of(context).unknownDevice,
),
],
),
subtitle: Text(
deviceKeys[i].ed25519Key?.beautified ??
L10n.of(context).unknownEncryptionAlgorithm,
style: TextStyle(
fontFamily: 'RobotoMono',
color: theme.colorScheme.secondary,
fontSize: 11,
),
),
),
),
],
),
);
},

View file

@ -11,7 +11,6 @@ import 'package:matrix/matrix.dart' as sdk;
import 'package:matrix/matrix.dart';
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/chat_list/chat_list_view.dart';
import 'package:fluffychat/pangea/chat_list/utils/app_version_util.dart';
@ -83,17 +82,13 @@ extension LocalizedActiveFilter on ActiveFilter {
class ChatList extends StatefulWidget {
static BuildContext? contextForVoip;
final String? activeChat;
// #Pangea
final String? activeSpaceId;
// Pangea#
final String? activeSpace;
final bool displayNavigationRail;
const ChatList({
super.key,
required this.activeChat,
// #Pangea
this.activeSpaceId,
// Pangea#
this.activeSpace,
this.displayNavigationRail = false,
});
@ -111,15 +106,10 @@ class ChatListController extends State<ChatList>
// StreamSubscription? _intentUriStreamSubscription;
// Pangea#
// #Pangea
// ActiveFilter activeFilter = AppConfig.separateChatTypes
// ? ActiveFilter.messages
// : ActiveFilter.allChats;
ActiveFilter activeFilter = ActiveFilter.allChats;
// Pangea#
late ActiveFilter activeFilter;
// #Pangea
String? get activeSpaceId => widget.activeSpaceId;
String? get activeSpaceId => widget.activeSpace;
// String? _activeSpaceId;
// String? get activeSpaceId => _activeSpaceId;
@ -535,7 +525,16 @@ class ChatListController extends State<ChatList>
@override
void initState() {
// #Pangea
// activeFilter = AppSettings.separateChatTypes.value
// ? ActiveFilter.messages
// : ActiveFilter.allChats;
activeFilter = ActiveFilter.allChats;
// Pangea#
_initReceiveSharingIntent();
// #Pangea
// _activeSpaceId = widget.activeSpace;
// Pangea#
scrollController.addListener(_onScroll);
_waitForFirstSync();
@ -993,8 +992,7 @@ class ChatListController extends State<ChatList>
context: context,
);
if (result == OkCancelResult.ok) {
await Matrix.of(context).store.setBool(SettingKeys.showPresences, false);
AppConfig.showPresences = false;
AppSettings.showPresences.setItem(false);
setState(() {});
}
}

View file

@ -42,10 +42,7 @@ class ChatListViewBody extends StatelessWidget {
// spaceId: activeSpace,
// onBack: controller.clearActiveSpace,
// onChatTab: (room) => controller.onChatTap(room),
// onChatContext: (room, context) =>
// controller.chatContextAction(room, context),
// activeChat: controller.activeChat,
// toParentSpace: controller.setActiveSpace,
// );
return CourseChats(
activeSpace,
@ -108,8 +105,8 @@ class ChatListViewBody extends StatelessWidget {
// ),
// PublicRoomsHorizontalList(publicRooms: publicRooms),
// SearchTitle(
// title: L10n.of(context).publicSpaces,
// icon: const Icon(Icons.workspaces_outlined),
// title: L10n.of(context).publicSpaces,
// icon: const Icon(Icons.workspaces_outlined),
// ),
// PublicRoomsHorizontalList(publicRooms: publicSpaces),
// SearchTitle(
@ -127,27 +124,28 @@ class ChatListViewBody extends StatelessWidget {
// curve: FluffyThemes.animationCurve,
// child: userSearchResult == null
// ? null
// : ListView.builder(
// scrollDirection: Axis.horizontal,
// itemCount: userSearchResult.results.length,
// itemBuilder: (context, i) => _SearchItem(
// title:
// userSearchResult.results[i].displayName ??
// userSearchResult
// .results[i].userId.localpart ??
// L10n.of(context).unknownDevice,
// avatar: userSearchResult.results[i].avatarUrl,
// onPressed: () => UserDialog.show(
// context: context,
// profile: userSearchResult.results[i],
// ),
// ),
// ),
// ),
// Pangea#
// : ListView.builder(
// scrollDirection: Axis.horizontal,
// itemCount: userSearchResult.results.length,
// itemBuilder: (context, i) => _SearchItem(
// title:
// userSearchResult.results[i].displayName ??
// userSearchResult
// .results[i].userId.localpart ??
// L10n.of(context).unknownDevice,
// avatar: userSearchResult.results[i].avatarUrl,
// onPressed: () => UserDialog.show(
// context: context,
// profile: userSearchResult.results[i],
// ),
// ),
// ),
// ),
// Pangea#
],
// #Pangea
// if (!controller.isSearchMode && AppConfig.showPresences)
// if (!controller.isSearchMode &&
// AppSettings.showPresences.value)
// GestureDetector(
// onLongPress: () => controller.dismissStatusList(),
// child: StatusMessageList(
@ -184,14 +182,14 @@ class ChatListViewBody extends StatelessWidget {
// shrinkWrap: true,
// scrollDirection: Axis.horizontal,
// children: [
// if (AppConfig.separateChatTypes)
// if (AppSettings.separateChatTypes.value)
// ActiveFilter.messages
// else
// ActiveFilter.allChats,
// ActiveFilter.groups,
// ActiveFilter.unread,
// if (spaceDelegateCandidates.isNotEmpty &&
// !AppConfig.displayNavigationRail &&
// !AppSettings.displayNavigationRail.value &&
// !FluffyThemes.isColumnMode(context))
// ActiveFilter.spaces,
// ]
@ -217,24 +215,6 @@ class ChatListViewBody extends StatelessWidget {
// title: L10n.of(context).chats,
// icon: const Icon(Icons.forum_outlined),
// ),
if (controller.isSearchMode &&
rooms
.where(
(room) => room
.getLocalizedDisplayname(
MatrixLocals(L10n.of(context)),
)
.toLowerCase()
.contains(filter),
)
.isEmpty)
Padding(
padding: const EdgeInsetsGeometry.all(16.0),
child: Text(
L10n.of(context).emptyChatSearch,
textAlign: TextAlign.center,
),
),
// if (client.prevBatch != null &&
// rooms.isEmpty &&
// !controller.isSearchMode) ...[
@ -268,7 +248,7 @@ class ChatListViewBody extends StatelessWidget {
// padding: const EdgeInsets.all(16.0),
// child: Text(
// client.rooms.isEmpty
// ? L10n.of(context).noChatsFoundHereYet
// ? L10n.of(context).noChatsFoundHere
// : L10n.of(context).noMoreChatsFound,
// textAlign: TextAlign.center,
// style: TextStyle(
@ -280,6 +260,24 @@ class ChatListViewBody extends StatelessWidget {
// ],
// ),
// ],
if (controller.isSearchMode &&
rooms
.where(
(room) => room
.getLocalizedDisplayname(
MatrixLocals(L10n.of(context)),
)
.toLowerCase()
.contains(filter),
)
.isEmpty)
Padding(
padding: const EdgeInsetsGeometry.all(16.0),
child: Text(
L10n.of(context).emptyChatSearch,
textAlign: TextAlign.center,
),
),
// Pangea#
],
),

View file

@ -4,6 +4,7 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/chat_list/unread_bubble.dart';
import 'package:fluffychat/pangea/chat_list/utils/get_chat_list_item_subtitle.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
@ -54,11 +55,6 @@ class ChatListItem extends StatelessWidget {
final unread = room.isUnread;
final directChatMatrixId = room.directChatMatrixID;
final isDirectChat = directChatMatrixId != null;
final unreadBubbleSize = unread || room.hasNewMessages
? room.notificationCount > 0
? 20.0
: 14.0
: 0.0;
final hasNotifications = room.notificationCount > 0;
final backgroundColor =
activeChat ? theme.colorScheme.secondaryContainer : null;
@ -248,7 +244,7 @@ class ChatListItem extends StatelessWidget {
children: <Widget>[
if (typingText.isEmpty &&
ownMessage &&
room.lastEvent!.status.isSending) ...[
room.lastEvent?.status.isSending == true) ...[
const SizedBox(
width: 16,
height: 16,
@ -272,13 +268,11 @@ class ChatListItem extends StatelessWidget {
Expanded(
child: room.isSpace && room.membership == Membership.join
? Text(
L10n.of(context).countChatsAndCountParticipants(
// #Pangea
// room.spaceChildren.length,
room.spaceChildCount,
// Pangea#
(room.summary.mJoinedMemberCount ?? 1),
),
// #Pangea
// L10n.of(context)
// .countChats(room.spaceChildren.length),
L10n.of(context).countChats(room.spaceChildCount),
// Pangea#
style: TextStyle(color: theme.colorScheme.outline),
)
: typingText.isNotEmpty
@ -367,41 +361,7 @@ class ChatListItem extends StatelessWidget {
),
),
const SizedBox(width: 8),
AnimatedContainer(
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 7),
height: unreadBubbleSize,
width: !hasNotifications && !unread && !room.hasNewMessages
? 0
: (unreadBubbleSize - 9) *
room.notificationCount.toString().length +
9,
decoration: BoxDecoration(
color: room.highlightCount > 0
? theme.colorScheme.error
: hasNotifications || room.markedUnread
? theme.colorScheme.primary
: theme.colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(7),
),
child: hasNotifications
? Text(
room.notificationCount.toString(),
style: TextStyle(
color: room.highlightCount > 0
? theme.colorScheme.onError
: hasNotifications
? theme.colorScheme.onPrimary
: theme.colorScheme.onPrimaryContainer,
fontSize: 13,
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.center,
)
: const SizedBox.shrink(),
),
UnreadBubble(room: room),
],
),
onTap: onTap,

View file

@ -30,7 +30,7 @@ class ChatListView extends StatelessWidget {
children: [
// #Pangea
// if (FluffyThemes.isColumnMode(context) ||
// AppConfig.displayNavigationRail) ...[
// AppSettings.displayNavigationRail.value) ...[
// SpacesNavigationRail(
// activeSpaceId: controller.activeSpaceId,
// onGoToChats: controller.clearActiveSpace,

View file

@ -1,9 +1,10 @@
// #Pangea
// import 'package:flutter/material.dart';
// import 'package:go_router/go_router.dart';
// import 'package:matrix/matrix.dart';
// import 'package:url_launcher/url_launcher_string.dart';
// import 'package:fluffychat/config/app_config.dart';
// import 'package:fluffychat/config/themes.dart';
// import 'package:fluffychat/l10n/l10n.dart';
// import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
@ -68,6 +69,17 @@
// ],
// ),
// ),
// if (Matrix.of(context).backgroundPush?.firebaseEnabled != true)
// PopupMenuItem(
// value: SettingsAction.support,
// child: Row(
// children: [
// const Icon(Icons.favorite, color: Colors.red),
// const SizedBox(width: 18),
// Text(L10n.of(context).donate),
// ],
// ),
// ),
// PopupMenuItem(
// value: SettingsAction.settings,
// child: Row(
@ -208,6 +220,9 @@
// case SettingsAction.invite:
// FluffyShare.shareInviteLink(context);
// break;
// case SettingsAction.support:
// launchUrlString(AppConfig.donationUrl);
// break;
// case SettingsAction.settings:
// context.go('/rooms/settings');
// break;
@ -227,7 +242,7 @@
// newGroup,
// setStatus,
// invite,
// support,
// settings,
// archive,
// }
// Pangea#

View file

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
@ -8,26 +10,35 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/chat_list/chat_list_item.dart';
import 'package:fluffychat/pages/chat_list/search_title.dart';
import 'package:fluffychat/pages/chat_list/unread_bubble.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/utils/stream_extension.dart';
import 'package:fluffychat/utils/string_color.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/public_room_dialog.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_modal_action_popup.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_text_input_dialog.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/hover_builder.dart';
import 'package:fluffychat/widgets/matrix.dart';
enum AddRoomType { chat, subspace }
enum SpaceChildAction { edit, moveToSpace, removeFromSpace }
enum SpaceActions {
settings,
invite,
members,
leave,
}
class SpaceView extends StatefulWidget {
final String spaceId;
final void Function() onBack;
final void Function(String spaceId) toParentSpace;
final void Function(Room room) onChatTab;
final void Function(Room room, BuildContext context) onChatContext;
final String? activeChat;
const SpaceView({
@ -35,8 +46,6 @@ class SpaceView extends StatefulWidget {
required this.onBack,
required this.onChatTab,
required this.activeChat,
required this.toParentSpace,
required this.onChatContext,
super.key,
});
@ -58,9 +67,28 @@ class _SpaceViewState extends State<SpaceView> {
}
void _loadHierarchy() async {
final room = Matrix.of(context).client.getRoomById(widget.spaceId);
final matrix = Matrix.of(context);
final room = matrix.client.getRoomById(widget.spaceId);
if (room == null) return;
final cacheKey = 'spaces_history_cache${room.id}';
if (_discoveredChildren.isEmpty) {
final cachedChildren = matrix.store.getStringList(cacheKey);
if (cachedChildren != null) {
try {
_discoveredChildren.addAll(
cachedChildren.map(
(jsonString) =>
SpaceRoomsChunk$2.fromJson(jsonDecode(jsonString)),
),
);
} catch (e, s) {
Logs().e('Unable to json decode spaces hierarchy cache!', e, s);
matrix.store.remove(cacheKey);
}
}
}
setState(() {
_isLoading = true;
});
@ -74,16 +102,25 @@ class _SpaceViewState extends State<SpaceView> {
);
if (!mounted) return;
setState(() {
if (_nextBatch == null) _discoveredChildren.clear();
_nextBatch = hierarchy.nextBatch;
if (hierarchy.nextBatch == null) {
_noMoreRooms = true;
}
_discoveredChildren.addAll(
hierarchy.rooms
.where((c) => room.client.getRoomById(c.roomId) == null),
hierarchy.rooms.where((room) => room.roomId != widget.spaceId),
);
_isLoading = false;
});
if (_nextBatch == null) {
matrix.store.setStringList(
cacheKey,
_discoveredChildren
.map((child) => jsonEncode(child.toJson()))
.toList(),
);
}
} catch (e, s) {
Logs().w('Unable to load hierarchy', e, s);
if (!mounted) return;
@ -111,9 +148,7 @@ class _SpaceViewState extends State<SpaceView> {
),
);
if (mounted && joined == true) {
setState(() {
_discoveredChildren.remove(item);
});
setState(() {});
}
}
@ -129,6 +164,10 @@ class _SpaceViewState extends State<SpaceView> {
await space?.postLoad();
context.push('/rooms/${widget.spaceId}/invite');
break;
case SpaceActions.members:
await space?.postLoad();
context.push('/rooms/${widget.spaceId}/details/members');
break;
case SpaceActions.leave:
final confirmed = await showOkCancelAlertDialog(
context: context,
@ -151,27 +190,11 @@ class _SpaceViewState extends State<SpaceView> {
}
}
void _addChatOrSubspace() async {
final roomType = await showModalActionPopup(
context: context,
title: L10n.of(context).addChatOrSubSpace,
actions: [
AdaptiveModalAction(
value: AddRoomType.subspace,
label: L10n.of(context).createNewSpace,
),
AdaptiveModalAction(
value: AddRoomType.chat,
label: L10n.of(context).createGroup,
),
],
);
if (roomType == null) return;
void _addChatOrSubspace(AddRoomType roomType) async {
final names = await showTextInputDialog(
context: context,
title: roomType == AddRoomType.subspace
? L10n.of(context).createNewSpace
? L10n.of(context).newSubSpace
: L10n.of(context).createGroup,
hintText: roomType == AddRoomType.subspace
? L10n.of(context).spaceName
@ -196,29 +219,169 @@ class _SpaceViewState extends State<SpaceView> {
late final String roomId;
final activeSpace = client.getRoomById(widget.spaceId)!;
await activeSpace.postLoad();
final isPublicSpace = activeSpace.joinRules == JoinRules.public;
if (roomType == AddRoomType.subspace) {
roomId = await client.createSpace(
name: names,
visibility: activeSpace.joinRules == JoinRules.public
? sdk.Visibility.public
: sdk.Visibility.private,
visibility:
isPublicSpace ? sdk.Visibility.public : sdk.Visibility.private,
);
} else {
roomId = await client.createGroupChat(
enableEncryption: !isPublicSpace,
groupName: names,
preset: activeSpace.joinRules == JoinRules.public
preset: isPublicSpace
? CreateRoomPreset.publicChat
: CreateRoomPreset.privateChat,
visibility: activeSpace.joinRules == JoinRules.public
? sdk.Visibility.public
: sdk.Visibility.private,
visibility:
isPublicSpace ? sdk.Visibility.public : sdk.Visibility.private,
initialState: isPublicSpace
? null
: [
StateEvent(
content: {
'join_rule': 'restricted',
'allow': [
{
'room_id': widget.spaceId,
'type': 'm.room_membership',
},
],
},
type: EventTypes.RoomJoinRules,
),
],
);
}
await activeSpace.setSpaceChild(roomId);
},
);
if (result.error != null) return;
setState(() {
_nextBatch = null;
_discoveredChildren.clear();
});
_loadHierarchy();
}
void _showSpaceChildEditMenu(BuildContext posContext, String roomId) async {
final overlay =
Overlay.of(posContext).context.findRenderObject() as RenderBox;
final button = posContext.findRenderObject() as RenderBox;
final position = RelativeRect.fromRect(
Rect.fromPoints(
button.localToGlobal(const Offset(0, -65), ancestor: overlay),
button.localToGlobal(
button.size.bottomRight(Offset.zero) + const Offset(-50, 0),
ancestor: overlay,
),
),
Offset.zero & overlay.size,
);
final action = await showMenu<SpaceChildAction>(
context: posContext,
position: position,
items: [
PopupMenuItem(
value: SpaceChildAction.moveToSpace,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.move_down_outlined),
const SizedBox(width: 12),
Text(L10n.of(context).moveToDifferentSpace),
],
),
),
PopupMenuItem(
value: SpaceChildAction.edit,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.edit_outlined),
const SizedBox(width: 12),
Text(L10n.of(context).edit),
],
),
),
PopupMenuItem(
value: SpaceChildAction.removeFromSpace,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.group_remove_outlined),
const SizedBox(width: 12),
Text(L10n.of(context).removeFromSpace),
],
),
),
],
);
if (action == null) return;
if (!mounted) return;
final space = Matrix.of(context).client.getRoomById(widget.spaceId);
if (space == null) return;
switch (action) {
case SpaceChildAction.edit:
context.push('/rooms/${widget.spaceId}/details');
case SpaceChildAction.moveToSpace:
final spacesWithPowerLevels = space.client.rooms
.where(
(room) =>
room.isSpace &&
room.canChangeStateEvent(EventTypes.SpaceChild) &&
room.id != widget.spaceId,
)
.toList();
final newSpace = await showModalActionPopup(
context: context,
title: L10n.of(context).space,
actions: spacesWithPowerLevels
.map(
(space) => AdaptiveModalAction(
value: space,
label: space
.getLocalizedDisplayname(MatrixLocals(L10n.of(context))),
),
)
.toList(),
);
if (newSpace == null) return;
final result = await showFutureLoadingDialog(
context: context,
future: () async {
await newSpace.setSpaceChild(newSpace.id);
await space.removeSpaceChild(roomId);
},
);
if (result.isError) return;
if (!mounted) return;
_nextBatch = null;
_loadHierarchy();
return;
case SpaceChildAction.removeFromSpace:
final consent = await showOkCancelAlertDialog(
context: context,
title: L10n.of(context).removeFromSpace,
message: L10n.of(context).removeFromSpaceDescription,
);
if (consent != OkCancelResult.ok) return;
if (!mounted) return;
final result = await showFutureLoadingDialog(
context: context,
future: () => space.removeSpaceChild(roomId),
);
if (result.isError) return;
if (!mounted) return;
_nextBatch = null;
_loadHierarchy();
return;
}
}
@override
@ -228,6 +391,11 @@ class _SpaceViewState extends State<SpaceView> {
final room = Matrix.of(context).client.getRoomById(widget.spaceId);
final displayname =
room?.getLocalizedDisplayname() ?? L10n.of(context).nothingFound;
const avatarSize = Avatar.defaultSize / 1.5;
final isAdmin = room?.canChangeStateEvent(
EventTypes.SpaceChild,
) ==
true;
return Scaffold(
appBar: AppBar(
leading: FluffyThemes.isColumnMode(context)
@ -242,6 +410,7 @@ class _SpaceViewState extends State<SpaceView> {
title: ListTile(
contentPadding: EdgeInsets.zero,
leading: Avatar(
size: avatarSize,
mxContent: room?.avatar,
name: displayname,
border: BorderSide(width: 1, color: theme.dividerColor),
@ -252,18 +421,38 @@ class _SpaceViewState extends State<SpaceView> {
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subtitle: room == null
? null
: Text(
L10n.of(context).countChatsAndCountParticipants(
room.spaceChildren.length,
room.summary.mJoinedMemberCount ?? 1,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
actions: [
if (isAdmin)
PopupMenuButton<AddRoomType>(
icon: const Icon(Icons.add_outlined),
onSelected: _addChatOrSubspace,
tooltip: L10n.of(context).addChatOrSubSpace,
itemBuilder: (context) => [
PopupMenuItem(
value: AddRoomType.chat,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.group_add_outlined),
const SizedBox(width: 12),
Text(L10n.of(context).newGroup),
],
),
),
PopupMenuItem(
value: AddRoomType.subspace,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.workspaces_outlined),
const SizedBox(width: 12),
Text(L10n.of(context).newSubSpace),
],
),
),
],
),
PopupMenuButton<SpaceActions>(
useRootNavigator: true,
onSelected: _onSpaceAction,
@ -290,6 +479,21 @@ class _SpaceViewState extends State<SpaceView> {
],
),
),
PopupMenuItem(
value: SpaceActions.members,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.group_outlined),
const SizedBox(width: 12),
Text(
L10n.of(context).countParticipants(
room?.summary.mJoinedMemberCount ?? 1,
),
),
],
),
),
PopupMenuItem(
value: SpaceActions.leave,
child: Row(
@ -305,16 +509,6 @@ class _SpaceViewState extends State<SpaceView> {
),
],
),
floatingActionButton: room?.canChangeStateEvent(
EventTypes.SpaceChild,
) ==
true
? FloatingActionButton.extended(
onPressed: _addChatOrSubspace,
label: Text(L10n.of(context).group),
icon: const Icon(Icons.group_add_outlined),
)
: null,
body: room == null
? const Center(
child: Icon(
@ -327,29 +521,11 @@ class _SpaceViewState extends State<SpaceView> {
.where((s) => s.hasRoomUpdate)
.rateLimit(const Duration(seconds: 1)),
builder: (context, snapshot) {
final childrenIds = room.spaceChildren
.map((c) => c.roomId)
.whereType<String>()
.toSet();
final joinedRooms = room.client.rooms
.where((room) => childrenIds.remove(room.id))
.toList();
final joinedParents = room.spaceParents
.map((parent) {
final roomId = parent.roomId;
if (roomId == null) return null;
return room.client.getRoomById(roomId);
})
.whereType<Room>()
.toList();
final filter = _filterController.text.trim().toLowerCase();
return CustomScrollView(
slivers: [
SliverAppBar(
floating: true,
toolbarHeight: 72,
scrolledUnderElevation: 0,
backgroundColor: Colors.transparent,
automaticallyImplyLeading: false,
@ -359,11 +535,6 @@ class _SpaceViewState extends State<SpaceView> {
textInputAction: TextInputAction.search,
decoration: InputDecoration(
filled: true,
fillColor: theme.colorScheme.secondaryContainer,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(99),
),
contentPadding: EdgeInsets.zero,
hintText: L10n.of(context).search,
hintStyle: TextStyle(
@ -382,83 +553,11 @@ class _SpaceViewState extends State<SpaceView> {
),
),
SliverList.builder(
itemCount: joinedParents.length,
itemCount: _discoveredChildren.length + 1,
itemBuilder: (context, i) {
final displayname =
joinedParents[i].getLocalizedDisplayname();
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 1,
),
child: Material(
borderRadius:
BorderRadius.circular(AppConfig.borderRadius),
clipBehavior: Clip.hardEdge,
child: ListTile(
minVerticalPadding: 0,
leading: Icon(
Icons.adaptive.arrow_back_outlined,
size: 16,
),
title: Row(
children: [
Avatar(
mxContent: joinedParents[i].avatar,
name: displayname,
size: Avatar.defaultSize / 2,
borderRadius: BorderRadius.circular(
AppConfig.borderRadius / 4,
),
),
const SizedBox(width: 8),
Expanded(child: Text(displayname)),
],
),
onTap: () =>
widget.toParentSpace(joinedParents[i].id),
),
),
);
},
),
SliverList.builder(
itemCount: joinedRooms.length,
itemBuilder: (context, i) {
final joinedRoom = joinedRooms[i];
return ChatListItem(
joinedRoom,
filter: filter,
onTap: () => widget.onChatTab(joinedRoom),
onLongPress: (context) => widget.onChatContext(
joinedRoom,
context,
),
activeChat: widget.activeChat == joinedRoom.id,
);
},
),
SliverList.builder(
itemCount: _discoveredChildren.length + 2,
itemBuilder: (context, i) {
if (i == 0) {
return SearchTitle(
title: L10n.of(context).discover,
icon: const Icon(Icons.explore_outlined),
);
}
i--;
if (i == _discoveredChildren.length) {
if (_noMoreRooms) {
return Padding(
padding: const EdgeInsets.all(12.0),
child: Center(
child: Text(
L10n.of(context).noMoreChatsFound,
style: const TextStyle(fontSize: 13),
),
),
);
return const SizedBox.shrink();
}
return Padding(
padding: const EdgeInsets.symmetric(
@ -468,11 +567,7 @@ class _SpaceViewState extends State<SpaceView> {
child: TextButton(
onPressed: _isLoading ? null : _loadHierarchy,
child: _isLoading
? LinearProgressIndicator(
borderRadius: BorderRadius.circular(
AppConfig.borderRadius,
),
)
? const CircularProgressIndicator.adaptive()
: Text(L10n.of(context).loadMore),
),
);
@ -484,6 +579,10 @@ class _SpaceViewState extends State<SpaceView> {
if (!displayname.toLowerCase().contains(filter)) {
return const SizedBox.shrink();
}
var joinedRoom = room.client.getRoomById(item.roomId);
if (joinedRoom?.membership == Membership.leave) {
joinedRoom = null;
}
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8,
@ -493,51 +592,83 @@ class _SpaceViewState extends State<SpaceView> {
borderRadius:
BorderRadius.circular(AppConfig.borderRadius),
clipBehavior: Clip.hardEdge,
child: ListTile(
visualDensity:
const VisualDensity(vertical: -0.5),
contentPadding:
const EdgeInsets.symmetric(horizontal: 8),
onTap: () => _joinChildRoom(item),
leading: Avatar(
mxContent: item.avatarUrl,
name: displayname,
borderRadius: item.roomType == 'm.space'
? BorderRadius.circular(
AppConfig.borderRadius / 2,
)
color: joinedRoom != null &&
widget.activeChat == joinedRoom.id
? theme.colorScheme.secondaryContainer
: Colors.transparent,
child: HoverBuilder(
builder: (context, hovered) => ListTile(
visualDensity:
const VisualDensity(vertical: -0.5),
contentPadding:
const EdgeInsets.symmetric(horizontal: 8),
onTap: joinedRoom != null
? () => widget.onChatTab(joinedRoom!)
: () => _joinChildRoom(item),
onLongPress: isAdmin
? () => _showSpaceChildEditMenu(
context,
item.roomId,
)
: null,
),
title: Row(
children: [
Expanded(
child: Text(
displayname,
maxLines: 1,
overflow: TextOverflow.ellipsis,
leading: hovered && isAdmin
? SizedBox.square(
dimension: avatarSize,
child: IconButton(
splashRadius: avatarSize,
iconSize: 14,
style: IconButton.styleFrom(
foregroundColor: theme.colorScheme
.onTertiaryContainer,
backgroundColor: theme
.colorScheme.tertiaryContainer,
),
onPressed: () =>
_showSpaceChildEditMenu(
context,
item.roomId,
),
icon: const Icon(Icons.edit_outlined),
),
)
: Avatar(
size: avatarSize,
mxContent: item.avatarUrl,
name: '#',
backgroundColor:
theme.colorScheme.surfaceContainer,
textColor: item.name?.darkColor ??
theme.colorScheme.onSurface,
border: item.roomType == 'm.space'
? BorderSide(
color: theme.colorScheme
.surfaceContainerHighest,
)
: null,
borderRadius: item.roomType == 'm.space'
? BorderRadius.circular(
AppConfig.borderRadius / 4,
)
: null,
),
title: Row(
children: [
Expanded(
child: Opacity(
opacity: joinedRoom == null ? 0.5 : 1,
child: Text(
displayname,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
),
),
Text(
item.numJoinedMembers.toString(),
style: TextStyle(
fontSize: 13,
color: theme.textTheme.bodyMedium!.color,
),
),
const SizedBox(width: 4),
const Icon(
Icons.people_outlined,
size: 14,
),
],
),
subtitle: Text(
item.topic ??
L10n.of(context).countParticipants(
item.numJoinedMembers,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
if (joinedRoom != null)
UnreadBubble(room: joinedRoom)
else
const Icon(Icons.chevron_right_outlined),
],
),
),
),
),
@ -552,9 +683,3 @@ class _SpaceViewState extends State<SpaceView> {
);
}
}
enum SpaceActions {
settings,
invite,
leave,
}

View file

@ -0,0 +1,56 @@
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/themes.dart';
class UnreadBubble extends StatelessWidget {
final Room room;
const UnreadBubble({required this.room, super.key});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final unread = room.isUnread;
final hasNotifications = room.notificationCount > 0;
final unreadBubbleSize = unread || room.hasNewMessages
? room.notificationCount > 0
? 20.0
: 14.0
: 0.0;
return AnimatedContainer(
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 7),
height: unreadBubbleSize,
width: !hasNotifications && !unread && !room.hasNewMessages
? 0
: (unreadBubbleSize - 9) * room.notificationCount.toString().length +
9,
decoration: BoxDecoration(
color: room.highlightCount > 0
? theme.colorScheme.error
: hasNotifications || room.markedUnread
? theme.colorScheme.primary
: theme.colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(7),
),
child: hasNotifications
? Text(
room.notificationCount.toString(),
style: TextStyle(
color: room.highlightCount > 0
? theme.colorScheme.onError
: hasNotifications
? theme.colorScheme.onPrimary
: theme.colorScheme.onPrimaryContainer,
fontSize: 13,
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.center,
)
: const SizedBox.shrink(),
);
}
}

View file

@ -8,7 +8,7 @@ import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
import 'package:universal_html/html.dart' as html;
import 'package:url_launcher/url_launcher_string.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/l10n/l10n.dart';
@ -34,7 +34,10 @@ class HomeserverPickerController extends State<HomeserverPicker> {
bool isLoading = false;
final TextEditingController homeserverController = TextEditingController(
// #Pangea
// text: AppSettings.defaultHomeserver.value,
text: AppConfig.defaultHomeserver,
// Pangea#
);
String? error;
@ -211,7 +214,7 @@ class HomeserverPickerController extends State<HomeserverPicker> {
case MoreLoginActions.importBackup:
restoreBackup();
case MoreLoginActions.privacy:
launchUrlString(AppConfig.privacyUrl);
launchUrl(AppConfig.privacyUrl);
case MoreLoginActions.about:
PlatformInfos.showDialog(context);
}

View file

@ -148,7 +148,9 @@ class SettingsView extends StatelessWidget {
displayname,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 18),
style: const TextStyle(
fontSize: 18,
),
),
),
TextButton.icon(
@ -380,7 +382,7 @@ class SettingsView extends StatelessWidget {
// ListTile(
// leading: const Icon(Icons.privacy_tip_outlined),
// title: Text(L10n.of(context).privacy),
// onTap: () => launchUrlString(AppConfig.privacyUrl),
// onTap: () => launchUrl(AppConfig.privacyUrl),
// ),
// ListTile(
// leading: const Icon(Icons.info_outline_rounded),

View file

@ -4,7 +4,6 @@ import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
import 'package:fluffychat/widgets/settings_switch_list_tile.dart';
import 'settings_chat.dart';
@ -32,46 +31,33 @@ class SettingsChatView extends StatelessWidget {
// SettingsSwitchListTile.adaptive(
// title: L10n.of(context).formattedMessages,
// subtitle: L10n.of(context).formattedMessagesDescription,
// onChanged: (b) => AppConfig.renderHtml = b,
// storeKey: SettingKeys.renderHtml,
// defaultValue: AppConfig.renderHtml,
// setting: AppSettings.renderHtml,
// ),
// Pangea#
SettingsSwitchListTile.adaptive(
title: L10n.of(context).hideRedactedMessages,
subtitle: L10n.of(context).hideRedactedMessagesBody,
onChanged: (b) => AppConfig.hideRedactedEvents = b,
storeKey: SettingKeys.hideRedactedEvents,
defaultValue: AppConfig.hideRedactedEvents,
setting: AppSettings.hideRedactedEvents,
),
SettingsSwitchListTile.adaptive(
title: L10n.of(context).hideInvalidOrUnknownMessageFormats,
onChanged: (b) => AppConfig.hideUnknownEvents = b,
storeKey: SettingKeys.hideUnknownEvents,
defaultValue: AppConfig.hideUnknownEvents,
setting: AppSettings.hideUnknownEvents,
),
// #Pangea
// if (PlatformInfos.isMobile)
// SettingsSwitchListTile.adaptive(
// title: L10n.of(context).autoplayImages,
// onChanged: (b) => AppConfig.autoplayImages = b,
// storeKey: SettingKeys.autoplayImages,
// defaultValue: AppConfig.autoplayImages,
// setting: AppSettings.autoplayImages,
// ),
// Pangea#
SettingsSwitchListTile.adaptive(
title: L10n.of(context).sendOnEnter,
onChanged: (b) => AppConfig.sendOnEnter = b,
storeKey: SettingKeys.sendOnEnter,
defaultValue: AppConfig.sendOnEnter ?? !PlatformInfos.isMobile,
setting: AppSettings.sendOnEnter,
),
SettingsSwitchListTile.adaptive(
title: L10n.of(context).swipeRightToLeftToReply,
onChanged: (b) => AppConfig.swipeRightToLeftToReply = b,
storeKey: SettingKeys.swipeRightToLeftToReply,
defaultValue: AppConfig.swipeRightToLeftToReply,
setting: AppSettings.swipeRightToLeftToReply,
),
// #Pangea
SwitchListTile.adaptive(
value: AppConfig.useActivityImageAsChatBackground,
@ -110,12 +96,10 @@ class SettingsChatView extends StatelessWidget {
// SettingsSwitchListTile.adaptive(
// title: L10n.of(context).experimentalVideoCalls,
// onChanged: (b) {
// AppConfig.experimentalVoip = b;
// Matrix.of(context).createVoipPlugin();
// return;
// },
// storeKey: SettingKeys.experimentalVoip,
// defaultValue: AppConfig.experimentalVoip,
// setting: AppSettings.experimentalVoip,
// ),
// Pangea#
],

View file

@ -201,10 +201,7 @@ class SettingsNotificationsController extends State<SettingsNotifications> {
void updateVolume(double value) {
volumeNotifier.value = value;
AppConfig.volume = value;
Matrix.of(context).store.setDouble(
SettingKeys.volume,
value,
);
AppSettings.volume.setItem(value);
}
Future<void> requestNotificationPermission() async {

View file

@ -156,7 +156,6 @@ class SettingsSecurityController extends State<SettingsSecurity> {
void changeShareKeysWith(ShareKeysWith? shareKeysWith) async {
if (shareKeysWith == null) return;
AppSettings.shareKeysWith.setItem(
Matrix.of(context).store,
shareKeysWith.name,
);
Matrix.of(context).client.shareKeysWith = shareKeysWith;

View file

@ -63,16 +63,12 @@ class SettingsSecurityView extends StatelessWidget {
title: L10n.of(context).sendTypingNotifications,
subtitle:
L10n.of(context).sendTypingNotificationsDescription,
onChanged: (b) => AppConfig.sendTypingNotifications = b,
storeKey: SettingKeys.sendTypingNotifications,
defaultValue: AppConfig.sendTypingNotifications,
setting: AppSettings.sendTypingNotifications,
),
SettingsSwitchListTile.adaptive(
title: L10n.of(context).sendReadReceipts,
subtitle: L10n.of(context).sendReadReceiptsDescription,
onChanged: (b) => AppConfig.sendPublicReadReceipts = b,
storeKey: SettingKeys.sendPublicReadReceipts,
defaultValue: AppConfig.sendPublicReadReceipts,
setting: AppSettings.sendPublicReadReceipts,
),
ListTile(
trailing: const Icon(Icons.chevron_right_outlined),

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/user/style_settings_repo.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/utils/account_config.dart';
import 'package:fluffychat/utils/file_selector.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
@ -18,7 +18,9 @@ class SettingsStyle extends StatefulWidget {
class SettingsStyleController extends State<SettingsStyle> {
void setChatColor(Color? color) async {
AppConfig.colorSchemeSeed = color;
AppSettings.colorSchemeSeedInt.setItem(
color?.toARGB32() ?? AppSettings.colorSchemeSeedInt.defaultValue,
);
ThemeController.of(context).setPrimaryColor(color);
}
@ -156,17 +158,7 @@ class SettingsStyleController extends State<SettingsStyle> {
}
void changeFontSizeFactor(double d) {
setState(() => AppConfig.fontSizeFactor = d);
// #Pangea
// Matrix.of(context).store.setString(
// SettingKeys.fontSizeFactor,
// AppConfig.fontSizeFactor.toString(),
// );
StyleSettingsRepo.setFontSizeFactor(
Matrix.of(context).client.userID!,
AppConfig.fontSizeFactor,
);
// Pangea#
AppSettings.fontSizeFactor.setItem(d);
}
@override

View file

@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:dynamic_color/dynamic_color.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/chat/events/state_message.dart';
@ -228,7 +229,7 @@ class SettingsStyleView extends StatelessWidget {
style: TextStyle(
color: theme.onBubbleColor,
fontSize: AppConfig.messageFontSize *
AppConfig.fontSizeFactor,
AppSettings.fontSizeFactor.value,
),
),
),
@ -261,7 +262,7 @@ class SettingsStyleView extends StatelessWidget {
style: TextStyle(
color: theme.colorScheme.onSurface,
fontSize: AppConfig.messageFontSize *
AppConfig.fontSizeFactor,
AppSettings.fontSizeFactor.value,
),
),
),
@ -323,13 +324,15 @@ class SettingsStyleView extends StatelessWidget {
),
ListTile(
title: Text(L10n.of(context).fontSize),
trailing: Text('× ${AppConfig.fontSizeFactor}'),
trailing: Text(
'× ${AppSettings.fontSizeFactor.value}',
),
),
Slider.adaptive(
min: 0.5,
max: 2.5,
divisions: 20,
value: AppConfig.fontSizeFactor,
value: AppSettings.fontSizeFactor.value,
semanticFormatterCallback: (d) => d.toString(),
onChanged: controller.changeFontSizeFactor,
),
@ -348,21 +351,15 @@ class SettingsStyleView extends StatelessWidget {
// ),
// SettingsSwitchListTile.adaptive(
// title: L10n.of(context).presencesToggle,
// onChanged: (b) => AppConfig.showPresences = b,
// storeKey: SettingKeys.showPresences,
// defaultValue: AppConfig.showPresences,
// setting: AppSettings.showPresences,
// ),
// SettingsSwitchListTile.adaptive(
// title: L10n.of(context).separateChatTypes,
// onChanged: (b) => AppConfig.separateChatTypes = b,
// storeKey: SettingKeys.separateChatTypes,
// defaultValue: AppConfig.separateChatTypes,
// setting: AppSettings.separateChatTypes,
// ),
// SettingsSwitchListTile.adaptive(
// title: L10n.of(context).displayNavigationRail,
// onChanged: (b) => AppConfig.displayNavigationRail = b,
// storeKey: SettingKeys.displayNavigationRail,
// defaultValue: AppConfig.displayNavigationRail,
// setting: AppSettings.displayNavigationRail,
// ),
// Pangea#
],

View file

@ -1,7 +1,6 @@
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart';
import 'package:fluffychat/pangea/instructions/instructions_enum.dart';
@ -10,7 +9,7 @@ import 'package:fluffychat/widgets/matrix.dart';
extension ActivityMenuLogic on ChatController {
bool get shouldShowActivityInstructions {
if (AppConfig.showedActivityMenu ||
if (InstructionsEnum.showedActivityMenu.isToggledOff ||
InstructionsEnum.activityStatsMenu.isToggledOff ||
MatrixState.pAnyState.isOverlayOpen(RegExp(r"^word-zoom-card-.*$")) ||
timeline == null ||

View file

@ -4,6 +4,7 @@ import 'package:collection/collection.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/activity_sessions/activity_role_model.dart';
@ -72,7 +73,7 @@ class ActivityRolesEvent extends StatelessWidget {
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 12 * AppConfig.fontSizeFactor,
fontSize: 12 * AppSettings.fontSizeFactor.value,
decoration:
event.redacted ? TextDecoration.lineThrough : null,
),

View file

@ -6,6 +6,7 @@ import 'package:collection/collection.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
@ -118,7 +119,7 @@ class LemmaUseExampleMessages extends StatelessWidget {
text: TextSpan(
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimaryFixed,
fontSize: AppConfig.fontSizeFactor *
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
),
children: example.textSpans,

View file

@ -7,6 +7,7 @@ import 'package:intl/intl.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/analytics_downloads/analytics_summary_enum.dart';
@ -426,7 +427,8 @@ class AnalyticsDownloadDialogState extends State<AnalyticsDownloadDialog> {
Text(
L10n.of(context).fileType,
style: TextStyle(
fontSize: AppConfig.fontSizeFactor * AppConfig.messageFontSize,
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
),
),
Padding(

View file

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:shimmer/shimmer.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
class TextLoadingShimmer extends StatelessWidget {
final double width;
@ -24,8 +25,8 @@ class TextLoadingShimmer extends StatelessWidget {
borderRadius: BorderRadius.circular(4.0),
color: Theme.of(context).colorScheme.primary,
),
height:
height ?? (AppConfig.messageFontSize * AppConfig.fontSizeFactor),
height: height ??
(AppConfig.messageFontSize * AppSettings.fontSizeFactor.value),
width: width,
),
);

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/analytics_details_popup/morph_meaning_widget.dart';
@ -270,7 +271,8 @@ class _ExampleMessageWidget extends StatelessWidget {
text: TextSpan(
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimaryFixed,
fontSize: AppConfig.fontSizeFactor * AppConfig.messageFontSize,
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
),
children: snapshot.data!,
),
@ -464,8 +466,8 @@ class _ErrorBlankWidgetState extends State<_ErrorBlankWidget> {
text: TextSpan(
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimaryFixed,
fontSize:
AppConfig.fontSizeFactor * AppConfig.messageFontSize,
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
),
children: [
if (trimmedBefore) const TextSpan(text: ''),
@ -491,7 +493,7 @@ class _ErrorBlankWidgetState extends State<_ErrorBlankWidget> {
translation,
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimaryFixed,
fontSize: AppConfig.fontSizeFactor *
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
fontStyle: FontStyle.italic,
),

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
class BotStyle {
@ -16,7 +17,7 @@ class BotStyle {
final TextStyle botStyle = TextStyle(
fontWeight: bold ? FontWeight.w700 : null,
fontSize: AppConfig.messageFontSize *
AppConfig.fontSizeFactor *
AppSettings.fontSizeFactor.value *
(big == true ? 1.2 : 1),
fontStyle: italics ? FontStyle.italic : null,
color: setColor ? Theme.of(context).colorScheme.primary : null,

View file

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:animations/animations.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/chat/chat.dart';
@ -201,10 +201,11 @@ class PangeaChatInputRow extends StatelessWidget {
maxLines: 8,
autofocus: !PlatformInfos.isMobile,
keyboardType: TextInputType.multiline,
textInputAction: AppConfig.sendOnEnter == true &&
PlatformInfos.isMobile
? TextInputAction.send
: null,
textInputAction:
AppSettings.sendOnEnter.value == true &&
PlatformInfos.isMobile
? TextInputAction.send
: null,
onSubmitted: (_) => controller.onInputBarSubmitted(),
onSubmitImage: controller.sendImageFromClipBoard,
focusNode: controller.inputFocus,

View file

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart';
import 'package:fluffychat/pangea/course_chats/open_roles_indicator.dart';
@ -25,7 +25,9 @@ class ChatListItemSubtitle extends StatelessWidget {
!event.redacted &&
event.type == EventTypes.Message &&
event.messageType == MessageTypes.Text &&
!(AppConfig.renderHtml && !event.redacted && event.isRichMessage);
!(AppSettings.renderHtml.value &&
!event.redacted &&
event.isRichMessage);
}
Future<PangeaMessageEvent> _getPangeaMessageEvent(

View file

@ -6,7 +6,6 @@ import 'package:get_storage/get_storage.dart';
import 'package:matrix/matrix.dart';
import 'package:provider/provider.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
@ -67,7 +66,7 @@ class PangeaController {
subscriptionController.reinitialize();
StyleSettingsRepo.settings(userID!).then((settings) {
AppConfig.fontSizeFactor = settings.fontSizeFactor;
AppSettings.fontSizeFactor.setItem(settings.fontSizeFactor);
AppConfig.useActivityImageAsChatBackground =
settings.useActivityImageBackground;
});
@ -136,18 +135,6 @@ class PangeaController {
futures.add(GetStorage(key).erase());
}
if (AppConfig.showedActivityMenu) {
futures.add(
SharedPreferences.getInstance().then((prefs) async {
AppConfig.showedActivityMenu = false;
prefs.setBool(
SettingKeys.showedActivityMenu,
AppConfig.showedActivityMenu,
);
}),
);
}
await Future.wait(futures);
}

View file

@ -35,6 +35,7 @@ enum InstructionsEnum {
dismissSupportChat,
shimmerNewToken,
shimmerTranslation,
showedActivityMenu,
}
extension InstructionsEnumExtension on InstructionsEnum {
@ -69,6 +70,7 @@ extension InstructionsEnumExtension on InstructionsEnum {
case InstructionsEnum.dismissSupportChat:
case InstructionsEnum.shimmerNewToken:
case InstructionsEnum.shimmerTranslation:
case InstructionsEnum.showedActivityMenu:
ErrorHandler.logError(
e: Exception("No title for this instruction"),
m: 'InstructionsEnumExtension.title',
@ -133,6 +135,7 @@ extension InstructionsEnumExtension on InstructionsEnum {
case InstructionsEnum.dismissSupportChat:
case InstructionsEnum.shimmerNewToken:
case InstructionsEnum.shimmerTranslation:
case InstructionsEnum.showedActivityMenu:
return "";
case InstructionsEnum.disableLanguageTools:
return l10n.disableLanguageToolsDesc;

View file

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/pangea/common/widgets/pangea_logo_svg.dart';
@ -78,7 +78,7 @@ class LoginOrSignupViewState extends State<LoginOrSignupView> {
forceColor: theme.colorScheme.onSurface,
),
Text(
AppConfig.applicationName,
AppSettings.applicationName.value,
style: theme.textTheme.headlineSmall
?.copyWith(fontWeight: FontWeight.bold),
),

View file

@ -2,7 +2,7 @@ import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/widgets/mxc_image.dart';
@ -84,7 +84,7 @@ class PangeaLoginScaffold extends StatelessWidget {
),
if (showAppName)
Text(
AppConfig.applicationName,
AppSettings.applicationName.value,
style: Theme.of(context).textTheme.displaySmall,
),
const SizedBox(height: 12),

View file

@ -6,6 +6,7 @@ import 'package:excel/excel.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/analytics_downloads/space_analytics_summary_enum.dart';
@ -289,7 +290,8 @@ class DownloadAnalyticsDialogState extends State<DownloadAnalyticsDialog> {
Text(
L10n.of(context).fileType,
style: TextStyle(
fontSize: AppConfig.fontSizeFactor * AppConfig.messageFontSize,
fontSize: AppSettings.fontSizeFactor.value *
AppConfig.messageFontSize,
),
),
Padding(

View file

@ -183,7 +183,7 @@ class _MainView extends StatelessWidget {
if (path == null) {
return ChatList(
activeChat: state.pathParameters['roomid'],
activeSpaceId: state.pathParameters['spaceid'],
activeSpace: state.pathParameters['spaceid'],
);
}
@ -220,7 +220,7 @@ class _MainView extends StatelessWidget {
return ChatList(
activeChat: state.pathParameters['roomid'],
activeSpaceId: state.pathParameters['spaceid'],
activeSpace: state.pathParameters['spaceid'],
);
}
}

View file

@ -154,7 +154,7 @@ class MessageSelectionPositionerState extends State<MessageSelectionPositioner>
widget.event.senderId == widget.event.room.client.userID;
bool get showDetails =>
AppSettings.displayChatDetailsColumn.getItem(Matrix.of(context).store) &&
AppSettings.displayChatDetailsColumn.value &&
FluffyThemes.isThreeColumnMode(context) &&
widget.chatController.room.membership == Membership.join;

View file

@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/pages/chat/events/audio_player.dart';
import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
@ -79,8 +80,8 @@ class MessageAudioCardState extends State<MessageAudioCard> {
senderId: widget.messageEvent.senderId,
matrixFile: audioFile,
color: Theme.of(context).colorScheme.onPrimaryContainer,
fontSize:
AppConfig.messageFontSize * AppConfig.fontSizeFactor,
fontSize: AppConfig.messageFontSize *
AppSettings.fontSizeFactor.value,
linkColor: Theme.of(context).brightness == Brightness.light
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onPrimary,

View file

@ -69,6 +69,7 @@ class BackgroundPush {
}
final pendingTests = <String, Completer<void>>{};
bool firebaseEnabled = false;
//<GOOGLE_SERVICES>final firebase = FcmSharedIsolate();
@ -77,6 +78,7 @@ class BackgroundPush {
bool upAction = false;
void _init() async {
//<GOOGLE_SERVICES>firebaseEnabled = true;
try {
// #Pangea
// Handle notifications when app is opened from terminated/background state
@ -346,8 +348,7 @@ class BackgroundPush {
currentPushers.first.data.url.toString() == gatewayUrl &&
currentPushers.first.data.format ==
// #Pangea
// AppSettings.pushNotificationsPusherFormat
// .getItem(matrix!.store) &&
// AppSettings.pushNotificationsPusherFormat.value &&
null &&
// Pangea#
mapEquals(
@ -393,8 +394,7 @@ class BackgroundPush {
data: PusherData(
url: Uri.parse(gatewayUrl!),
// #Pangea
// format: AppSettings.pushNotificationsPusherFormat
// .getItem(matrix!.store),
// format: AppSettings.pushNotificationsPusherFormat.value,
// Pangea#
additionalProperties: {"data_message": pusherDataMessageFormat},
),
@ -468,7 +468,7 @@ class BackgroundPush {
if (matrix == null) {
return;
}
if ((matrix?.store.getBool(SettingKeys.showNoGoogle) ?? false) == true) {
if (!AppSettings.showNoGoogle.value) {
return;
}
await loadLocale();
@ -499,15 +499,19 @@ class BackgroundPush {
}
}
await setupPusher(
gatewayUrl:
AppSettings.pushNotificationsGatewayUrl.getItem(matrix!.store),
gatewayUrl: AppSettings.pushNotificationsGatewayUrl.value,
token: _fcmToken,
);
}
Future<void> setupUp() async {
await UnifiedPushUi(matrix!.context, ["default"], UPFunctions())
.registerAppWithDialog();
await UnifiedPushUi(
context: matrix!.context,
instances: ["default"],
unifiedPushFunctions: UPFunctions(),
showNoDistribDialog: false,
onNoDistribDialogDismissed: () {}, // TODO: Implement me
).registerAppWithDialog();
}
Future<void> _newUpEndpoint(PushEndpoint newPushEndpoint, String i) async {
@ -552,18 +556,18 @@ class BackgroundPush {
oldTokens: oldTokens,
useDeviceSpecificAppId: true,
);
await matrix?.store.setString(SettingKeys.unifiedPushEndpoint, newEndpoint);
await matrix?.store.setBool(SettingKeys.unifiedPushRegistered, true);
await AppSettings.unifiedPushEndpoint.setItem(newEndpoint);
await AppSettings.unifiedPushRegistered.setItem(true);
}
Future<void> _upUnregistered(String i) async {
upAction = true;
Logs().i('[Push] Removing UnifiedPush endpoint...');
final oldEndpoint =
matrix?.store.getString(SettingKeys.unifiedPushEndpoint);
await matrix?.store.setBool(SettingKeys.unifiedPushRegistered, false);
await matrix?.store.remove(SettingKeys.unifiedPushEndpoint);
if (oldEndpoint?.isNotEmpty ?? false) {
final oldEndpoint = AppSettings.unifiedPushEndpoint.value;
await AppSettings.unifiedPushEndpoint
.setItem(AppSettings.unifiedPushEndpoint.defaultValue);
await AppSettings.unifiedPushRegistered.setItem(false);
if (oldEndpoint.isNotEmpty) {
// remove the old pusher
await setupPusher(
oldTokens: {oldEndpoint},

View file

@ -11,7 +11,6 @@ import 'package:matrix/matrix.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:universal_html/html.dart' as html;
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
@ -109,8 +108,8 @@ abstract class ClientManager {
String clientName,
SharedPreferences store,
) async {
final shareKeysWith = AppSettings.shareKeysWith.getItem(store);
final enableSoftLogout = AppSettings.enableSoftLogout.getItem(store);
final shareKeysWith = AppSettings.shareKeysWith.value;
final enableSoftLogout = AppSettings.enableSoftLogout.value;
return Client(
clientName,
@ -185,7 +184,7 @@ abstract class ClientManager {
await NotificationsClient().notify(
title,
body: body,
appName: AppConfig.applicationName,
appName: AppSettings.applicationName.value,
hints: [
NotificationHint.soundName('message-new-instant'),
],

View file

@ -5,6 +5,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/utils/client_manager.dart';
import 'package:fluffychat/utils/platform_infos.dart';
@ -57,13 +58,13 @@ extension InitWithRestoreExtension on Client {
? const FlutterSecureStorage()
: null;
await storage?.delete(
key: '${AppConfig.applicationName}_session_backup_$clientName',
key: '${AppSettings.applicationName.value}_session_backup_$clientName',
);
}
Future<void> initWithRestore({void Function()? onMigration}) async {
final storageKey =
'${AppConfig.applicationName}_session_backup_$clientName';
'${AppSettings.applicationName.value}_session_backup_$clientName';
final storage = PlatformInfos.isMobile || PlatformInfos.isLinux
? const FlutterSecureStorage()
: null;

View file

@ -1,13 +1,16 @@
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart';
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/filtered_timeline_extension.dart';
import '../../config/app_config.dart';
extension VisibleInGuiExtension on List<Event> {
List<Event> filterByVisibleInGui({String? exceptionEventId}) => where(
List<Event> filterByVisibleInGui({
String? exceptionEventId,
}) =>
where(
// #Pangea
// (event) => event.isVisibleInGui || event.eventId == exceptionEventId,
(event) =>
@ -28,18 +31,16 @@ extension IsStateExtension on Event {
// if a reaction has been redacted we also want it to be hidden in the timeline
!{EventTypes.Reaction, EventTypes.Redaction}.contains(type) &&
// if we enabled to hide all redacted events, don't show those
(!AppConfig.hideRedactedEvents || !redacted) &&
(!AppSettings.hideRedactedEvents.value || !redacted) &&
// if we enabled to hide all unknown events, don't show those
// #Pangea
// (!AppConfig.hideUnknownEvents || isEventTypeKnown);
(!AppConfig.hideUnknownEvents || pangeaIsEventTypeKnown) &&
(!isState || importantStateEvents.contains(type)) &&
// (!AppSettings.hideUnknownEvents.value || isEventTypeKnown);
(!AppSettings.hideUnknownEvents.value || pangeaIsEventTypeKnown) &&
content.tryGet(ModelKey.transcription) == null &&
// if sending of transcription fails,
// don't show it as a errored audio event in timeline.
((unsigned?['extra_content']
as Map<String, dynamic>?)?[ModelKey.transcription] ==
null);
null) &&
(!isState || importantStateEvents.contains(type));
// Pangea#
bool get isState => !{
@ -74,6 +75,7 @@ extension IsStateExtension on Event {
PangeaEventTypes.activityRole,
].contains(type);
// we're filtering out some state events that we don't want to render
static const Set<String> importantStateEvents = {
EventTypes.Encryption,
EventTypes.RoomCreate,

View file

@ -6,7 +6,6 @@ import 'package:flutter/services.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:matrix/matrix.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluffychat/config/setting_keys.dart';
@ -89,8 +88,7 @@ Future<String?> getDatabaseCipher() async {
}
void _sendNoEncryptionWarning(Object exception) async {
final store = await SharedPreferences.getInstance();
final isStored = AppSettings.noEncryptionWarningShown.getItem(store);
final isStored = AppSettings.noEncryptionWarningShown.value;
if (isStored == true) return;
@ -108,5 +106,5 @@ void _sendNoEncryptionWarning(Object exception) async {
// );
// Pangea#
await AppSettings.noEncryptionWarningShown.setItem(store, true);
await AppSettings.noEncryptionWarningShown.setItem(true);
}

View file

@ -6,7 +6,6 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_vodozemac/flutter_vodozemac.dart' as vod;
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/utils/client_download_content_extension.dart';
@ -59,7 +58,7 @@ void notificationTapBackground(
await vod.init();
_vodInitialized = true;
}
final store = await SharedPreferences.getInstance();
final store = await AppSettings.init();
final client = (await ClientManager.getClients(
initialize: false,
store: store,
@ -71,10 +70,6 @@ void notificationTapBackground(
waitUntilLoadCompletedLoaded: false,
);
AppConfig.sendPublicReadReceipts =
store.getBool(SettingKeys.sendPublicReadReceipts) ??
AppConfig.sendPublicReadReceipts;
if (!client.isLogged()) {
throw Exception('Notification tab in background but not logged in!');
}
@ -145,7 +140,7 @@ Future<void> notificationTap(
await room.setReadMarker(
payload.eventId ?? room.lastEvent!.eventId,
mRead: payload.eventId ?? room.lastEvent!.eventId,
public: AppConfig.sendPublicReadReceipts,
public: AppSettings.sendPublicReadReceipts.value,
);
case FluffyChatNotificationActions.reply:
final input = notificationResponse.input;

View file

@ -8,6 +8,7 @@ import 'package:package_info_plus/package_info_plus.dart';
import 'package:universal_html/html.dart' as html;
import 'package:url_launcher/url_launcher_string.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
import '../config/app_config.dart';
@ -46,7 +47,7 @@ abstract class PlatformInfos {
// Pangea#
static String get clientName =>
'${AppConfig.applicationName} ${isWeb ? 'web' : Platform.operatingSystem}${kReleaseMode ? '' : 'Debug'}';
'${AppSettings.applicationName.value} ${isWeb ? 'web' : Platform.operatingSystem}${kReleaseMode ? '' : 'Debug'}';
static Future<String> getVersion() async {
var version = kIsWeb ? 'Web' : 'Unknown';
@ -101,7 +102,7 @@ abstract class PlatformInfos {
height: 64,
filterQuality: FilterQuality.medium,
),
applicationName: AppConfig.applicationName,
applicationName: AppSettings.applicationName.value,
);
}

View file

@ -8,9 +8,9 @@ import 'package:collection/collection.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_shortcuts_new/flutter_shortcuts_new.dart';
import 'package:matrix/matrix.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/utils/client_download_content_extension.dart';
@ -60,7 +60,7 @@ Future<void> pushHelper(
l10n.incomingMessages,
number: notification.counts?.unread,
ticker: l10n.unreadChatsInApp(
AppConfig.applicationName,
AppSettings.applicationName.value,
(notification.counts?.unread ?? 0).toString(),
),
importance: Importance.high,
@ -98,7 +98,7 @@ Future<void> _tryPushHelper(
client ??= (await ClientManager.getClients(
initialize: false,
store: await SharedPreferences.getInstance(),
store: await AppSettings.init(),
))
.first;
final event = await client.getEventByPushNotification(
@ -300,25 +300,27 @@ Future<void> _tryPushHelper(
importance: Importance.high,
priority: Priority.max,
groupKey: event.room.spaceParents.firstOrNull?.roomId ?? 'rooms',
actions: <AndroidNotificationAction>[
AndroidNotificationAction(
FluffyChatNotificationActions.reply.name,
l10n.reply,
inputs: [
AndroidNotificationActionInput(
label: l10n.writeAMessage,
),
],
cancelNotification: false,
allowGeneratedReplies: true,
semanticAction: SemanticAction.reply,
),
AndroidNotificationAction(
FluffyChatNotificationActions.markAsRead.name,
l10n.markAsRead,
semanticAction: SemanticAction.markAsRead,
),
],
actions: event.type == EventTypes.RoomMember
? null
: <AndroidNotificationAction>[
AndroidNotificationAction(
FluffyChatNotificationActions.reply.name,
l10n.reply,
inputs: [
AndroidNotificationActionInput(
label: l10n.writeAMessage,
),
],
cancelNotification: false,
allowGeneratedReplies: true,
semanticAction: SemanticAction.reply,
),
AndroidNotificationAction(
FluffyChatNotificationActions.markAsRead.name,
l10n.markAsRead,
semanticAction: SemanticAction.markAsRead,
),
],
);
const iOSPlatformChannelSpecifics = DarwinNotificationDetails();
final platformChannelSpecifics = NotificationDetails(

View file

@ -30,7 +30,9 @@ class PublicRoomDialog extends StatelessWidget {
final result = await showFutureLoadingDialog<String>(
context: context,
future: () async {
if (chunk != null && client.getRoomById(chunk.roomId) != null) {
if (chunk != null &&
client.getRoomById(chunk.roomId) != null &&
client.getRoomById(chunk.roomId)?.membership != Membership.leave) {
return chunk.roomId;
}
final roomId = chunk != null && knock
@ -64,6 +66,8 @@ class PublicRoomDialog extends StatelessWidget {
if (chunk?.roomType != 'm.space' &&
!client.getRoomById(result.result!)!.isSpace) {
context.go('/rooms/$roomId');
} else {
context.go('/rooms?spaceId=$roomId');
}
return;
}

View file

@ -89,7 +89,6 @@ Future<String?> showTextInputDialog({
// Pangea#
maxLength: maxLength,
keyboardType: keyboardType,
obscureText: obscureText,
);
},
),

View file

@ -4,7 +4,6 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:matrix/matrix.dart';
import 'package:provider/provider.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/widgets/lock_screen.dart';
class AppLockWidget extends StatefulWidget {
@ -65,7 +64,7 @@ class AppLock extends State<AppLockWidget> with WidgetsBindingObserver {
Future<void> changePincode(String? pincode) async {
await const FlutterSecureStorage().write(
key: SettingKeys.appLockKey,
key: 'chat.fluffy.app_lock',
value: pincode,
);
_pincode = pincode;

View file

@ -21,6 +21,8 @@ class Avatar extends StatelessWidget {
final BorderRadius? borderRadius;
final IconData? icon;
final BorderSide? border;
final Color? backgroundColor;
final Color? textColor;
// #Pangea
final bool useRive;
final bool showPresence;
@ -42,6 +44,8 @@ class Avatar extends StatelessWidget {
this.borderRadius,
this.border,
this.icon,
this.backgroundColor,
this.textColor,
// #Pangea
this.useRive = false,
this.showPresence = true,
@ -80,7 +84,6 @@ class Avatar extends StatelessWidget {
side: border ?? BorderSide.none,
),
clipBehavior: Clip.antiAlias,
// #Pangea
// child: MxcImage(
child: (userId ?? presenceUserId) == BotName.byEnvironment
? BotFace(
@ -88,6 +91,7 @@ class Avatar extends StatelessWidget {
expression: BotExpression.idle,
useRive: useRive,
)
// #Pangea
: !(mxContent.toString().startsWith('mxc://'))
? ImageByUrl(
imageUrl: mxContent,
@ -101,6 +105,7 @@ class Avatar extends StatelessWidget {
),
borderRadius: borderRadius,
)
// Pangea#
: MxcImage(
// Pangea#
client: client,
@ -114,7 +119,8 @@ class Avatar extends StatelessWidget {
placeholder: (_) => noPic
? Container(
decoration: BoxDecoration(
color: name?.lightColorAvatar,
color:
backgroundColor ?? name?.lightColorAvatar,
),
alignment: Alignment.center,
child: Text(
@ -122,7 +128,7 @@ class Avatar extends StatelessWidget {
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'RobotoMono',
color: Colors.white,
color: textColor ?? Colors.white,
fontWeight: FontWeight.bold,
fontSize: (size / 2.5).roundToDouble(),
),

View file

@ -21,7 +21,7 @@ class _ConfigViewerState extends State<ConfigViewer> {
String initialValue,
) async {
if (appSetting is AppSettings<bool>) {
await appSetting.setItem(store, !(initialValue == 'true'));
await appSetting.setItem(!(initialValue == 'true'));
setState(() {});
return;
}
@ -35,13 +35,13 @@ class _ConfigViewerState extends State<ConfigViewer> {
if (value == null) return;
if (appSetting is AppSettings<String>) {
await appSetting.setItem(store, value);
await appSetting.setItem(value);
}
if (appSetting is AppSettings<int>) {
await appSetting.setItem(store, int.parse(value));
await appSetting.setItem(int.parse(value));
}
if (appSetting is AppSettings<double>) {
await appSetting.setItem(store, double.parse(value));
await appSetting.setItem(double.parse(value));
}
setState(() {});
@ -78,16 +78,16 @@ class _ConfigViewerState extends State<ConfigViewer> {
final appSetting = AppSettings.values[i];
var value = '';
if (appSetting is AppSettings<String>) {
value = appSetting.getItem(store);
value = appSetting.value;
}
if (appSetting is AppSettings<int>) {
value = appSetting.getItem(store).toString();
value = appSetting.value.toString();
}
if (appSetting is AppSettings<bool>) {
value = appSetting.getItem(store).toString();
value = appSetting.value.toString();
}
if (appSetting is AppSettings<double>) {
value = appSetting.getItem(store).toString();
value = appSetting.value.toString();
}
return ListTile(
title: Text(appSetting.name),

View file

@ -8,13 +8,13 @@ import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluffychat/config/routes.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart';
import 'package:fluffychat/pangea/languages/locale_provider.dart';
import 'package:fluffychat/widgets/app_lock.dart';
import 'package:fluffychat/widgets/theme_builder.dart';
import '../config/app_config.dart';
import '../utils/custom_scroll_behaviour.dart';
import 'matrix.dart';
@ -53,7 +53,7 @@ class FluffyChatApp extends StatelessWidget {
Widget build(BuildContext context) {
return ThemeBuilder(
builder: (context, themeMode, primaryColor) => MaterialApp.router(
title: AppConfig.applicationName,
title: AppSettings.applicationName.value,
themeMode: themeMode,
theme: FluffyThemes.buildTheme(context, Brightness.light, primaryColor),
darkTheme:

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:fluffychat/config/app_config.dart';
@ -132,7 +133,7 @@ class _PrivacyButtons extends StatelessWidget {
),
),
TextButton(
onPressed: () => launchUrlString(AppConfig.privacyUrl),
onPressed: () => launchUrl(AppConfig.privacyUrl),
child: Text(
L10n.of(context).privacy,
style: shadowTextStyle,

View file

@ -11,6 +11,7 @@ import 'package:permission_handler/permission_handler.dart';
import 'package:universal_html/html.dart' as html;
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/utils/client_download_content_extension.dart';
@ -122,7 +123,7 @@ extension LocalNotificationsExtension on MatrixState {
title,
body: body,
replacesId: linuxNotificationIds[roomId] ?? 0,
appName: AppConfig.applicationName,
appName: AppSettings.applicationName.value,
appIcon: 'fluffychat',
actions: [
NotificationAction(
@ -147,7 +148,7 @@ extension LocalNotificationsExtension on MatrixState {
event.room.setReadMarker(
event.eventId,
mRead: event.eventId,
public: AppConfig.sendPublicReadReceipts,
public: AppSettings.sendPublicReadReceipts.value,
);
break;
case DesktopNotificationActions.openChat:

View file

@ -7,7 +7,6 @@ import 'package:flutter/material.dart';
import 'package:app_links/app_links.dart';
import 'package:collection/collection.dart';
import 'package:desktop_notifications/desktop_notifications.dart';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:just_audio/just_audio.dart';
@ -19,13 +18,13 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:universal_html/html.dart' as html;
import 'package:url_launcher/url_launcher_string.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/analytics_data/analytics_data_service.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/utils/any_state_holder.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/languages/locale_provider.dart';
import 'package:fluffychat/pangea/user/style_settings_repo.dart';
import 'package:fluffychat/utils/client_manager.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart';
@ -34,7 +33,6 @@ import 'package:fluffychat/utils/voip_plugin.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
import 'package:fluffychat/widgets/fluffy_chat_app.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import '../config/app_config.dart';
import '../config/setting_keys.dart';
import '../pages/key_verification/key_verification_dialog.dart';
import '../utils/account_bundles.dart';
@ -192,7 +190,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
}
final candidate =
_loginClientCandidate ??= await ClientManager.createClient(
'${AppConfig.applicationName}-${DateTime.now().millisecondsSinceEpoch}',
'${AppSettings.applicationName.value}-${DateTime.now().millisecondsSinceEpoch}',
store,
)
..onLoginStateChanged
@ -283,11 +281,6 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
super.initState();
WidgetsBinding.instance.addObserver(this);
initMatrix();
if (PlatformInfos.isWeb) {
initConfig().then((_) => initSettings());
} else {
initSettings();
}
// #Pangea
Sentry.configureScope(
(scope) => scope.setUser(
@ -369,19 +362,6 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
}
// Pangea#
Future<void> initConfig() async {
try {
final configJsonString =
utf8.decode((await http.get(Uri.parse('config.json'))).bodyBytes);
final configJson = json.decode(configJsonString);
AppConfig.loadFromJson(configJson);
} on FormatException catch (_) {
Logs().v('[ConfigLoader] config.json not found');
} catch (e) {
Logs().v('[ConfigLoader] config.json not found', e);
}
}
void _registerSubs(String name) {
final c = getClientByName(name);
if (c == null) {
@ -528,7 +508,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
);
}
if (result == OkCancelResult.cancel) {
await store.setBool(SettingKeys.showNoGoogle, true);
await AppSettings.showNoGoogle.setItem(true);
}
},
);
@ -538,7 +518,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
}
void createVoipPlugin() async {
if (store.getBool(SettingKeys.experimentalVoip) == false) {
if (AppSettings.experimentalVoip.value) {
voipPlugin = null;
return;
}
@ -560,72 +540,6 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
}
}
void initSettings() {
// #Pangea
// AppConfig.fontSizeFactor =
// double.tryParse(store.getString(SettingKeys.fontSizeFactor) ?? '') ??
// AppConfig.fontSizeFactor;
if (client.isLogged()) {
StyleSettingsRepo.settings(client.userID!).then((settings) {
AppConfig.fontSizeFactor = settings.fontSizeFactor;
AppConfig.useActivityImageAsChatBackground =
settings.useActivityImageBackground;
});
}
// Pangea#
AppConfig.renderHtml =
store.getBool(SettingKeys.renderHtml) ?? AppConfig.renderHtml;
AppConfig.swipeRightToLeftToReply =
store.getBool(SettingKeys.swipeRightToLeftToReply) ??
AppConfig.swipeRightToLeftToReply;
AppConfig.hideRedactedEvents =
store.getBool(SettingKeys.hideRedactedEvents) ??
AppConfig.hideRedactedEvents;
AppConfig.hideUnknownEvents =
store.getBool(SettingKeys.hideUnknownEvents) ??
AppConfig.hideUnknownEvents;
AppConfig.separateChatTypes =
store.getBool(SettingKeys.separateChatTypes) ??
AppConfig.separateChatTypes;
AppConfig.autoplayImages =
store.getBool(SettingKeys.autoplayImages) ?? AppConfig.autoplayImages;
AppConfig.sendTypingNotifications =
store.getBool(SettingKeys.sendTypingNotifications) ??
AppConfig.sendTypingNotifications;
AppConfig.sendPublicReadReceipts =
store.getBool(SettingKeys.sendPublicReadReceipts) ??
AppConfig.sendPublicReadReceipts;
AppConfig.sendOnEnter =
store.getBool(SettingKeys.sendOnEnter) ?? AppConfig.sendOnEnter;
AppConfig.experimentalVoip = store.getBool(SettingKeys.experimentalVoip) ??
AppConfig.experimentalVoip;
AppConfig.showPresences =
store.getBool(SettingKeys.showPresences) ?? AppConfig.showPresences;
AppConfig.displayNavigationRail =
store.getBool(SettingKeys.displayNavigationRail) ??
AppConfig.displayNavigationRail;
// #Pangea
AppConfig.volume = store.getDouble(SettingKeys.volume) ?? AppConfig.volume;
AppConfig.showedActivityMenu =
store.getBool(SettingKeys.showedActivityMenu) ??
AppConfig.showedActivityMenu;
// Pangea#
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);

View file

@ -73,15 +73,8 @@ class SpacesNavigationRail extends StatelessWidget {
.where((s) => s.hasRoomUpdate)
.rateLimit(const Duration(seconds: 1)),
builder: (context, _) {
final allSpaces = client.rooms.where((room) => room.isSpace);
final rootSpaces = allSpaces
.where(
(space) => !allSpaces.any(
(parentSpace) => parentSpace.spaceChildren
.any((child) => child.roomId == space.id),
),
)
.toList();
final allSpaces =
client.rooms.where((room) => room.isSpace).toList();
// #Pangea
// return SizedBox(
@ -99,8 +92,8 @@ class SpacesNavigationRail extends StatelessWidget {
child: ListView.builder(
scrollDirection: Axis.vertical,
// #Pangea
// itemCount: rootSpaces.length + 2,
itemCount: rootSpaces.length + 3,
// itemCount: allSpaces.length + 2,
itemCount: allSpaces.length + 3,
// Pangea#
itemBuilder: (context, i) {
// #Pangea
@ -189,7 +182,7 @@ class SpacesNavigationRail extends StatelessWidget {
);
}
i--;
if (i == rootSpaces.length) {
if (i == allSpaces.length) {
return NaviRailItem(
// #Pangea
// isSelected: false,
@ -226,9 +219,9 @@ class SpacesNavigationRail extends StatelessWidget {
// Pangea#
);
}
final space = rootSpaces[i];
final space = allSpaces[i];
final displayname =
rootSpaces[i].getLocalizedDisplayname(
allSpaces[i].getLocalizedDisplayname(
MatrixLocals(L10n.of(context)),
);
final spaceChildrenIds =
@ -239,10 +232,10 @@ class SpacesNavigationRail extends StatelessWidget {
// #Pangea
backgroundColor: Colors.transparent,
borderRadius: BorderRadius.circular(0),
// onTap: () => onGoToSpaceId(rootSpaces[i].id),
// onTap: () => onGoToSpaceId(allSpaces[i].id),
onTap: () {
collapse();
final room = client.getRoomById(rootSpaces[i].id);
final room = client.getRoomById(allSpaces[i].id);
if (room != null) {
chatListHandleSpaceTap(
context,
@ -250,7 +243,7 @@ class SpacesNavigationRail extends StatelessWidget {
);
} else {
context.go(
"/rooms/spaces/${rootSpaces[i].id}/details",
"/rooms/spaces/${allSpaces[i].id}/details",
);
}
},
@ -259,7 +252,7 @@ class SpacesNavigationRail extends StatelessWidget {
spaceChildrenIds.contains(room.id),
// #Pangea
// icon: Avatar(
// mxContent: rootSpaces[i].avatar,
// mxContent: allSpaces[i].avatar,
// name: displayname,
// border: BorderSide(
// width: 1,
@ -271,7 +264,7 @@ class SpacesNavigationRail extends StatelessWidget {
// ),
icon: b.Badge(
showBadge:
rootSpaces[i].membership == Membership.invite,
allSpaces[i].membership == Membership.invite,
badgeStyle: b.BadgeStyle(
badgeColor: Theme.of(context).colorScheme.error,
elevation: 4,
@ -290,7 +283,7 @@ class SpacesNavigationRail extends StatelessWidget {
child: ClipPath(
clipper: MapClipper(),
child: Avatar(
mxContent: rootSpaces[i].avatar,
mxContent: allSpaces[i].avatar,
name: displayname,
border: BorderSide(
width: 1,

View file

@ -1,18 +1,16 @@
import 'package:flutter/material.dart';
import 'matrix.dart';
import 'package:fluffychat/config/setting_keys.dart';
class SettingsSwitchListTile extends StatefulWidget {
final bool defaultValue;
final String storeKey;
final AppSettings<bool> setting;
final String title;
final String? subtitle;
final Function(bool)? onChanged;
const SettingsSwitchListTile.adaptive({
super.key,
this.defaultValue = false,
required this.storeKey,
required this.setting,
required this.title,
this.subtitle,
this.onChanged,
@ -27,13 +25,12 @@ class SettingsSwitchListTileState extends State<SettingsSwitchListTile> {
Widget build(BuildContext context) {
final subtitle = widget.subtitle;
return SwitchListTile.adaptive(
value: Matrix.of(context).store.getBool(widget.storeKey) ??
widget.defaultValue,
value: widget.setting.value,
title: Text(widget.title),
subtitle: subtitle == null ? null : Text(subtitle),
onChanged: (bool newValue) async {
widget.onChanged?.call(newValue);
await Matrix.of(context).store.setBool(widget.storeKey, newValue);
await widget.setting.setItem(newValue);
setState(() {});
},
);

View file

@ -42,6 +42,8 @@ PODS:
- FlutterMacOS
- record_macos (1.1.0):
- FlutterMacOS
- screen_retriever_macos (0.0.1):
- FlutterMacOS
- share_plus (0.0.1):
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
@ -64,7 +66,12 @@ PODS:
- FlutterMacOS
- wakelock_plus (0.0.1):
- FlutterMacOS
- webcrypto (0.1.1):
- Flutter
- FlutterMacOS
- WebRTC-SDK (137.7151.04)
- window_manager (0.5.0):
- FlutterMacOS
- window_to_front (0.0.1):
- FlutterMacOS
@ -89,6 +96,7 @@ DEPENDENCIES:
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- record_macos (from `Flutter/ephemeral/.symlinks/plugins/record_macos/macos`)
- screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`)
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqlcipher_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlcipher_flutter_libs/macos`)
@ -96,6 +104,8 @@ DEPENDENCIES:
- video_compress (from `Flutter/ephemeral/.symlinks/plugins/video_compress/macos`)
- video_player_avfoundation (from `Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin`)
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
- webcrypto (from `Flutter/ephemeral/.symlinks/plugins/webcrypto/darwin`)
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
- window_to_front (from `Flutter/ephemeral/.symlinks/plugins/window_to_front/macos`)
SPEC REPOS:
@ -144,6 +154,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
record_macos:
:path: Flutter/ephemeral/.symlinks/plugins/record_macos/macos
screen_retriever_macos:
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos
share_plus:
:path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos
shared_preferences_foundation:
@ -158,6 +170,10 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin
wakelock_plus:
:path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos
webcrypto:
:path: Flutter/ephemeral/.symlinks/plugins/webcrypto/darwin
window_manager:
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
window_to_front:
:path: Flutter/ephemeral/.symlinks/plugins/window_to_front/macos
@ -182,6 +198,7 @@ SPEC CHECKSUMS:
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
record_macos: 43194b6c06ca6f8fa132e2acea72b202b92a0f5b
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
SQLCipher: eb79c64049cb002b4e9fcb30edb7979bf4706dfc
@ -190,7 +207,9 @@ SPEC CHECKSUMS:
video_compress: 752b161da855df2492dd1a8fa899743cc8fe9534
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
wakelock_plus: 917609be14d812ddd9e9528876538b2263aaa03b
webcrypto: a5f5eb3e375cf0a99993e207e97cdcab5c94ce2e
WebRTC-SDK: 40d4f5ba05cadff14e4db5614aec402a633f007e
window_manager: b729e31d38fb04905235df9ea896128991cad99e
window_to_front: 9e76fd432e36700a197dac86a0011e49c89abe0a
PODFILE CHECKSUM: d0975b16fbdecb73b109d8fbc88aa77ffe4c7a8d

View file

@ -45,10 +45,10 @@ packages:
dependency: "direct main"
description:
name: animations
sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb
sha256: a8031b276f0a7986ac907195f10ca7cd04ecf2a8a566bd6dbe03018a9b02b427
url: "https://pub.dev"
source: hosted
version: "2.0.11"
version: "2.1.0"
ansicolor:
dependency: transitive
description:
@ -1342,14 +1342,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.6.7"
js_interop:
dependency: transitive
description:
name: js_interop
sha256: "7ec859c296958ccea34dc770504bd3ff4ae52fdd9e7eeb2bacc7081ad476a1f5"
url: "https://pub.dev"
source: hosted
version: "0.0.1"
json_annotation:
dependency: transitive
description:
@ -1516,7 +1508,7 @@ packages:
path: "/Users/ggurdin/pangea/matrix-dart-sdk"
relative: false
source: path
version: "2.0.1"
version: "3.0.0"
meta:
dependency: transitive
description:
@ -2558,10 +2550,10 @@ packages:
dependency: "direct main"
description:
name: unifiedpush_ui
sha256: cf86f0214f37debd41f25c0425c8489df85e27f9f8784fed571eb7a86d39ba11
sha256: "1b36b2aa0bc6b61577e2661c1183bd3442969ecf77b4c78174796d324f66dd1d"
url: "https://pub.dev"
source: hosted
version: "0.1.0"
version: "0.2.0"
universal_html:
dependency: "direct main"
description:

View file

@ -12,7 +12,7 @@ environment:
sdk: ">=3.0.0 <4.0.0"
dependencies:
animations: ^2.0.11
animations: ^2.1.0
app_links: ^6.4.1
archive: ^4.0.7
async: ^2.11.0
@ -91,7 +91,7 @@ dependencies:
swipe_to_action: ^0.3.0
tor_detector_web: ^1.1.0
unifiedpush: ^6.2.0
unifiedpush_ui: ^0.1.0
unifiedpush_ui: ^0.2.0
universal_html: ^2.2.4
url_launcher: ^6.3.2
video_compress: ^3.1.4