diff --git a/commet/integration_test/benchmark/benchmark.dart b/commet/integration_test/benchmark/benchmark.dart index 6bcabddf9..d98fc2797 100644 --- a/commet/integration_test/benchmark/benchmark.dart +++ b/commet/integration_test/benchmark/benchmark.dart @@ -1,4 +1,5 @@ import 'package:integration_test/integration_test.dart'; + import 'benchmarks/timeline_viewer_benchmark.dart' as timeline; main() { diff --git a/commet/integration_test/benchmark/benchmarks/timeline_viewer_benchmark.dart b/commet/integration_test/benchmark/benchmarks/timeline_viewer_benchmark.dart index ea3f83b58..dbf089c83 100644 --- a/commet/integration_test/benchmark/benchmarks/timeline_viewer_benchmark.dart +++ b/commet/integration_test/benchmark/benchmarks/timeline_viewer_benchmark.dart @@ -11,12 +11,12 @@ void main() { testWidgets('Timeline Viewer Test', (tester) async { // Build our app and trigger a frame. - await tester.pumpWidget(MaterialApp( - theme: ThemeDark.theme, - home: const Scaffold( - body: BenchmarkTimelineViewer(), + await tester.pumpWidget( + MaterialApp( + theme: ThemeDark.theme, + home: const Scaffold(body: BenchmarkTimelineViewer()), ), - )); + ); await tester.pump(const Duration(seconds: 1)); @@ -25,18 +25,15 @@ void main() { var reportKey = 'TimelineViewer Scrolling'; - await binding.traceAction( - () async { - // Scroll until the item to be found appears. - await tester.scrollUntilVisible( - itemFinder, - 50.0, - maxScrolls: 10000, - scrollable: listFinder, - ); - }, - reportKey: reportKey, - ); + await binding.traceAction(() async { + // Scroll until the item to be found appears. + await tester.scrollUntilVisible( + itemFinder, + 50.0, + maxScrolls: 10000, + scrollable: listFinder, + ); + }, reportKey: reportKey); binding.reportData?[reportKey]["extra_values"] = [ { @@ -58,7 +55,7 @@ void main() { "name": "$reportKey - Timeline Event Message Url Preview Build Count", "value": BenchmarkValues.numTimelineUrlPreviewBuilt, "unit": "Builds", - } + }, ]; }); } diff --git a/commet/integration_test/extensions/common_flows.dart b/commet/integration_test/extensions/common_flows.dart index 29bfef85a..c955ffac9 100644 --- a/commet/integration_test/extensions/common_flows.dart +++ b/commet/integration_test/extensions/common_flows.dart @@ -16,8 +16,10 @@ extension CommonFlows on WidgetTester { const String.fromEnvironment('HOMESERVER', defaultValue: "localhost"); String get username => const String.fromEnvironment('USER1_NAME', defaultValue: "alice"); - String get password => const String.fromEnvironment('USER1_PW', - defaultValue: "AliceInWonderland"); + String get password => const String.fromEnvironment( + 'USER1_PW', + defaultValue: "AliceInWonderland", + ); String get userTwoName => const String.fromEnvironment('USER2_NAME', defaultValue: "bob"); @@ -81,8 +83,11 @@ extension CommonFlows on WidgetTester { await pumpAndSettle(); - await waitFor(() => app.clientManager.isLoggedIn(), - timeout: const Duration(seconds: 5), skipPumpAndSettle: true); + await waitFor( + () => app.clientManager.isLoggedIn(), + timeout: const Duration(seconds: 5), + skipPumpAndSettle: true, + ); expect(app.clientManager.isLoggedIn(), equals(true)); } @@ -104,8 +109,11 @@ extension CommonFlows on WidgetTester { await pumpAndSettle(); - await waitFor(() => app.clientManager.isLoggedIn(), - timeout: const Duration(seconds: 5), skipPumpAndSettle: true); + await waitFor( + () => app.clientManager.isLoggedIn(), + timeout: const Duration(seconds: 5), + skipPumpAndSettle: true, + ); expect(app.clientManager.isLoggedIn(), equals(true)); } @@ -137,8 +145,11 @@ extension CommonFlows on WidgetTester { } Future openSettings(App app) async { - await dragUntilVisible(find.byKey(SideNavigationBar.settingsKey), - find.byType(SideNavigationBar), const Offset(0, 20)); + await dragUntilVisible( + find.byKey(SideNavigationBar.settingsKey), + find.byType(SideNavigationBar), + const Offset(0, 20), + ); await tap(find.byKey(SideNavigationBar.settingsKey)); diff --git a/commet/integration_test/matrix/change_space_name_test.dart b/commet/integration_test/matrix/change_space_name_test.dart index 591a49c83..f33528230 100644 --- a/commet/integration_test/matrix/change_space_name_test.dart +++ b/commet/integration_test/matrix/change_space_name_test.dart @@ -9,6 +9,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:tiamat/tiamat.dart' as tiamat; + import '../extensions/common_flows.dart'; import '../generated/l10n.dart'; @@ -47,8 +48,10 @@ void main() { expect(space.displayName, equals(newName)); - expect(find.widgetWithText(SpaceHeader, newName).evaluate().isNotEmpty, - isTrue); + expect( + find.widgetWithText(SpaceHeader, newName).evaluate().isNotEmpty, + isTrue, + ); }); } @@ -63,7 +66,11 @@ Future _openSpaceSettings(WidgetTester tester) async { } Future _openSpaceAppearanceSettings(WidgetTester tester) async { - await tester.tap(find.widgetWithText( - tiamat.TextButton, T.current.labelSpaceAppearanceSettings)); + await tester.tap( + find.widgetWithText( + tiamat.TextButton, + T.current.labelSpaceAppearanceSettings, + ), + ); await tester.pumpAndSettle(); } diff --git a/commet/integration_test/matrix/create_space_test.dart b/commet/integration_test/matrix/create_space_test.dart index 3c7ca30b2..8a23b1ad0 100644 --- a/commet/integration_test/matrix/create_space_test.dart +++ b/commet/integration_test/matrix/create_space_test.dart @@ -7,6 +7,7 @@ import 'package:commet/main.dart'; import 'package:integration_test/integration_test.dart'; import '../extensions/common_flows.dart'; + import 'package:tiamat/tiamat.dart' as tiamat; import '../generated/l10n.dart'; @@ -27,13 +28,16 @@ void main() { var client = app.clientManager.clients.first; - expect(client.spaces.any((element) => element.displayName == spaceName), - isTrue); expect( - client.spaces - .firstWhere((element) => element.displayName == spaceName) - .visibility, - equals(RoomVisibility.invite)); + client.spaces.any((element) => element.displayName == spaceName), + isTrue, + ); + expect( + client.spaces + .firstWhere((element) => element.displayName == spaceName) + .visibility, + equals(RoomVisibility.invite), + ); await app.clientManager.close(); await tester.clean(); @@ -52,13 +56,16 @@ void main() { var client = app.clientManager.clients.first; - expect(client.spaces.any((element) => element.displayName == spaceName), - isTrue); expect( - client.spaces - .firstWhere((element) => element.displayName == spaceName) - .visibility, - equals(RoomVisibility.public)); + client.spaces.any((element) => element.displayName == spaceName), + isTrue, + ); + expect( + client.spaces + .firstWhere((element) => element.displayName == spaceName) + .visibility, + equals(RoomVisibility.public), + ); await app.clientManager.close(); await tester.clean(); @@ -66,20 +73,20 @@ void main() { } Future _confirmCreateSpace(WidgetTester tester) async { - await tester.tap(find - .widgetWithText(tiamat.Button, T.current.promptConfirmSpaceCreation) - .first); + await tester.tap( + find + .widgetWithText(tiamat.Button, T.current.promptConfirmSpaceCreation) + .first, + ); await tester.pumpAndSettle(); } Future _setSpaceName(WidgetTester tester, String spaceName) async { await tester.enterText( - find.widgetWithText( - tiamat.TextInput, - T.current.promptSpaceName, - ), - spaceName); + find.widgetWithText(tiamat.TextInput, T.current.promptSpaceName), + spaceName, + ); } Future _setPrivate(WidgetTester tester) async { @@ -87,9 +94,14 @@ Future _setPrivate(WidgetTester tester) async { await tester.pumpAndSettle(); - await tester.tap(find - .widgetWithText(tiamat.Text, T.current.spaceVisibilityPrivateExplanation) - .last); + await tester.tap( + find + .widgetWithText( + tiamat.Text, + T.current.spaceVisibilityPrivateExplanation, + ) + .last, + ); await tester.pumpAndSettle(); } @@ -99,9 +111,11 @@ Future _setPublic(WidgetTester tester) async { await tester.pumpAndSettle(); - await tester.tap(find - .widgetWithText(tiamat.Text, T.current.spaceVisibilityPublicExplanation) - .last); + await tester.tap( + find + .widgetWithText(tiamat.Text, T.current.spaceVisibilityPublicExplanation) + .last, + ); await tester.pumpAndSettle(); } @@ -114,16 +128,18 @@ Future _openMenu(WidgetTester tester, App app) async { await tester.pumpAndSettle(); await tester.dragUntilVisible( - find.widgetWithIcon(tiamat.ImageButton, Icons.add), - find.byType(SpaceSelector), - const Offset(0, 50)); + find.widgetWithIcon(tiamat.ImageButton, Icons.add), + find.byType(SpaceSelector), + const Offset(0, 50), + ); await tester.tap(find.widgetWithIcon(tiamat.ImageButton, Icons.add)); await tester.pumpAndSettle(); - await tester - .tap(find.widgetWithText(InkWell, T.current.promptCreateNewSpace)); + await tester.tap( + find.widgetWithText(InkWell, T.current.promptCreateNewSpace), + ); await tester.pumpAndSettle(); } diff --git a/commet/integration_test/matrix/key_verification_test.dart b/commet/integration_test/matrix/key_verification_test.dart index 75465daac..917ad8640 100644 --- a/commet/integration_test/matrix/key_verification_test.dart +++ b/commet/integration_test/matrix/key_verification_test.dart @@ -4,13 +4,15 @@ import 'package:commet/utils/common_strings.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:matrix/encryption/utils/key_verification.dart'; + import '../extensions/wait_for.dart'; import '../extensions/common_flows.dart'; import '../generated/l10n.dart'; void main() { - testWidgets('Test emoji verification started from another device', - (WidgetTester tester) async { + testWidgets('Test emoji verification started from another device', ( + WidgetTester tester, + ) async { var app = await tester.setupApp(); await tester.pumpWidget(app); await tester.login(app); @@ -22,31 +24,36 @@ void main() { var client = matrixClient.getMatrixClient(); var devices = await otherClient.getDevices(); - var device = - devices!.firstWhere((element) => element.deviceId == client.deviceID); + var device = devices!.firstWhere( + (element) => element.deviceId == client.deviceID, + ); expect(device, isNotNull); var verification = await otherClient - .userDeviceKeys[otherClient.userID]!.deviceKeys[device.deviceId]! + .userDeviceKeys[otherClient.userID]! + .deviceKeys[device.deviceId]! .startVerification(); verification.onUpdate = () {}; await tester.waitFor( - () => find.byType(MatrixVerificationPage).evaluate().isNotEmpty); + () => find.byType(MatrixVerificationPage).evaluate().isNotEmpty, + ); await tester.pumpAndSettle(); var button = find.descendant( - of: find.byType(MatrixVerificationPage), - matching: - find.widgetWithText(ElevatedButton, CommonStrings.promptAccept)); + of: find.byType(MatrixVerificationPage), + matching: find.widgetWithText(ElevatedButton, CommonStrings.promptAccept), + ); await tester.tap(button); - await tester.waitFor(() => find - .widgetWithText(ElevatedButton, T.current.promptConfirmEmojiMatches) - .evaluate() - .isNotEmpty); + await tester.waitFor( + () => find + .widgetWithText(ElevatedButton, T.current.promptConfirmEmojiMatches) + .evaluate() + .isNotEmpty, + ); await tester.pumpAndSettle(); @@ -56,10 +63,12 @@ void main() { await verification.acceptSas(); - await tester.waitFor(() => find - .widgetWithText(ElevatedButton, T.current.messageVerificationComplete) - .evaluate() - .isNotEmpty); + await tester.waitFor( + () => find + .widgetWithText(ElevatedButton, T.current.messageVerificationComplete) + .evaluate() + .isNotEmpty, + ); await tester.pumpAndSettle(); @@ -67,12 +76,14 @@ void main() { expect(verification.state, equals(KeyVerificationState.done)); expect( - client.userDeviceKeys[client.userID]!.deviceKeys[otherClient.deviceID!], - isNotNull); + client.userDeviceKeys[client.userID]!.deviceKeys[otherClient.deviceID!], + isNotNull, + ); expect( - otherClient - .userDeviceKeys[otherClient.userID]!.deviceKeys[client.deviceID!], - isNotNull); + otherClient.userDeviceKeys[otherClient.userID]!.deviceKeys[client + .deviceID!], + isNotNull, + ); await app.clientManager.close(); await otherClient.dispose(); diff --git a/commet/integration_test/matrix/login_test.dart b/commet/integration_test/matrix/login_test.dart index c93df4bd5..a6f1df72f 100644 --- a/commet/integration_test/matrix/login_test.dart +++ b/commet/integration_test/matrix/login_test.dart @@ -19,8 +19,11 @@ void main() { await tester.login(app); - await tester.waitFor(() => app.clientManager.isLoggedIn(), - timeout: const Duration(seconds: 5), skipPumpAndSettle: true); + await tester.waitFor( + () => app.clientManager.isLoggedIn(), + timeout: const Duration(seconds: 5), + skipPumpAndSettle: true, + ); expect(app.clientManager.isLoggedIn(), equals(true)); await app.clientManager.close(); @@ -28,8 +31,10 @@ void main() { }); testWidgets('Test Matrix Login Invalid', (WidgetTester tester) async { - var hs = - const String.fromEnvironment('HOMESERVER', defaultValue: "localhost"); + var hs = const String.fromEnvironment( + 'HOMESERVER', + defaultValue: "localhost", + ); var username = "invalidUser"; var password = "InvalidPassword!"; @@ -53,9 +58,10 @@ void main() { await tester.tap(button); await tester.waitFor( - () => find.text(T.current.messageLoginFailed).evaluate().isNotEmpty, - skipPumpAndSettle: false, - timeout: const Duration(seconds: 5)); + () => find.text(T.current.messageLoginFailed).evaluate().isNotEmpty, + skipPumpAndSettle: false, + timeout: const Duration(seconds: 5), + ); await tester.pumpFrames(app, const Duration(seconds: 1)); expect(app.clientManager.isLoggedIn(), equals(false)); diff --git a/commet/integration_test/matrix/multi_account_test.dart b/commet/integration_test/matrix/multi_account_test.dart index c18c121b0..8f05d1a67 100644 --- a/commet/integration_test/matrix/multi_account_test.dart +++ b/commet/integration_test/matrix/multi_account_test.dart @@ -4,6 +4,7 @@ import 'package:integration_test/integration_test.dart'; import '../extensions/wait_for.dart'; import '../extensions/common_flows.dart'; + import 'package:tiamat/tiamat.dart' as tiamat; import '../generated/l10n.dart'; @@ -18,24 +19,37 @@ void main() { await tester.pumpWidget(app); await tester.login(app); - await tester.waitFor(() => app.clientManager.isLoggedIn(), - timeout: const Duration(seconds: 5), skipPumpAndSettle: true); + await tester.waitFor( + () => app.clientManager.isLoggedIn(), + timeout: const Duration(seconds: 5), + skipPumpAndSettle: true, + ); await tester.openSettings(app); - await tester.waitFor(() => find - .widgetWithText( - tiamat.TextButton, T.current.labelSettingsTabManageAccounts) - .evaluate() - .isNotEmpty); - - await tester.tap(find.widgetWithText( - tiamat.TextButton, T.current.labelSettingsTabManageAccounts)); - - await tester.waitFor(() => find - .byKey(AccountManagementSettingsTab.addAccountKey) - .evaluate() - .isNotEmpty); + await tester.waitFor( + () => find + .widgetWithText( + tiamat.TextButton, + T.current.labelSettingsTabManageAccounts, + ) + .evaluate() + .isNotEmpty, + ); + + await tester.tap( + find.widgetWithText( + tiamat.TextButton, + T.current.labelSettingsTabManageAccounts, + ), + ); + + await tester.waitFor( + () => find + .byKey(AccountManagementSettingsTab.addAccountKey) + .evaluate() + .isNotEmpty, + ); await tester.tap(find.byKey(AccountManagementSettingsTab.addAccountKey)); @@ -45,11 +59,13 @@ void main() { expect(app.clientManager.clients.length, equals(2)); expect( - app.clientManager.clients - .where((client) => - client.self!.identifier.contains(tester.userTwoName)) - .isNotEmpty, - isTrue); + app.clientManager.clients + .where( + (client) => client.self!.identifier.contains(tester.userTwoName), + ) + .isNotEmpty, + isTrue, + ); await app.clientManager.close(); await tester.clean(); @@ -62,31 +78,45 @@ void main() { await tester.pumpWidget(app); await tester.login(app); - await tester.waitFor(() => app.clientManager.isLoggedIn(), - timeout: const Duration(seconds: 5), skipPumpAndSettle: true); + await tester.waitFor( + () => app.clientManager.isLoggedIn(), + timeout: const Duration(seconds: 5), + skipPumpAndSettle: true, + ); await tester.openSettings(app); - await tester.waitFor(() => find - .widgetWithText( - tiamat.TextButton, T.current.labelSettingsTabManageAccounts) - .evaluate() - .isNotEmpty); - - await tester.tap(find.widgetWithText( - tiamat.TextButton, T.current.labelSettingsTabManageAccounts)); - - await tester.waitFor(() => find - .byKey(AccountManagementSettingsTab.addAccountKey) - .evaluate() - .isNotEmpty); + await tester.waitFor( + () => find + .widgetWithText( + tiamat.TextButton, + T.current.labelSettingsTabManageAccounts, + ) + .evaluate() + .isNotEmpty, + ); + + await tester.tap( + find.widgetWithText( + tiamat.TextButton, + T.current.labelSettingsTabManageAccounts, + ), + ); + + await tester.waitFor( + () => find + .byKey(AccountManagementSettingsTab.addAccountKey) + .evaluate() + .isNotEmpty, + ); await tester.tap(find.byKey(AccountManagementSettingsTab.addAccountKey)); await tester.login(app); - await tester.waitFor(() => - find.text(T.current.messageAlreadyLoggedIn).evaluate().isNotEmpty); + await tester.waitFor( + () => find.text(T.current.messageAlreadyLoggedIn).evaluate().isNotEmpty, + ); expect(app.clientManager.clients.length, equals(1)); diff --git a/commet/integration_test/runner.dart b/commet/integration_test/runner.dart index f23f63955..cb2e9850b 100644 --- a/commet/integration_test/runner.dart +++ b/commet/integration_test/runner.dart @@ -3,6 +3,7 @@ import 'package:commet/main.dart'; import 'package:flutter/material.dart'; import 'package:integration_test/integration_test.dart'; + import 'generated/l10n.dart'; import 'matrix/login_test.dart' as login_test; import 'matrix/key_verification_test.dart' as key_verification_test; diff --git a/commet/lib/cache/cache_file_provider.dart b/commet/lib/cache/cache_file_provider.dart index 27194a194..8b1ff08db 100644 --- a/commet/lib/cache/cache_file_provider.dart +++ b/commet/lib/cache/cache_file_provider.dart @@ -11,7 +11,7 @@ class CacheFileProvider implements FileProvider { CacheFileProvider(this.fileIdentifier, this.getter); CacheFileProvider.thumbnail(String fileId, this.getter) - : fileIdentifier = "thumbnail_$fileId"; + : fileIdentifier = "thumbnail_$fileId"; @override Future resolve({String? savePath}) async { diff --git a/commet/lib/cache/drift_file_cache.dart b/commet/lib/cache/drift_file_cache.dart index 872fd6b52..ed0d3b1b9 100644 --- a/commet/lib/cache/drift_file_cache.dart +++ b/commet/lib/cache/drift_file_cache.dart @@ -1,4 +1,5 @@ import 'dart:io'; + import 'package:commet/cache/file_cache.dart'; import 'package:commet/config/app_config.dart'; import 'package:commet/config/build_config.dart'; @@ -46,10 +47,11 @@ class DriftFileCache implements FileCache { var cutoffTime = now.subtract(const Duration(days: 5)); var timeMs = cutoffTime.millisecondsSinceEpoch; - var removeFiles = await (db.select(db.fileCacheEntry) - ..where( - (tbl) => tbl.lastAccessedTimestamp.isSmallerThanValue(timeMs))) - .get(); + var removeFiles = + await (db.select(db.fileCacheEntry)..where( + (tbl) => tbl.lastAccessedTimestamp.isSmallerThanValue(timeMs), + )) + .get(); var allFiles = await (db.select(db.fileCacheEntry).get()); @@ -60,9 +62,9 @@ class DriftFileCache implements FileCache { } var removedIds = removeFiles.map((e) => e.id).toList(); - await (db.delete(db.fileCacheEntry) - ..where((tbl) => tbl.id.isIn(removedIds))) - .go(); + await (db.delete( + db.fileCacheEntry, + )..where((tbl) => tbl.id.isIn(removedIds))).go(); } Future _cleanFile(FileCacheEntryData entry) async { @@ -81,7 +83,9 @@ class DriftFileCache implements FileCache { @override Future fetchFile( - String identifier, Future Function() getter) async { + String identifier, + Future Function() getter, + ) async { var existing = await getFile(identifier); if (existing != null) return existing; @@ -94,9 +98,10 @@ class DriftFileCache implements FileCache { await file.writeAsBytes(bytes); var entry = FileCacheEntryCompanion.insert( - id: identifier, - path: path, - lastAccessedTimestamp: DateTime.now().millisecondsSinceEpoch); + id: identifier, + path: path, + lastAccessedTimestamp: DateTime.now().millisecondsSinceEpoch, + ); final db = await get(); await db.into(db.fileCacheEntry).insertOnConflictUpdate(entry); @@ -111,8 +116,13 @@ class DriftFileCache implements FileCache { if (entry == null) return null; //var lastAccess = DateTime.fromMillisecondsSinceEpoch(entry!.lastAccessedTimestamp).toLocal().toString(); final db = await get(); - db.into(db.fileCacheEntry).insertOnConflictUpdate(entry.copyWith( - lastAccessedTimestamp: DateTime.now().millisecondsSinceEpoch)); + db + .into(db.fileCacheEntry) + .insertOnConflictUpdate( + entry.copyWith( + lastAccessedTimestamp: DateTime.now().millisecondsSinceEpoch, + ), + ); var file = File(entry.path); @@ -127,8 +137,9 @@ class DriftFileCache implements FileCache { // if the file exists in the database but not on disk, we should remove it from db var exists = await File(file.path).exists(); if (!exists) - (db.delete(db.fileCacheEntry)..where((tbl) => tbl.id.equals(file.id))) - .go(); + (db.delete( + db.fileCacheEntry, + )..where((tbl) => tbl.id.equals(file.id))).go(); return exists; } @@ -162,9 +173,10 @@ class DriftFileCache implements FileCache { await file.writeAsBytes(bytes); var entry = FileCacheEntryCompanion.insert( - id: identifier, - path: path, - lastAccessedTimestamp: DateTime.now().millisecondsSinceEpoch); + id: identifier, + path: path, + lastAccessedTimestamp: DateTime.now().millisecondsSinceEpoch, + ); await db.into(db.fileCacheEntry).insertOnConflictUpdate(entry); @@ -188,9 +200,11 @@ class DriftFileCache implements FileCache { Future generateTempFilePath() async { var path = ""; - for (path = await newPath(); - await File(path).exists(); - path = await newPath()) {} + for ( + path = await newPath(); + await File(path).exists(); + path = await newPath() + ) {} return path; } diff --git a/commet/lib/client/alert.dart b/commet/lib/client/alert.dart index c0547e27d..04612e242 100644 --- a/commet/lib/client/alert.dart +++ b/commet/lib/client/alert.dart @@ -12,10 +12,12 @@ class Alert { String get title => _titleGetter(); String get message => _messageGetter(); - Alert(this.type, - {required String Function() messageGetter, - required String Function() titleGetter, - this.action}) { + Alert( + this.type, { + required String Function() messageGetter, + required String Function() titleGetter, + this.action, + }) { _messageGetter = messageGetter; _titleGetter = titleGetter; } diff --git a/commet/lib/client/attachment.dart b/commet/lib/client/attachment.dart index a9dea0881..3d1c1392a 100644 --- a/commet/lib/client/attachment.dart +++ b/commet/lib/client/attachment.dart @@ -25,8 +25,13 @@ class PendingFileAttachment { Size? dimensions; Duration? length; - PendingFileAttachment( - {this.name, this.path, this.data, this.mimeType, this.size}) { + PendingFileAttachment({ + this.name, + this.path, + this.data, + this.mimeType, + this.size, + }) { assert(path != null || data != null); mimeType ??= Mime.lookupType(path ?? name ?? "", data: data); @@ -96,13 +101,15 @@ class VideoAttachment extends FileAttachment { final Uri? streamUrl; - VideoAttachment(super.file, - {super.name, - required super.mimeType, - this.thumbnail, - this.streamUrl, - this.width, - this.height, - this.duration, - super.fileSize}); + VideoAttachment( + super.file, { + super.name, + required super.mimeType, + this.thumbnail, + this.streamUrl, + this.width, + this.height, + this.duration, + super.fileSize, + }); } diff --git a/commet/lib/client/call_manager.dart b/commet/lib/client/call_manager.dart index 39a66d097..075e31e98 100644 --- a/commet/lib/client/call_manager.dart +++ b/commet/lib/client/call_manager.dart @@ -22,22 +22,24 @@ class CallManager { StreamController.broadcast(); String notificationContentUserIsCalling(String user) => Intl.message( - "$user is calling!", - desc: - "Notification body content for when receiving an incoming call from another user", - args: [user], - name: "notificationContentUserIsCalling"); - - String notificationTitleIncomingCall(String roomName) => - Intl.message("Incoming Call! ($roomName)", - desc: "Notification title for when a call is being received", - args: [roomName], - name: "notificationTitleIncomingCall"); + "$user is calling!", + desc: "Notification body content for when receiving an incoming call from another user", + args: [user], + name: "notificationContentUserIsCalling", + ); + + String notificationTitleIncomingCall(String roomName) => Intl.message( + "Incoming Call! ($roomName)", + desc: "Notification title for when a call is being received", + args: [roomName], + name: "notificationTitleIncomingCall", + ); Stream get onSessionStarted => _onSessionStarted.stream; - NotifyingList currentSessions = - NotifyingList.empty(growable: true); + NotifyingList currentSessions = NotifyingList.empty( + growable: true, + ); CallManager(this.clientManager) { clientManager.onClientAdded.stream.listen(_onClientAdded); @@ -71,10 +73,12 @@ class CallManager { var member = room?.getMemberOrFallback(event.remoteUserId!); - NotificationManager.notify(CallNotificationContent( + NotificationManager.notify( + CallNotificationContent( title: notificationTitleIncomingCall(event.roomName), content: notificationContentUserIsCalling( - event.remoteUserName ?? event.remoteUserId!), + event.remoteUserName ?? event.remoteUserId!, + ), roomId: event.roomId, roomName: event.roomName, senderName: member?.displayName ?? event.remoteUserId!, @@ -85,10 +89,13 @@ class CallManager { senderImageId: member?.avatarId, roomImageId: room?.avatarId, clientId: event.client.identifier, - isDirectMessage: event.client + isDirectMessage: + event.client .getComponent() ?.isRoomDirectMessage(room!) == - true)); + true, + ), + ); } if (event.state == VoipState.outgoing) { @@ -121,22 +128,25 @@ class CallManager { } void removeOverlay() { - for (var existing in WidgetComponent.currentSessions - .where((i) => i.info.type == VoipOverlay.widgetId)) { + for (var existing in WidgetComponent.currentSessions.where( + (i) => i.info.type == VoipOverlay.widgetId, + )) { existing.dispose(); } } void onSessionEnded(VoipSession event) { - currentSessions - .removeWhere((element) => element.sessionId == event.sessionId); + currentSessions.removeWhere( + (element) => element.sessionId == event.sessionId, + ); if (currentSessions.where((e) => e.state == VoipState.incoming).isEmpty) { stopRingtone(); } - for (var existing in WidgetComponent.currentSessions - .where((i) => i.info.type == VoipOverlay.widgetId)) { + for (var existing in WidgetComponent.currentSessions.where( + (i) => i.info.type == VoipOverlay.widgetId, + )) { existing.dispose(); } @@ -146,7 +156,8 @@ class CallManager { VoipSession? getCallInRoom(Client client, String roomId) { return currentSessions .where( - (element) => element.client == client && element.roomId == roomId) + (element) => element.client == client && element.roomId == roomId, + ) .firstOrNull; } diff --git a/commet/lib/client/client.dart b/commet/lib/client/client.dart index ec5a46e04..1aa7de715 100644 --- a/commet/lib/client/client.dart +++ b/commet/lib/client/client.dart @@ -31,13 +31,7 @@ class ClientConnectionStatusUpdate { enum ClientConnectionStatus { unknown, connected, connecting, disconnected } -enum RoomType { - defaultRoom, - photoAlbum, - space, - voipRoom, - calendar; -} +enum RoomType { defaultRoom, photoAlbum, space, voipRoom, calendar } extension ToIcon on RoomType { IconData get icon { @@ -145,7 +139,7 @@ abstract class Client { NotifyingListFilter get favoriteRooms; StoredStreamController - get connectionStatusChanged; + get connectionStatusChanged; Future init(bool loadingFromCache, {bool isBackgroundService = false}); diff --git a/commet/lib/client/client_manager.dart b/commet/lib/client/client_manager.dart index e5240907d..500a50dbd 100644 --- a/commet/lib/client/client_manager.dart +++ b/commet/lib/client/client_manager.dart @@ -66,8 +66,9 @@ class ClientManager { List get spaces => _spaces; - final NotifyingList _clientsList = - NotifyingList.empty(growable: true); + final NotifyingList _clientsList = NotifyingList.empty( + growable: true, + ); final Map> _clientSubscriptions = {}; NotifyingList get clients => _clientsList; @@ -105,8 +106,10 @@ class ClientManager { final newClientManager = ClientManager(); await Future.wait([ - MatrixClient.loadFromDB(newClientManager, - isBackgroundService: isBackgroundService), + MatrixClient.loadFromDB( + newClientManager, + isBackgroundService: isBackgroundService, + ), ]); return newClientManager; @@ -128,16 +131,20 @@ class ClientManager { _clientSubscriptions[client] = [ client.onSync.listen((_) => _synced()), - client.onTimelineEvent - .listen((i) => _onEventReceived.add((client, i.$1, i.$2))), + client.onTimelineEvent.listen( + (i) => _onEventReceived.add((client, i.$1, i.$2)), + ), client.onRoomAdded.listen((room) => _onClientAddedRoom(client, room)), - client.onRoomRemoved - .listen((room) => _onClientRemovedRoom(client, room)), + client.onRoomRemoved.listen( + (room) => _onClientRemovedRoom(client, room), + ), client.onSpaceAdded.listen((space) => _addSpace(client, space)), - client.onSpaceRemoved - .listen((space) => _onClientRemovedSpace(client, space)), - client.connectionStatusChanged.stream - .listen((event) => _onClientConnectionStatusChanged(client, event)), + client.onSpaceRemoved.listen( + (space) => _onClientRemovedSpace(client, space), + ), + client.connectionStatusChanged.stream.listen( + (event) => _onClientConnectionStatusChanged(client, event), + ), ]; onClientAdded.add(_clients.length - 1); @@ -145,7 +152,9 @@ class ClientManager { } void _onClientConnectionStatusChanged( - Client client, ClientConnectionStatusUpdate status) { + Client client, + ClientConnectionStatusUpdate status, + ) { if (status.status == ClientConnectionStatus.connected) { return; } @@ -205,10 +214,11 @@ class ClientManager { } var clientInfo = StalePeerInfo( - index: clientIndex, - displayName: client.self!.displayName, - identifier: client.self!.identifier, - avatar: client.self!.avatar); + index: clientIndex, + displayName: client.self!.displayName, + identifier: client.self!.identifier, + avatar: client.self!.avatar, + ); for (int i = rooms.length - 1; i >= 0; i--) { if (rooms[i].client == client) { diff --git a/commet/lib/client/components/activities/activities_component.dart b/commet/lib/client/components/activities/activities_component.dart index b82dc2a01..c6d42c2dc 100644 --- a/commet/lib/client/components/activities/activities_component.dart +++ b/commet/lib/client/components/activities/activities_component.dart @@ -17,13 +17,14 @@ class RoomActivitySession { UserWidgetInfo? associatedWidget; - RoomActivitySession( - {required this.participants, - required this.application, - this.thirdparty = true, - required this.icon, - this.associatedWidget, - String? appName}) { + RoomActivitySession({ + required this.participants, + required this.application, + this.thirdparty = true, + required this.icon, + this.associatedWidget, + String? appName, + }) { this.knownName = appName; } } diff --git a/commet/lib/client/components/calendar_room/calendar_room_component.dart b/commet/lib/client/components/calendar_room/calendar_room_component.dart index acb03e333..751f24766 100644 --- a/commet/lib/client/components/calendar_room/calendar_room_component.dart +++ b/commet/lib/client/components/calendar_room/calendar_room_component.dart @@ -4,19 +4,18 @@ import 'package:commet/utils/stored_stream_controller.dart'; import 'package:commet_calendar_widget/calendar.dart'; import 'package:commet_calendar_widget/rfc8984.dart'; -enum CalendarSyncType { - events, - unavailability, -} +enum CalendarSyncType { events, unavailability } -enum CalendarSource { - ical, - room, -} +enum CalendarSource { ical, room } class SyncedCalendar { - SyncedCalendar(this.source, this.sourceType, this.syncType, - {this.overrideEventName, this.id}); + SyncedCalendar( + this.source, + this.sourceType, + this.syncType, { + this.overrideEventName, + this.id, + }); String source; CalendarSyncType syncType; @@ -33,7 +32,7 @@ class SyncedCalendar { }, "sync_type": switch (syncType) { CalendarSyncType.events => "events", - CalendarSyncType.unavailability => "unavailability" + CalendarSyncType.unavailability => "unavailability", }, if (overrideEventName != null) "override_event_name": overrideEventName!, }; @@ -43,17 +42,21 @@ class SyncedCalendar { var syncType = switch (data["sync_type"]) { "events" => CalendarSyncType.events, "unavailability" => CalendarSyncType.unavailability, - _ => throw Exception("Unknown calendar sync type") + _ => throw Exception("Unknown calendar sync type"), }; var source_type = switch (data["source_type"]) { "ical" => CalendarSource.ical, "room" => CalendarSource.room, - _ => throw Exception("Unknown calendar sync type") + _ => throw Exception("Unknown calendar sync type"), }; - return SyncedCalendar(data["source"], source_type, syncType, - overrideEventName: data["override_event_name"]); + return SyncedCalendar( + data["source"], + source_type, + syncType, + overrideEventName: data["override_event_name"], + ); } } @@ -71,8 +74,10 @@ abstract class CalendarRoom StoredStreamController> get syncedCalendars; - Future> getEventsFromIcsUrl(Uri uri, - {String? calendarId}); + Future> getEventsFromIcsUrl( + Uri uri, { + String? calendarId, + }); Future addSyncedCalendar(SyncedCalendar calendar); diff --git a/commet/lib/client/components/command/command_component.dart b/commet/lib/client/components/command/command_component.dart index e3ba1bb92..3fef8973f 100644 --- a/commet/lib/client/components/command/command_component.dart +++ b/commet/lib/client/components/command/command_component.dart @@ -11,6 +11,10 @@ abstract class CommandComponent implements Component { // Check if a string *could* be a command, but isn't necessarily valid bool isPossiblyCommand(String string); - Future executeCommand(String string, Room room, - {TimelineEvent? interactingEvent, EventInteractionType? type}); + Future executeCommand( + String string, + Room room, { + TimelineEvent? interactingEvent, + EventInteractionType? type, + }); } diff --git a/commet/lib/client/components/component_registry.dart b/commet/lib/client/components/component_registry.dart index a524215ba..057d4a262 100644 --- a/commet/lib/client/components/component_registry.dart +++ b/commet/lib/client/components/component_registry.dart @@ -94,11 +94,11 @@ class ComponentRegistry { } static List> - getMatrixSpaceComponents(MatrixClient client, MatrixSpace space) { + getMatrixSpaceComponents(MatrixClient client, MatrixSpace space) { return [ MatrixSpaceEmoticonComponent(client, space), MatrixSpaceColorSchemeComponent(client, space), - MatrixSpaceBannerComponent(client, space) + MatrixSpaceBannerComponent(client, space), ]; } } diff --git a/commet/lib/client/components/donation_awards/donation_awards_component.dart b/commet/lib/client/components/donation_awards/donation_awards_component.dart index 1a73cb70d..a691a21ad 100644 --- a/commet/lib/client/components/donation_awards/donation_awards_component.dart +++ b/commet/lib/client/components/donation_awards/donation_awards_component.dart @@ -13,8 +13,10 @@ class SecretClientIdentifier { String encryptedHash; String clientSecret; - SecretClientIdentifier( - {required this.encryptedHash, required this.clientSecret}); + SecretClientIdentifier({ + required this.encryptedHash, + required this.clientSecret, + }); } abstract class DonationAwardsComponent @@ -32,13 +34,20 @@ class DonationAward { DonationAward({required this.image, required this.title, required this.data}); static DonationAward fromJsonMatrix( - Map data, MatrixClient client) { + Map data, + MatrixClient client, + ) { return DonationAward( - data: data, - image: MatrixMxcImage( - Uri.parse(data["signed"]["content"]["image"]), client.matrixClient, - doFullres: true, doThumbnail: false, autoLoadFullRes: true), - title: data["signed"]["content"]["body"]); + data: data, + image: MatrixMxcImage( + Uri.parse(data["signed"]["content"]["image"]), + client.matrixClient, + doFullres: true, + doThumbnail: false, + autoLoadFullRes: true, + ), + title: data["signed"]["content"]["body"], + ); } } @@ -48,14 +57,19 @@ class DonationAwardsClient { DonationAwardsClient(this.host, this.client); - Future?> getAwards(SecretClientIdentifier identifier, - {DateTime? since}) async { - var path = host.replace(path: "/awards", queryParameters: { - if (since != null) - "since": (since.millisecondsSinceEpoch / 1000).toInt().toString(), - "client_reference_id": identifier.encryptedHash, - "secret": identifier.clientSecret, - }); + Future?> getAwards( + SecretClientIdentifier identifier, { + DateTime? since, + }) async { + var path = host.replace( + path: "/awards", + queryParameters: { + if (since != null) + "since": (since.millisecondsSinceEpoch / 1000).toInt().toString(), + "client_reference_id": identifier.encryptedHash, + "secret": identifier.clientSecret, + }, + ); Log.d("Fetching url: $path"); var result = await http.get(path); @@ -67,8 +81,9 @@ class DonationAwardsClient { try { var response = jsonDecode(result.body) as List; - var awards = response - .map((i) => DonationAward.fromJsonMatrix(i, client as MatrixClient)); + var awards = response.map( + (i) => DonationAward.fromJsonMatrix(i, client as MatrixClient), + ); Log.d(response); diff --git a/commet/lib/client/components/emoticon/dynamic_emoticon_pack.dart b/commet/lib/client/components/emoticon/dynamic_emoticon_pack.dart index 9683752ac..0efe99952 100644 --- a/commet/lib/client/components/emoticon/dynamic_emoticon_pack.dart +++ b/commet/lib/client/components/emoticon/dynamic_emoticon_pack.dart @@ -16,12 +16,13 @@ class DynamicEmoticonPack implements EmoticonPack { }); @override - Future addEmoticon( - {required String slug, - String? shortcode, - required Uint8List data, - String? mimeType, - EmoticonUsage usage = EmoticonUsage.emoji}) { + Future addEmoticon({ + required String slug, + String? shortcode, + required Uint8List data, + String? mimeType, + EmoticonUsage usage = EmoticonUsage.emoji, + }) { throw UnimplementedError(); } @@ -90,19 +91,23 @@ class DynamicEmoticonPack implements EmoticonPack { List get stickers => emoticons.where((i) => i.isSticker).toList(); @override - Future updateEmoticon( - {String? slug, - String? shortcode, - Uint8List? data, - String? mimeType, - EmoticonUsage? usage, - required Emoticon previous}) { + Future updateEmoticon({ + String? slug, + String? shortcode, + Uint8List? data, + String? mimeType, + EmoticonUsage? usage, + required Emoticon previous, + }) { throw UnimplementedError(); } @override - Future updatePack( - {EmoticonUsage? usage, String? name, Uint8List? imageData}) { + Future updatePack({ + EmoticonUsage? usage, + String? name, + Uint8List? imageData, + }) { throw UnimplementedError(); } diff --git a/commet/lib/client/components/emoticon/emoji_pack.dart b/commet/lib/client/components/emoticon/emoji_pack.dart index 66e55c419..f9b44bbc6 100644 --- a/commet/lib/client/components/emoticon/emoji_pack.dart +++ b/commet/lib/client/components/emoticon/emoji_pack.dart @@ -30,8 +30,11 @@ abstract class EmoticonPack { Future setPackUsage(EmoticonUsage usage); - Future updatePack( - {EmoticonUsage? usage, String? name, Uint8List? imageData}); + Future updatePack({ + EmoticonUsage? usage, + String? name, + Uint8List? imageData, + }); Emoticon? getByShortcode(String shortcode); diff --git a/commet/lib/client/components/emoticon/emoticon.dart b/commet/lib/client/components/emoticon/emoticon.dart index d9935ab2f..c6861be1e 100644 --- a/commet/lib/client/components/emoticon/emoticon.dart +++ b/commet/lib/client/components/emoticon/emoticon.dart @@ -1,12 +1,8 @@ import 'dart:core'; + import 'package:flutter/material.dart'; -enum EmoticonUsage { - sticker, - emoji, - all, - inherit, -} +enum EmoticonUsage { sticker, emoji, all, inherit } abstract class Emoticon { ImageProvider? get image; diff --git a/commet/lib/client/components/emoticon/emoticon_component.dart b/commet/lib/client/components/emoticon/emoticon_component.dart index d8fba2511..1bc762ea9 100644 --- a/commet/lib/client/components/emoticon/emoticon_component.dart +++ b/commet/lib/client/components/emoticon/emoticon_component.dart @@ -18,15 +18,22 @@ abstract class EmoticonComponent implements Component { Stream get onStateChanged; Future createEmoticonPack(String name, Uint8List? avatarData); - Future importEmoticonPack(String name, int avatarIndex, - List names, List imageDatas); + Future importEmoticonPack( + String name, + int avatarIndex, + List names, + List imageDatas, + ); Future deleteEmoticonPack(EmoticonPack pack); } abstract class RoomEmoticonComponent - extends EmoticonComponent implements RoomComponent { + extends EmoticonComponent + implements RoomComponent { Future sendSticker( - Emoticon sticker, TimelineEvent? inReplyTo); + Emoticon sticker, + TimelineEvent? inReplyTo, + ); List get availablePacks; List get availableEmoji; @@ -34,4 +41,5 @@ abstract class RoomEmoticonComponent } abstract class SpaceEmoticonComponent - extends EmoticonComponent implements SpaceComponent {} + extends EmoticonComponent + implements SpaceComponent {} diff --git a/commet/lib/client/components/gif/gif_component.dart b/commet/lib/client/components/gif/gif_component.dart index 567544807..169b213e7 100644 --- a/commet/lib/client/components/gif/gif_component.dart +++ b/commet/lib/client/components/gif/gif_component.dart @@ -18,10 +18,16 @@ abstract class GifComponent implements Component { Future> search(String query); Future sendGif( - Room room, GifSearchResult gif, TimelineEvent? inReplyTo); + Room room, + GifSearchResult gif, + TimelineEvent? inReplyTo, + ); Future sendFavoriteGif( - Room room, FavoriteGif gif, TimelineEvent? inReplyTo); + Room room, + FavoriteGif gif, + TimelineEvent? inReplyTo, + ); String get searchPlaceholder; diff --git a/commet/lib/client/components/gif/gif_search_result.dart b/commet/lib/client/components/gif/gif_search_result.dart index 66f73df35..83307e528 100644 --- a/commet/lib/client/components/gif/gif_search_result.dart +++ b/commet/lib/client/components/gif/gif_search_result.dart @@ -6,5 +6,10 @@ class GifSearchResult { final String mimeType; GifSearchResult( - this.previewUrl, this.fullResUrl, this.x, this.y, this.mimeType); + this.previewUrl, + this.fullResUrl, + this.x, + this.y, + this.mimeType, + ); } diff --git a/commet/lib/client/components/invitation/invitation.dart b/commet/lib/client/components/invitation/invitation.dart index f1d9ea841..19ecb0e32 100644 --- a/commet/lib/client/components/invitation/invitation.dart +++ b/commet/lib/client/components/invitation/invitation.dart @@ -7,12 +7,13 @@ class Invitation { Color? color; ImageProvider? avatar; - Invitation( - {required this.roomId, - this.displayName, - this.color, - this.avatar, - this.senderId}); + Invitation({ + required this.roomId, + this.displayName, + this.color, + this.avatar, + this.senderId, + }); @override bool operator ==(Object other) { diff --git a/commet/lib/client/components/invitation/invitation_component.dart b/commet/lib/client/components/invitation/invitation_component.dart index 691256976..2089eb061 100644 --- a/commet/lib/client/components/invitation/invitation_component.dart +++ b/commet/lib/client/components/invitation/invitation_component.dart @@ -11,8 +11,10 @@ abstract class InvitationComponent implements Component { Future rejectInvitation(Invitation invitation); - Future inviteUserToRoom( - {required String userId, required String roomId}); + Future inviteUserToRoom({ + required String userId, + required String roomId, + }); Future> searchUsers(String term); diff --git a/commet/lib/client/components/polls/poll_component.dart b/commet/lib/client/components/polls/poll_component.dart index 78580cf61..691ad8920 100644 --- a/commet/lib/client/components/polls/poll_component.dart +++ b/commet/lib/client/components/polls/poll_component.dart @@ -25,7 +25,9 @@ class PollCreateArgs { abstract class PollComponent implements Component { Map> getPollResponses( - Timeline timeline, TimelineEvent event); + Timeline timeline, + TimelineEvent event, + ); bool isPollEvent(TimelineEvent event); @@ -46,5 +48,8 @@ abstract class PollComponent implements Component { bool canEndPoll(Room room, TimelineEvent event, Timeline timeline); Future setAnswer( - TimelineEvent event, Room room, List answer); + TimelineEvent event, + Room room, + List answer, + ); } diff --git a/commet/lib/client/components/profile/profile_component.dart b/commet/lib/client/components/profile/profile_component.dart index e811e5e6c..971a996a2 100644 --- a/commet/lib/client/components/profile/profile_component.dart +++ b/commet/lib/client/components/profile/profile_component.dart @@ -47,13 +47,15 @@ class ProfileBadge { Uri? link; Map source; - ProfileBadge(this.image, - {required this.body, - required this.id, - required this.sender, - required this.source, - this.brightness, - this.link}); + ProfileBadge( + this.image, { + required this.body, + required this.id, + required this.sender, + required this.source, + this.brightness, + this.link, + }); @override bool operator ==(Object other) { @@ -78,8 +80,11 @@ abstract class ProfileWithBio { String? get plaintextBio; - Widget buildBio(BuildContext context, ThemeData theme, - {String? overrideText}); + Widget buildBio( + BuildContext context, + ThemeData theme, { + String? overrideText, + }); } abstract class UserProfileComponent implements Component { diff --git a/commet/lib/client/components/push_notification/android/android_notifier.dart b/commet/lib/client/components/push_notification/android/android_notifier.dart index 3520c733a..543735abb 100644 --- a/commet/lib/client/components/push_notification/android/android_notifier.dart +++ b/commet/lib/client/components/push_notification/android/android_notifier.dart @@ -46,10 +46,12 @@ class AndroidNotifier implements Notifier { const settings = AndroidInitializationSettings("notification_icon"); const initSettings = InitializationSettings(android: settings); - await flutterLocalNotificationsPlugin?.initialize(initSettings, - onDidReceiveBackgroundNotificationResponse: - onBackgroundNotificationResponse, - onDidReceiveNotificationResponse: onResponse); + await flutterLocalNotificationsPlugin?.initialize( + initSettings, + onDidReceiveBackgroundNotificationResponse: + onBackgroundNotificationResponse, + onDidReceiveNotificationResponse: onResponse, + ); if (!isHeadless) { checkPermission(); @@ -71,8 +73,9 @@ class AndroidNotifier implements Notifier { if (localClientId == null) { var cache = preferences.getRoomsListCache(); - var id = - cache.entries.firstWhereOrNull((i) => i.value.contains(roomId))?.key; + var id = cache.entries + .firstWhereOrNull((i) => i.value.contains(roomId)) + ?.key; Log.i("Found client id from rooms list cache: $id"); localClientId = id; } @@ -108,12 +111,14 @@ class AndroidNotifier implements Notifier { if (event is TimelineEventMessage || event is TimelineEventSticker) { var user = await room.fetchMember(event!.senderId); - bool isDirectMessage = client - .getComponent() - ?.isRoomDirectMessage(room) ?? + bool isDirectMessage = + client.getComponent()?.isRoomDirectMessage( + room, + ) ?? false; - NotificationManager.notify(MessageNotificationContent( + NotificationManager.notify( + MessageNotificationContent( senderName: user.displayName, senderId: user.identifier, roomName: room.displayName, @@ -125,14 +130,17 @@ class AndroidNotifier implements Notifier { clientId: client.identifier, senderImage: user.avatar, roomImage: await room.getShortcutImage(), - isDirectMessage: isDirectMessage)); + isDirectMessage: isDirectMessage, + ), + ); } } Future checkPermission() async { var android = flutterLocalNotificationsPlugin! .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>()!; + AndroidFlutterLocalNotificationsPlugin + >()!; hasPermission = await android.requestNotificationsPermission() ?? false; @@ -155,7 +163,8 @@ class AndroidNotifier implements Notifier { } Future displayMessageNotification( - MessageNotificationContent content) async { + MessageNotificationContent content, + ) async { var room = content.room; if (room == null) { @@ -174,7 +183,8 @@ class AndroidNotifier implements Notifier { if (flutterLocalNotificationsPlugin == null) { Log.i( - "Flutter local notifications plugin was null. Something went wrong"); + "Flutter local notifications plugin was null. Something went wrong", + ); return; } @@ -186,84 +196,91 @@ class AndroidNotifier implements Notifier { Log.i("Room Name: '${room.displayName}'"); Uri? userAvatar = await ShortcutsManager.getCachedAvatarImage( - placeholderColor: room.getColorOfUser(content.senderId), - placeholderText: content.senderName, - imageId: content.senderImageId, - identifier: content.senderId, - format: ShortcutIconFormat.png, - shouldZoomOut: false, - imageProvider: content.senderImage); + placeholderColor: room.getColorOfUser(content.senderId), + placeholderText: content.senderName, + imageId: content.senderImageId, + identifier: content.senderId, + format: ShortcutIconFormat.png, + shouldZoomOut: false, + imageProvider: content.senderImage, + ); Uri? roomAvatar = await ShortcutsManager.getCachedAvatarImage( - placeholderColor: room.defaultColor, - placeholderText: content.roomName, - imageId: content.roomImageId, - format: ShortcutIconFormat.png, - identifier: room.identifier, - imageProvider: await room.getShortcutImage()); + placeholderColor: room.defaultColor, + placeholderText: content.roomName, + imageId: content.roomImageId, + format: ShortcutIconFormat.png, + identifier: room.identifier, + imageProvider: await room.getShortcutImage(), + ); - await Future.wait([ - shortcutsManager.createShortcutForRoom(room), - ]); + await Future.wait([shortcutsManager.createShortcutForRoom(room)]); var id = room.identifier.hashCode; var activeStyleInfo = await AndroidFlutterLocalNotificationsPlugin() .getActiveNotificationMessagingStyle(id); var person = Person( - name: content.senderName, - important: true, - bot: false, - key: content.senderId, - icon: userAvatar == null - ? null - : BitmapFilePathAndroidIcon(userAvatar.toFilePath())); - - var message = Message( - content.content, - DateTime.now(), - person, + name: content.senderName, + important: true, + bot: false, + key: content.senderId, + icon: userAvatar == null + ? null + : BitmapFilePathAndroidIcon(userAvatar.toFilePath()), ); - var payload = - OpenRoomURI(roomId: content.roomId, clientId: content.clientId) - .toString(); + var message = Message(content.content, DateTime.now(), person); + + var payload = OpenRoomURI( + roomId: content.roomId, + clientId: content.clientId, + ).toString(); activeStyleInfo?.messages?.add(message); - var style = activeStyleInfo ?? - MessagingStyleInformation(person, - conversationTitle: - content.isDirectMessage ? content.roomName : null, - groupConversation: !content.isDirectMessage, - messages: [message]); - - var details = AndroidNotificationDetails("messages", "Message Received", - importance: Importance.high, - priority: Priority.high, - icon: "notification_icon", - number: style.messages!.length, - largeIcon: FilePathAndroidBitmap(roomAvatar.toString()), - subText: content.roomName, - groupKey: content.roomId, - groupAlertBehavior: GroupAlertBehavior.all, - styleInformation: style, - sound: RawResourceAndroidNotificationSound('message'), - shortcutId: content.roomId, - silent: content.priority == NotificationPriority.low, - ticker: content.content, - bubble: bubblesEnabled - ? BubbleMetadata( - "chat.commet.commetapp.BubbleActivity", - extra: payload, - desiredHeight: 600, - ) - : null, - color: const Color.fromARGB(0xff, 0x53, 0x4c, 0xdd)); + var style = + activeStyleInfo ?? + MessagingStyleInformation( + person, + conversationTitle: content.isDirectMessage ? content.roomName : null, + groupConversation: !content.isDirectMessage, + messages: [message], + ); + + var details = AndroidNotificationDetails( + "messages", + "Message Received", + importance: Importance.high, + priority: Priority.high, + icon: "notification_icon", + number: style.messages!.length, + largeIcon: FilePathAndroidBitmap(roomAvatar.toString()), + subText: content.roomName, + groupKey: content.roomId, + groupAlertBehavior: GroupAlertBehavior.all, + styleInformation: style, + sound: RawResourceAndroidNotificationSound('message'), + shortcutId: content.roomId, + silent: content.priority == NotificationPriority.low, + ticker: content.content, + bubble: bubblesEnabled + ? BubbleMetadata( + "chat.commet.commetapp.BubbleActivity", + extra: payload, + desiredHeight: 600, + ) + : null, + color: const Color.fromARGB(0xff, 0x53, 0x4c, 0xdd), + ); await flutterLocalNotificationsPlugin?.show( - id, null, content.content, NotificationDetails(android: details), - payload: payload); + id, + null, + content.content, + NotificationDetails(android: details), + payload: payload, + ); } Future displayCallNotification(CallNotificationContent content) async { @@ -280,7 +297,8 @@ class AndroidNotifier implements Notifier { if (flutterLocalNotificationsPlugin == null) { Log.i( - "Flutter local notifications plugin was null. Something went wrong"); + "Flutter local notifications plugin was null. Something went wrong", + ); return; } @@ -289,61 +307,71 @@ class AndroidNotifier implements Notifier { } Uri? roomAvatar = await ShortcutsManager.getCachedAvatarImage( - placeholderColor: room.defaultColor, - placeholderText: content.roomName, - imageId: content.roomImageId, - format: ShortcutIconFormat.png, - identifier: room.identifier, - imageProvider: await room.getShortcutImage()); + placeholderColor: room.defaultColor, + placeholderText: content.roomName, + imageId: content.roomImageId, + format: ShortcutIconFormat.png, + identifier: room.identifier, + imageProvider: await room.getShortcutImage(), + ); var id = room.identifier.hashCode; - var payload = - OpenRoomURI(roomId: content.roomId, clientId: content.clientId) - .toString(); - - var details = - AndroidNotificationDetails("incoming_calls_channel_1", "Incoming Call", - importance: Importance.high, - priority: Priority.high, - icon: "notification_icon", - timeoutAfter: 60000, - largeIcon: FilePathAndroidBitmap(roomAvatar.toString()), - subText: content.roomName, - fullScreenIntent: true, - sound: RawResourceAndroidNotificationSound('ringtone_in'), - groupKey: content.roomId, - actions: [ - AndroidNotificationAction( - AcceptCallUri( - roomId: content.roomId, - callId: content.callId, - clientId: content.clientId) - .toString(), - "Accept", - showsUserInterface: true, - semanticAction: SemanticAction.call, - titleColor: Colors.green), - AndroidNotificationAction( - DeclineCallUri( - roomId: content.roomId, - callId: content.callId, - clientId: content.clientId) - .toString(), - "Decline", - showsUserInterface: true, - semanticAction: SemanticAction.delete, - titleColor: Colors.red) - ], - groupAlertBehavior: GroupAlertBehavior.all, - shortcutId: content.roomId, - silent: false, - ticker: content.content, - color: const Color.fromARGB(0xff, 0x53, 0x4c, 0xdd)); + var payload = OpenRoomURI( + roomId: content.roomId, + clientId: content.clientId, + ).toString(); + + var details = AndroidNotificationDetails( + "incoming_calls_channel_1", + "Incoming Call", + importance: Importance.high, + priority: Priority.high, + icon: "notification_icon", + timeoutAfter: 60000, + largeIcon: FilePathAndroidBitmap(roomAvatar.toString()), + subText: content.roomName, + fullScreenIntent: true, + sound: RawResourceAndroidNotificationSound('ringtone_in'), + groupKey: content.roomId, + actions: [ + AndroidNotificationAction( + AcceptCallUri( + roomId: content.roomId, + callId: content.callId, + clientId: content.clientId, + ).toString(), + "Accept", + showsUserInterface: true, + semanticAction: SemanticAction.call, + titleColor: Colors.green, + ), + AndroidNotificationAction( + DeclineCallUri( + roomId: content.roomId, + callId: content.callId, + clientId: content.clientId, + ).toString(), + "Decline", + showsUserInterface: true, + semanticAction: SemanticAction.delete, + titleColor: Colors.red, + ), + ], + groupAlertBehavior: GroupAlertBehavior.all, + shortcutId: content.roomId, + silent: false, + ticker: content.content, + color: const Color.fromARGB(0xff, 0x53, 0x4c, 0xdd), + ); await flutterLocalNotificationsPlugin?.show( - id, null, content.content, NotificationDetails(android: details), - payload: payload); + id, + null, + content.content, + NotificationDetails(android: details), + payload: payload, + ); } Future getImageBytes(ImageProvider? provider) async { @@ -362,16 +390,19 @@ class AndroidNotifier implements Notifier { static void onResponse(NotificationResponse details) { Log.i( - "Got a notification response: $details (${details.actionId}) (${details.data}) (${details.payload})"); + "Got a notification response: $details (${details.actionId}) (${details.data}) (${details.payload})", + ); if (details.actionId != null) { var uri = CustomURI.parse(details.actionId!); Log.d("Parsed action uri: $uri"); if (uri case AcceptCallUri _) { final session = clientManager?.callManager.currentSessions - .where((e) => - e.sessionId == uri.callId && - e.client.identifier == uri.clientId) + .where( + (e) => + e.sessionId == uri.callId && + e.client.identifier == uri.clientId, + ) .firstOrNull; session?.acceptCall(withMicrophone: true); @@ -381,9 +412,11 @@ class AndroidNotifier implements Notifier { if (uri case DeclineCallUri _) { final session = clientManager?.callManager.currentSessions - .where((e) => - e.sessionId == uri.callId && - e.client.identifier == uri.clientId) + .where( + (e) => + e.sessionId == uri.callId && + e.client.identifier == uri.clientId, + ) .firstOrNull; session?.declineCall(); @@ -414,8 +447,8 @@ class AndroidNotifier implements Notifier { @override Future clearNotifications(Room room) async { - var notifications = - await flutterLocalNotificationsPlugin?.getActiveNotifications(); + var notifications = await flutterLocalNotificationsPlugin + ?.getActiveNotifications(); if (notifications == null) return; @@ -427,7 +460,8 @@ class AndroidNotifier implements Notifier { } Future displayErrorNotification( - ErrorNotificationContent notification) async { + ErrorNotificationContent notification, + ) async { var details = AndroidNotificationDetails( "errors", "Error Messages", @@ -446,7 +480,8 @@ class AndroidNotifier implements Notifier { } Future displayGenericInviteNotification( - GenericRoomInviteNotificationContent notification) async { + GenericRoomInviteNotificationContent notification, + ) async { var details = AndroidNotificationDetails( "chat_invites", "Chat Invitations", diff --git a/commet/lib/client/components/push_notification/android/firebase_push_notifier.dart b/commet/lib/client/components/push_notification/android/firebase_push_notifier.dart index ad1a63a49..0c39f98f1 100644 --- a/commet/lib/client/components/push_notification/android/firebase_push_notifier.dart +++ b/commet/lib/client/components/push_notification/android/firebase_push_notifier.dart @@ -55,10 +55,12 @@ Future _firebaseMessagingBackgroundHandler(dynamic message) async { return; } - NotificationManager.notify(ErrorNotificationContent( - title: "Unknown Notification Data", - content: jsonEncode(data), - )); + NotificationManager.notify( + ErrorNotificationContent( + title: "Unknown Notification Data", + content: jsonEncode(data), + ), + ); } return; @@ -68,9 +70,12 @@ Future _firebaseMessagingBackgroundHandler(dynamic message) async { } catch (e, s) { Log.e("An error occured while processing unified push background message"); Log.onError(e, s); - NotificationManager.notify(ErrorNotificationContent( + NotificationManager.notify( + ErrorNotificationContent( title: "An error occurred while processing notifications", - content: "${e} \n\n ${s}")); + content: "${e} \n\n ${s}", + ), + ); } } @@ -98,7 +103,8 @@ class FirebasePushNotifier implements Notifier { await notifier.init(); await Firebase.initializeApp( - options: DefaultFirebaseOptions.currentPlatform); + options: DefaultFirebaseOptions.currentPlatform, + ); Log.i("Initialized App"); FirebaseMessaging.instance.onTokenRefresh.listen((event) { diff --git a/commet/lib/client/components/push_notification/android/unified_push_notifier.dart b/commet/lib/client/components/push_notification/android/unified_push_notifier.dart index aeda150dc..a438370c3 100644 --- a/commet/lib/client/components/push_notification/android/unified_push_notifier.dart +++ b/commet/lib/client/components/push_notification/android/unified_push_notifier.dart @@ -99,10 +99,12 @@ class UnifiedPushNotifier implements Notifier { return; } - NotificationManager.notify(ErrorNotificationContent( - title: "Unknown Notification Data", - content: jsonEncode(message), - )); + NotificationManager.notify( + ErrorNotificationContent( + title: "Unknown Notification Data", + content: jsonEncode(message), + ), + ); } return; @@ -111,11 +113,15 @@ class UnifiedPushNotifier implements Notifier { notificationManager.handleMessage(message); } catch (e, s) { Log.e( - "An error occured while processing unified push background message"); + "An error occured while processing unified push background message", + ); Log.onError(e, s); - NotificationManager.notify(ErrorNotificationContent( + NotificationManager.notify( + ErrorNotificationContent( title: "An error occurred while processing notifications", - content: "${e} \n\n ${s}")); + content: "${e} \n\n ${s}", + ), + ); } } @@ -185,6 +191,4 @@ class UnifiedPushNotifier implements Notifier { // TODO: implement enableBadges throw UnimplementedError(); } - - } diff --git a/commet/lib/client/components/push_notification/linux/linux_notifier.dart b/commet/lib/client/components/push_notification/linux/linux_notifier.dart index 8b7d60e8f..ca632b3c4 100644 --- a/commet/lib/client/components/push_notification/linux/linux_notifier.dart +++ b/commet/lib/client/components/push_notification/linux/linux_notifier.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; + import 'package:commet/client/client.dart'; import 'package:commet/client/components/push_notification/notification_content.dart'; import 'package:commet/client/components/push_notification/notification_manager.dart'; @@ -20,6 +21,7 @@ import 'package:flutter_local_notifications_linux/src/model/hint.dart' as notif; import 'package:launcher_entry/launcher_entry.dart'; import 'package:media_kit/media_kit.dart'; import 'package:window_manager/window_manager.dart'; + import 'dart:ui' as ui; class LinuxNotifier implements Notifier { @@ -49,7 +51,8 @@ class LinuxNotifier implements Notifier { late LinuxServerCapabilities capabilities; final service = LauncherEntryService( - appUri: 'application://chat.commet.commetapp.desktop'); + appUri: 'application://chat.commet.commetapp.desktop', + ); static void notificationResponse(NotificationResponse details) { final payload = jsonDecode(details.payload!) as Map; @@ -91,7 +94,8 @@ class LinuxNotifier implements Notifier { final clientId = payload['client_id']; final session = clientManager?.callManager.currentSessions .where( - (e) => e.sessionId == callId && e.client.identifier == clientId) + (e) => e.sessionId == callId && e.client.identifier == clientId, + ) .firstOrNull; if (action == callDecline) { @@ -121,13 +125,15 @@ class LinuxNotifier implements Notifier { LinuxInitializationSettings(defaultActionName: 'Open notification'); await flutterLocalNotificationsPlugin?.initialize( - initializationSettingsLinux, - onDidReceiveNotificationResponse: notificationResponse); + initializationSettingsLinux, + onDidReceiveNotificationResponse: notificationResponse, + ); capabilities = await flutterLocalNotificationsPlugin!.getCapabilities(); - clientManager!.directMessages.highlightedRoomsList.onListUpdated - .listen((_) => updateBadgeCount()); + clientManager!.directMessages.highlightedRoomsList.onListUpdated.listen( + (_) => updateBadgeCount(), + ); clientManager!.onSpaceUpdated.stream.listen((_) => updateBadgeCount()); updateBadgeCount(); @@ -153,7 +159,8 @@ class LinuxNotifier implements Notifier { } Future displayMessageNotification( - MessageNotificationContent content) async { + MessageNotificationContent content, + ) async { var client = clientManager?.getClient(content.clientId); var room = client?.getRoom(content.roomId); @@ -162,19 +169,21 @@ class LinuxNotifier implements Notifier { } var image = await ShortcutsManager.createAvatarImage( - placeholderColor: room.getColorOfUser(content.senderId), - placeholderText: content.senderName, - imageProvider: content.senderImage, - doCircleMask: true, - shouldZoomOut: false); + placeholderColor: room.getColorOfUser(content.senderId), + placeholderText: content.senderName, + imageProvider: content.senderImage, + doCircleMask: true, + shouldZoomOut: false, + ); if (content.isDirectMessage == false) { var roomImage = await ShortcutsManager.createAvatarImage( - placeholderColor: room.defaultColor, - placeholderText: room.displayName, - imageProvider: content.roomImage, - doCircleMask: true, - shouldZoomOut: false); + placeholderColor: room.defaultColor, + placeholderText: room.displayName, + imageProvider: content.roomImage, + doCircleMask: true, + shouldZoomOut: false, + ); image = await ShortcutsManager.combineRoomAndUserImages(roomImage, image); } @@ -185,20 +194,25 @@ class LinuxNotifier implements Notifier { String notificationBody = content.content; var details = LinuxNotificationDetails( - icon: ByteDataLinuxIcon(LinuxRawIconData( + icon: ByteDataLinuxIcon( + LinuxRawIconData( data: data, width: image.width, height: image.height, hasAlpha: true, - channels: 4)), + channels: 4, + ), + ), defaultActionName: openRoom, actions: [ if (capabilities.otherCapabilities.contains("inline-reply")) - LinuxNotificationAction(key: "inline-reply", label: "Reply") + LinuxNotificationAction(key: "inline-reply", label: "Reply"), ], customHints: [ - notif.LinuxNotificationCustomHint('desktop-entry', - notif.LinuxHintStringValue("chat.commet.commetapp")), + notif.LinuxNotificationCustomHint( + 'desktop-entry', + notif.LinuxHintStringValue("chat.commet.commetapp"), + ), ], category: LinuxNotificationCategory.imReceived, ); @@ -222,8 +236,12 @@ class LinuxNotifier implements Notifier { player.open(Media("asset:///assets/sound/message.ogg")); flutterLocalNotificationsPlugin?.show( - notificationId++, title, notificationBody, - notificationDetails: details, payload: jsonEncode(payload)); + notificationId++, + title, + notificationBody, + notificationDetails: details, + payload: jsonEncode(payload), + ); } Future displayCallNotification(CallNotificationContent content) async { @@ -235,32 +253,41 @@ class LinuxNotifier implements Notifier { } var image = await ShortcutsManager.createAvatarImage( - placeholderColor: room.getColorOfUser(content.senderId), - placeholderText: content.roomName, - imageProvider: content.senderImage, - doCircleMask: true, - shouldZoomOut: false); + placeholderColor: room.getColorOfUser(content.senderId), + placeholderText: content.roomName, + imageProvider: content.senderImage, + doCircleMask: true, + shouldZoomOut: false, + ); var bytes = await image.toByteData(format: ui.ImageByteFormat.rawRgba); final data = bytes!.buffer.asUint8List(); var details = LinuxNotificationDetails( - icon: ByteDataLinuxIcon(LinuxRawIconData( - data: data, - width: image.width, - height: image.height, - hasAlpha: true, - channels: 4)), - defaultActionName: openRoom, - category: LinuxNotificationCategory.imReceived, - timeout: const LinuxNotificationTimeout.expiresNever(), - urgency: LinuxNotificationUrgency.critical, - actions: [ - LinuxNotificationAction( - key: callAccept, label: CommonStrings.promptAccept), - LinuxNotificationAction( - key: callDecline, label: CommonStrings.promptDecline), - ]); + icon: ByteDataLinuxIcon( + LinuxRawIconData( + data: data, + width: image.width, + height: image.height, + hasAlpha: true, + channels: 4, + ), + ), + defaultActionName: openRoom, + category: LinuxNotificationCategory.imReceived, + timeout: const LinuxNotificationTimeout.expiresNever(), + urgency: LinuxNotificationUrgency.critical, + actions: [ + LinuxNotificationAction( + key: callAccept, + label: CommonStrings.promptAccept, + ), + LinuxNotificationAction( + key: callDecline, + label: CommonStrings.promptDecline, + ), + ], + ); var payload = { // include default action here as well @@ -269,11 +296,16 @@ class LinuxNotifier implements Notifier { "default_action_id": openRoom, "room_id": content.roomId, "client_id": content.clientId, - "call_id": content.callId + "call_id": content.callId, }; - flutterLocalNotificationsPlugin?.show(0, content.title, content.content, - notificationDetails: details, payload: jsonEncode(payload)); + flutterLocalNotificationsPlugin?.show( + 0, + content.title, + content.content, + notificationDetails: details, + payload: jsonEncode(payload), + ); } Future determineImage(ImageProvider provider) async { diff --git a/commet/lib/client/components/push_notification/modifiers/do_not_disturb.dart b/commet/lib/client/components/push_notification/modifiers/do_not_disturb.dart index c400f25c7..6623b3321 100644 --- a/commet/lib/client/components/push_notification/modifiers/do_not_disturb.dart +++ b/commet/lib/client/components/push_notification/modifiers/do_not_disturb.dart @@ -3,8 +3,10 @@ import 'package:commet/client/components/push_notification/notification_content. class NotificationModifierDoNotDisturb implements NotificationModifier { @override - Future process(NotificationContent content, - {Function(String reason)? onNotificationRejected}) async { + Future process( + NotificationContent content, { + Function(String reason)? onNotificationRejected, + }) async { return null; } } diff --git a/commet/lib/client/components/push_notification/modifiers/hide_content.dart b/commet/lib/client/components/push_notification/modifiers/hide_content.dart index 4401c7b37..5e53f7e0d 100644 --- a/commet/lib/client/components/push_notification/modifiers/hide_content.dart +++ b/commet/lib/client/components/push_notification/modifiers/hide_content.dart @@ -4,14 +4,16 @@ import 'package:intl/intl.dart'; class NotificationModifierHideContent implements NotificationModifier { String get notificationModifiersPrivacyEnhanced => Intl.message( - "Sent a message", - name: "notificationModifiersPrivacyEnhanced", - desc: - "Placeholder text to put in a notification when the user has privacy enhanced notifications enabled."); + "Sent a message", + name: "notificationModifiersPrivacyEnhanced", + desc: "Placeholder text to put in a notification when the user has privacy enhanced notifications enabled.", + ); @override - Future process(NotificationContent content, - {Function(String reason)? onNotificationRejected}) async { + Future process( + NotificationContent content, { + Function(String reason)? onNotificationRejected, + }) async { content.content = "A Notification was received"; if (content is MessageNotificationContent) { diff --git a/commet/lib/client/components/push_notification/modifiers/linux_notification_formatting.dart b/commet/lib/client/components/push_notification/modifiers/linux_notification_formatting.dart index 6daa99da9..2466f216d 100644 --- a/commet/lib/client/components/push_notification/modifiers/linux_notification_formatting.dart +++ b/commet/lib/client/components/push_notification/modifiers/linux_notification_formatting.dart @@ -1,6 +1,7 @@ import 'package:commet/client/components/push_notification/linux/linux_notifier.dart'; import 'package:commet/client/components/push_notification/modifiers/notification_modifiers.dart'; import 'package:commet/client/components/push_notification/notification_content.dart'; + import 'dart:async'; import 'package:commet/client/client.dart'; @@ -20,14 +21,17 @@ import 'package:html/dom.dart' as html; import 'package:html/parser.dart'; import 'package:markdown/markdown.dart'; import 'package:vector_math/vector_math.dart'; + import 'dart:ui' as ui; class NotificationModifierLinuxFormatting implements NotificationModifier { final double thumbnailImageSize = 100; @override - Future process(NotificationContent content, - {Function(String reason)? onNotificationRejected}) async { + Future process( + NotificationContent content, { + Function(String reason)? onNotificationRejected, + }) async { if (preferences.formatNotificationBody.value == false) { return content; } @@ -187,7 +191,8 @@ class NotificationModifierLinuxFormatting implements NotificationModifier { final preview = room.client.getComponent(); - bool shouldGetPreview = preview?.shouldGetPreviewsInRoom(room) == true && + bool shouldGetPreview = + preview?.shouldGetPreviewsInRoom(room) == true && preferences.previewUrlInNotifications.value; if (!shouldGetPreview) { @@ -321,11 +326,10 @@ class NotificationModifierLinuxFormatting implements NotificationModifier { } Future convertPlainText(String formattedContent, Room room) async { - final html = markdownToHtml(formattedContent, - extensionSet: ExtensionSet( - [], - [AutolinkExtensionSyntax()], - )); + final html = markdownToHtml( + formattedContent, + extensionSet: ExtensionSet([], [AutolinkExtensionSyntax()]), + ); return convertMatrixHtml(html, room); } } diff --git a/commet/lib/client/components/push_notification/modifiers/notification_modifiers.dart b/commet/lib/client/components/push_notification/modifiers/notification_modifiers.dart index 35ad00205..904b4a560 100644 --- a/commet/lib/client/components/push_notification/modifiers/notification_modifiers.dart +++ b/commet/lib/client/components/push_notification/modifiers/notification_modifiers.dart @@ -1,6 +1,8 @@ import 'package:commet/client/components/push_notification/notification_content.dart'; abstract class NotificationModifier { - Future process(NotificationContent content, - {Function(String reason)? onNotificationRejected}); + Future process( + NotificationContent content, { + Function(String reason)? onNotificationRejected, + }); } diff --git a/commet/lib/client/components/push_notification/modifiers/suppress_active_room.dart b/commet/lib/client/components/push_notification/modifiers/suppress_active_room.dart index 6b2290235..57d80f2f5 100644 --- a/commet/lib/client/components/push_notification/modifiers/suppress_active_room.dart +++ b/commet/lib/client/components/push_notification/modifiers/suppress_active_room.dart @@ -17,8 +17,10 @@ class NotificationModifierSuppressActiveRoom implements NotificationModifier { } @override - Future process(NotificationContent content, - {Function(String reason)? onNotificationRejected}) async { + Future process( + NotificationContent content, { + Function(String reason)? onNotificationRejected, + }) async { if (preferences.suppressNotificationWhenRoomFocused.value == false) { return content; } @@ -37,7 +39,8 @@ class NotificationModifierSuppressActiveRoom implements NotificationModifier { if (content.roomId == roomId) { onNotificationRejected?.call( - "The notification was intended for the same room that is currently open, and the app was detected as being in focus. If this doesn't seem right, you may want to disable the 'Hide notifications for current room' setting to bypass this check"); + "The notification was intended for the same room that is currently open, and the app was detected as being in focus. If this doesn't seem right, you may want to disable the 'Hide notifications for current room' setting to bypass this check", + ); return null; } } diff --git a/commet/lib/client/components/push_notification/modifiers/suppress_other_device_active.dart b/commet/lib/client/components/push_notification/modifiers/suppress_other_device_active.dart index a8d4eabc0..1e0f56b8c 100644 --- a/commet/lib/client/components/push_notification/modifiers/suppress_other_device_active.dart +++ b/commet/lib/client/components/push_notification/modifiers/suppress_other_device_active.dart @@ -10,8 +10,10 @@ import 'package:matrix/matrix_api_lite/generated/model.dart' show Device; class NotificationModifierSuppressOtherActiveDevice implements NotificationModifier { @override - Future process(NotificationContent content, - {Function(String reason)? onNotificationRejected}) async { + Future process( + NotificationContent content, { + Function(String reason)? onNotificationRejected, + }) async { if (!preferences.silenceNotifications.value) { return content; } @@ -27,7 +29,8 @@ class NotificationModifierSuppressOtherActiveDevice clients = [content.room!.client]; } else { Log.w( - "Suppressing notifications for background client is not currently supported"); + "Suppressing notifications for background client is not currently supported", + ); return content; } } else { @@ -63,7 +66,8 @@ class NotificationModifierSuppressOtherActiveDevice if (diff.inMinutes < 10) { Log.i( - "Suppressing this notification because there is another device which has been active recently!\nThe device which was active is: ${device.displayName} : ${device.deviceId}"); + "Suppressing this notification because there is another device which has been active recently!\nThe device which was active is: ${device.displayName} : ${device.deviceId}", + ); content.priority = NotificationPriority.low; return content; diff --git a/commet/lib/client/components/push_notification/notification_content.dart b/commet/lib/client/components/push_notification/notification_content.dart index c99a4c8e1..e4cfc149e 100644 --- a/commet/lib/client/components/push_notification/notification_content.dart +++ b/commet/lib/client/components/push_notification/notification_content.dart @@ -15,10 +15,11 @@ class NotificationContent { String content; NotificationPriority priority; - NotificationContent( - {required this.title, - required this.content, - this.priority = NotificationPriority.normal}); + NotificationContent({ + required this.title, + required this.content, + this.priority = NotificationPriority.normal, + }); } class ErrorNotificationContent extends NotificationContent { @@ -26,8 +27,10 @@ class ErrorNotificationContent extends NotificationContent { } class GenericRoomInviteNotificationContent extends NotificationContent { - GenericRoomInviteNotificationContent( - {required super.title, required super.content}); + GenericRoomInviteNotificationContent({ + required super.title, + required super.content, + }); } class MessageNotificationContent extends NotificationContent { @@ -67,23 +70,27 @@ class MessageNotificationContent extends NotificationContent { }) : super(title: senderName); static String notificationSenderViaProfile( - String profileName, String sender) => - Intl.message("$profileName via $sender", - name: "notificationSenderViaProfile", - desc: - "Sender of a notification for a message which was sent with a per message profile", - args: [profileName, sender]); + String profileName, + String sender, + ) => Intl.message( + "$profileName via $sender", + name: "notificationSenderViaProfile", + desc: "Sender of a notification for a message which was sent with a per message profile", + args: [profileName, sender], + ); static Future fromEvent( - TimelineEvent msg, Room room) async { + TimelineEvent msg, + Room room, + ) async { var user = await room.fetchMember(msg.senderId); var senderName = user.displayName; var senderImage = user.avatar; if (msg is TimelineEventFeaturePerMessageProfile) { - var profile = - (msg as TimelineEventFeaturePerMessageProfile).getPerMessageProfile(); + var profile = (msg as TimelineEventFeaturePerMessageProfile) + .getPerMessageProfile(); if (profile != null) { if (profile.avatar != null || profile.clearAvatar) { @@ -91,8 +98,10 @@ class MessageNotificationContent extends NotificationContent { } if (profile.hasDisplayName) { - senderName = - notificationSenderViaProfile(profile.displayName!, senderName); + senderName = notificationSenderViaProfile( + profile.displayName!, + senderName, + ); } } } @@ -110,14 +119,15 @@ class MessageNotificationContent extends NotificationContent { eventId: msg.eventId, attachedImage: msg.attachments?.whereType().firstOrNull?.image ?? - msg.attachments - ?.whereType() - .firstOrNull - ?.thumbnail, + msg.attachments + ?.whereType() + .firstOrNull + ?.thumbnail, formatType: msg.bodyFormat, formattedContent: msg.formattedBody, room: room, - isDirectMessage: room.client + isDirectMessage: + room.client .getComponent() ?.isRoomDirectMessage(room) ?? false, @@ -139,7 +149,8 @@ class MessageNotificationContent extends NotificationContent { formattedContent: "", room: room, formatType: "chat.commet.custom.matrix_plain", - isDirectMessage: room.client + isDirectMessage: + room.client .getComponent() ?.isRoomDirectMessage(room) ?? false, diff --git a/commet/lib/client/components/push_notification/notification_manager.dart b/commet/lib/client/components/push_notification/notification_manager.dart index da963b296..159903883 100644 --- a/commet/lib/client/components/push_notification/notification_manager.dart +++ b/commet/lib/client/components/push_notification/notification_manager.dart @@ -21,8 +21,9 @@ class NotificationManager { static Notifier? get notifier => _notifier; - static final List _modifiers = - List.empty(growable: true); + static final List _modifiers = List.empty( + growable: true, + ); static Future? notifierLoading; @@ -91,9 +92,11 @@ class NotificationManager { await notifier?.clearNotifications(room); } - static Future notify(NotificationContent notification, - {bool forceShow = false, - Function(String reason)? onNotificationRejected}) async { + static Future notify( + NotificationContent notification, { + bool forceShow = false, + Function(String reason)? onNotificationRejected, + }) async { if (_notifier == null) { Log.e("Failed to show notification, notifier has not been initialzied"); onNotificationRejected?.call("Notifier has not been initialized"); @@ -113,13 +116,16 @@ class NotificationManager { if (modifier is NotificationModifierSuppressOtherActiveDevice) continue; } - content = await modifier.process(content!, - onNotificationRejected: onNotificationRejected); + content = await modifier.process( + content!, + onNotificationRejected: onNotificationRejected, + ); if (content == null) { Log.d("Modifier returned null notification, returning"); onNotificationRejected?.call( - "Notification modifier '${modifier}' rejected the notification"); + "Notification modifier '${modifier}' rejected the notification", + ); return; } } diff --git a/commet/lib/client/components/push_notification/push_notification_component.dart b/commet/lib/client/components/push_notification/push_notification_component.dart index ceb268c92..ef4110e1a 100644 --- a/commet/lib/client/components/push_notification/push_notification_component.dart +++ b/commet/lib/client/components/push_notification/push_notification_component.dart @@ -5,8 +5,11 @@ import 'package:commet/main.dart'; abstract class PushNotificationComponent implements Component, NeedsPostLoginInit { Future ensurePushNotificationsRegistered( - String pushKey, Uri pushServer, String deviceName, - {Map? extraData}); + String pushKey, + Uri pushServer, + String deviceName, { + Map? extraData, + }); Future updatePushers(); diff --git a/commet/lib/client/components/push_notification/windows/windows_notifier.dart b/commet/lib/client/components/push_notification/windows/windows_notifier.dart index 04fa85375..7004d2229 100644 --- a/commet/lib/client/components/push_notification/windows/windows_notifier.dart +++ b/commet/lib/client/components/push_notification/windows/windows_notifier.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:io'; + import 'package:commet/client/client.dart'; import 'package:commet/client/components/push_notification/notification_content.dart'; import 'package:commet/client/components/push_notification/notification_manager.dart'; @@ -34,8 +35,9 @@ class WindowsNotifier implements Notifier { final dir = await getTemporaryDirectory(); var file = p.join(dir.path, "chat.commet.app", "commet_app_icon.png"); - ByteData data = await rootBundle - .load("assets/images/app_icon/app_icon_transparent_cropped.png"); + ByteData data = await rootBundle.load( + "assets/images/app_icon/app_icon_transparent_cropped.png", + ); var imageFile = File(file); imageFile.createSync(recursive: true); @@ -96,7 +98,8 @@ class WindowsNotifier implements Notifier { final clientId = args['client_id']; final session = clientManager?.callManager.currentSessions .where( - (e) => e.sessionId == callId && e.client.identifier == clientId) + (e) => e.sessionId == callId && e.client.identifier == clientId, + ) .firstOrNull; if (args['action'] == "reject_call") { @@ -134,7 +137,8 @@ class WindowsNotifier implements Notifier { } Future displayCallNotificationContent( - CallNotificationContent content) async { + CallNotificationContent content, + ) async { String? avatarFilePath; var client = clientManager?.getClient(content.clientId); @@ -145,12 +149,13 @@ class WindowsNotifier implements Notifier { } var avatar = await ShortcutsManager.getCachedAvatarImage( - placeholderColor: room.getColorOfUser(content.senderId), - placeholderText: content.roomName, - identifier: content.senderId, - format: ShortcutIconFormat.png, - shouldZoomOut: false, - imageProvider: content.senderImage); + placeholderColor: room.getColorOfUser(content.senderId), + placeholderText: content.roomName, + identifier: content.senderId, + format: ShortcutIconFormat.png, + shouldZoomOut: false, + imageProvider: content.senderImage, + ); avatarFilePath = avatar == null ? "" : avatar.toFilePath(); @@ -162,7 +167,8 @@ class WindowsNotifier implements Notifier { var defaultAction = "action=open_room&client_id=${f(content.clientId)}&room_id=${f(content.roomId)}&call_id=${f(content.callId)}"; - var header = '''
'''; @@ -171,7 +177,8 @@ class WindowsNotifier implements Notifier { header = ""; } - var xml = """ + var xml = + """ $header @@ -194,7 +201,8 @@ class WindowsNotifier implements Notifier { } Future displayMessageNotification( - MessageNotificationContent content) async { + MessageNotificationContent content, + ) async { String? avatarFilePath; var client = clientManager?.getClient(content.clientId); @@ -205,12 +213,13 @@ class WindowsNotifier implements Notifier { } var avatar = await ShortcutsManager.getCachedAvatarImage( - placeholderColor: room.getColorOfUser(content.senderId), - placeholderText: content.senderName, - identifier: content.senderId, - format: ShortcutIconFormat.png, - shouldZoomOut: false, - imageProvider: content.senderImage); + placeholderColor: room.getColorOfUser(content.senderId), + placeholderText: content.senderName, + identifier: content.senderId, + format: ShortcutIconFormat.png, + shouldZoomOut: false, + imageProvider: content.senderImage, + ); avatarFilePath = avatar == null ? "" : avatar.toFilePath(); @@ -222,7 +231,8 @@ class WindowsNotifier implements Notifier { var defaultAction = "action=open_room&client_id=${f(content.clientId)}&room_id=${f(content.roomId)}&event_id=${f(content.eventId)}"; - var header = '''
'''; @@ -231,7 +241,8 @@ class WindowsNotifier implements Notifier { header = ""; } - var xml = """ + var xml = + """ $header diff --git a/commet/lib/client/components/rtc_data_channel/rtc_data_channel_component.dart b/commet/lib/client/components/rtc_data_channel/rtc_data_channel_component.dart index 2954d2cc4..c0d0a646a 100644 --- a/commet/lib/client/components/rtc_data_channel/rtc_data_channel_component.dart +++ b/commet/lib/client/components/rtc_data_channel/rtc_data_channel_component.dart @@ -4,8 +4,10 @@ import 'package:commet/client/components/voip/voip_session.dart'; abstract class RTCDataChannelComponent implements Component { - Future createDataChannel(VoipSession session, - {required String purpose}); + Future createDataChannel( + VoipSession session, { + required String purpose, + }); Stream get onDataChannelOpened; } diff --git a/commet/lib/client/components/rtc_screen_share_annotation/rtc_screen_share_annotation_component.dart b/commet/lib/client/components/rtc_screen_share_annotation/rtc_screen_share_annotation_component.dart index 293aa94f7..e3629a823 100644 --- a/commet/lib/client/components/rtc_screen_share_annotation/rtc_screen_share_annotation_component.dart +++ b/commet/lib/client/components/rtc_screen_share_annotation/rtc_screen_share_annotation_component.dart @@ -7,12 +7,16 @@ abstract class RTCScreenShareAnnotationComponent Future createSession(VoipSession session); Future getOrCreateSession( - VoipSession session); + VoipSession session, + ); RTCScreenShareAnnotationSession? getExistingSession(VoipSession session); } abstract class RTCScreenShareAnnotationSession { - void setCursorPosition( - {required String streamId, required double x, required double y}); + void setCursorPosition({ + required String streamId, + required double x, + required double y, + }); } diff --git a/commet/lib/client/components/sidebar_component/sidebar_entries_component.dart b/commet/lib/client/components/sidebar_component/sidebar_entries_component.dart index 06b4c2d4f..8bd122785 100644 --- a/commet/lib/client/components/sidebar_component/sidebar_entries_component.dart +++ b/commet/lib/client/components/sidebar_component/sidebar_entries_component.dart @@ -17,7 +17,7 @@ class SpaceSidebarEntry extends SidebarEntry { Space space; SpaceSidebarEntry(this.space, {required String order}) - : super(space.localId, order); + : super(space.localId, order); } class SpaceGroupSidebarEntry extends SidebarEntry { @@ -25,7 +25,7 @@ class SpaceGroupSidebarEntry extends SidebarEntry { List spaces; SpaceGroupSidebarEntry(this.groupId, this.spaces, {required String order}) - : super(groupId, order); + : super(groupId, order); } class StringOrderGenerator { diff --git a/commet/lib/client/components/threads/thread_component.dart b/commet/lib/client/components/threads/thread_component.dart index 295347a78..e50ad1892 100644 --- a/commet/lib/client/components/threads/thread_component.dart +++ b/commet/lib/client/components/threads/thread_component.dart @@ -8,8 +8,10 @@ abstract class ThreadsComponent implements Component { bool isHeadOfThread(TimelineEvent event, Timeline timeline); - Future getThreadTimeline( - {required Timeline roomTimeline, required String threadRootEventId}); + Future getThreadTimeline({ + required Timeline roomTimeline, + required String threadRootEventId, + }); Future sendMessage({ required String threadRootEventId, diff --git a/commet/lib/client/components/url_preview/url_preview_component.dart b/commet/lib/client/components/url_preview/url_preview_component.dart index ebf83f24e..628612f7c 100644 --- a/commet/lib/client/components/url_preview/url_preview_component.dart +++ b/commet/lib/client/components/url_preview/url_preview_component.dart @@ -6,7 +6,9 @@ import 'package:flutter/widgets.dart'; abstract class UrlPreviewComponent implements Component { bool shouldGetPreviewDataForTimelineEvent( - Timeline timeline, TimelineEvent event); + Timeline timeline, + TimelineEvent event, + ); bool shouldGetPreviewsInRoom(Room room); @@ -20,15 +22,13 @@ abstract class UrlPreviewComponent implements Component { // Instead of storing null, which is a bit confusing as if the cache returns null, does that mean we have // nothing cached, or the result was invalid? maybe this is dumb but it was the simplest way // to prevent weird ui glitches when failed fetches kept getting retried. - static UrlPreviewData invalidPreviewData = - UrlPreviewData(Uri.new(), title: "Unable to get url preview "); + static UrlPreviewData invalidPreviewData = UrlPreviewData( + Uri.new(), + title: "Unable to get url preview ", + ); } -enum UrlDestinationType { - page, - video, - image, -} +enum UrlDestinationType { page, video, image } class UrlPreviewData { final Uri uri; diff --git a/commet/lib/client/components/user_presence/user_presence_component.dart b/commet/lib/client/components/user_presence/user_presence_component.dart index 87980e91a..13cb6088e 100644 --- a/commet/lib/client/components/user_presence/user_presence_component.dart +++ b/commet/lib/client/components/user_presence/user_presence_component.dart @@ -2,16 +2,9 @@ import 'package:commet/client/client.dart'; import 'package:commet/client/components/component.dart'; import 'package:flutter/material.dart'; -enum UserPresenceStatus { - offline, - unknown, - online, - unavailable, -} +enum UserPresenceStatus { offline, unknown, online, unavailable } -enum PresenceMessageType { - userCustom, -} +enum PresenceMessageType { userCustom } class UserPresenceMessage { PresenceMessageType messageType; @@ -49,6 +42,9 @@ abstract class UserPresenceComponent implements Component { Future getUserPresence(String userId); - Future setStatus(UserPresenceStatus status, - {String? message, bool clearMessage = false}); + Future setStatus( + UserPresenceStatus status, { + String? message, + bool clearMessage = false, + }); } diff --git a/commet/lib/client/components/voip/android_screencapture_source.dart b/commet/lib/client/components/voip/android_screencapture_source.dart index b2b544971..a063cd397 100644 --- a/commet/lib/client/components/voip/android_screencapture_source.dart +++ b/commet/lib/client/components/voip/android_screencapture_source.dart @@ -7,7 +7,8 @@ import 'package:flutter_webrtc/flutter_webrtc.dart'; class WebrtcAndroidScreencaptureSource implements ScreenCaptureSource { static Future getCaptureSource( - BuildContext context) async { + BuildContext context, + ) async { if (PlatformUtils.isAndroid) { final permission = await Helper.requestCapturePermission(); if (permission == false) { @@ -23,13 +24,16 @@ class WebrtcAndroidScreencaptureSource implements ScreenCaptureSource { notificationTitle: 'Screen Sharing', notificationText: 'Commet is sharing the screen.', notificationImportance: AndroidNotificationImportance.normal, - notificationIcon: - AndroidResource(name: 'notification_icon', defType: 'mipmap'), + notificationIcon: AndroidResource( + name: 'notification_icon', + defType: 'mipmap', + ), ); if (!isRetry) { hasPermissions = await FlutterBackground.initialize( - androidConfig: androidConfig); + androidConfig: androidConfig, + ); } if (hasPermissions && !FlutterBackground.isBackgroundExecutionEnabled) { @@ -37,8 +41,10 @@ class WebrtcAndroidScreencaptureSource implements ScreenCaptureSource { } } catch (e) { if (!isRetry) { - return await Future.delayed(const Duration(seconds: 1), - () => requestBackgroundPermission(true)); + return await Future.delayed( + const Duration(seconds: 1), + () => requestBackgroundPermission(true), + ); } Log.e('could not publish video: $e'); } diff --git a/commet/lib/client/components/voip/voip_session.dart b/commet/lib/client/components/voip/voip_session.dart index b0b76b886..2b1ea983d 100644 --- a/commet/lib/client/components/voip/voip_session.dart +++ b/commet/lib/client/components/voip/voip_session.dart @@ -5,14 +5,7 @@ import 'package:commet/client/components/voip/voip_stream.dart'; import 'package:flutter/material.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; -enum VoipState { - incoming, - connecting, - connected, - unknown, - outgoing, - ended, -} +enum VoipState { incoming, connecting, connected, unknown, outgoing, ended } abstract class ScreenCaptureSource {} @@ -47,8 +40,10 @@ abstract class VoipSession { List get streams; - Future acceptCall( - {bool withMicrophone = false, bool withCamera = false}); + Future acceptCall({ + bool withMicrophone = false, + bool withCamera = false, + }); Future declineCall(); diff --git a/commet/lib/client/components/voip/webrtc_default_devices.dart b/commet/lib/client/components/voip/webrtc_default_devices.dart index 920eea4e6..4dd0bfb8c 100644 --- a/commet/lib/client/components/voip/webrtc_default_devices.dart +++ b/commet/lib/client/components/voip/webrtc_default_devices.dart @@ -20,11 +20,13 @@ class WebrtcDefaultDevices { if (preferences.voipDefaultAudioInput.value != null) { var pickedDevice = devices.firstWhereOrNull( - (i) => i.label == preferences.voipDefaultAudioInput.value); + (i) => i.label == preferences.voipDefaultAudioInput.value, + ); if (pickedDevice != null) { print( - "Picked device id: ${pickedDevice.deviceId} (${pickedDevice.label})"); + "Picked device id: ${pickedDevice.deviceId} (${pickedDevice.label})", + ); constraints["deviceId"] = {'exact': pickedDevice.deviceId}; webrtc.Helper.selectAudioInput(pickedDevice.deviceId); @@ -35,8 +37,9 @@ class WebrtcDefaultDevices { print("No default device set picking first"); } - return await webrtc.navigator.mediaDevices - .getUserMedia({"audio": constraints}); + return await webrtc.navigator.mediaDevices.getUserMedia({ + "audio": constraints, + }); } static Future> getDevices() async { @@ -63,7 +66,8 @@ class WebrtcDefaultDevices { return devices .firstWhereOrNull( - (i) => i.label == preferences.voipDefaultAudioInput.value) + (i) => i.label == preferences.voipDefaultAudioInput.value, + ) ?.deviceId; } @@ -72,11 +76,13 @@ class WebrtcDefaultDevices { if (preferences.voipDefaultAudioInput.value != null) { var pickedDevice = devices.firstWhereOrNull( - (i) => i.label == preferences.voipDefaultAudioInput.value); + (i) => i.label == preferences.voipDefaultAudioInput.value, + ); if (pickedDevice != null) { print( - "Picked device id: ${pickedDevice.deviceId} (${pickedDevice.label})"); + "Picked device id: ${pickedDevice.deviceId} (${pickedDevice.label})", + ); webrtc.Helper.selectAudioInput(pickedDevice.deviceId); } else { @@ -91,7 +97,8 @@ class WebrtcDefaultDevices { var devices = (await getDevices()).where((i) => i.kind == "audiooutput"); var device = devices.firstWhereOrNull( - (i) => i.label == preferences.voipDefaultAudioOutput.value); + (i) => i.label == preferences.voipDefaultAudioOutput.value, + ); if (device != null) { Log.i("Setting webrtc output to: ${device.label} (${device.deviceId})"); diff --git a/commet/lib/client/components/voip/webrtc_screencapture_source.dart b/commet/lib/client/components/voip/webrtc_screencapture_source.dart index 3e2986a2c..47e3c52aa 100644 --- a/commet/lib/client/components/voip/webrtc_screencapture_source.dart +++ b/commet/lib/client/components/voip/webrtc_screencapture_source.dart @@ -14,7 +14,8 @@ class WebrtcScreencaptureSource implements ScreenCaptureSource { static bool get supportsSystemAudio => PlatformUtils.isWindows; static Future showSelectSourcePrompt( - BuildContext context) async { + BuildContext context, + ) async { if (PlatformUtils.isAndroid) { return WebrtcAndroidScreencaptureSource.getCaptureSource(context); } @@ -30,10 +31,14 @@ class WebrtcScreencaptureSource implements ScreenCaptureSource { } if (context.mounted) { - var result = await PopupDialog.show(context, - content: ScreenCaptureSourceDialog( - sources, desktopCapturer.onThumbnailChanged.stream), - title: "Screen Share"); + var result = await PopupDialog.show( + context, + content: ScreenCaptureSourceDialog( + sources, + desktopCapturer.onThumbnailChanged.stream, + ), + title: "Screen Share", + ); if (result != null) { return WebrtcScreencaptureSource(result); diff --git a/commet/lib/client/components/widgets/widget_component.dart b/commet/lib/client/components/widgets/widget_component.dart index 3de5bf6fd..4293f75d4 100644 --- a/commet/lib/client/components/widgets/widget_component.dart +++ b/commet/lib/client/components/widgets/widget_component.dart @@ -48,10 +48,7 @@ abstract class WidgetTransceiver { Stream get onReceived; } -enum WidgetMessageDirection { - incoming, - outgoing, -} +enum WidgetMessageDirection { incoming, outgoing } abstract class WidgetMessageTransport { Future> send(Map msg); @@ -64,8 +61,10 @@ abstract class WidgetMessageTransport { abstract class WidgetEventHandler { String generateRequestId(); - Map generateToWidgetEvent( - {required String action, required Map data}); + Map generateToWidgetEvent({ + required String action, + required Map data, + }); } abstract class WidgetRunner { @@ -95,11 +94,16 @@ abstract class WidgetComponent implements Component { Stream get onWidgetsChanged; - static NotifyingList currentSessions = - NotifyingList.empty(growable: true); + static NotifyingList currentSessions = NotifyingList.empty( + growable: true, + ); - static void runWidget(Room room, BuildContext context, UserWidgetInfo data, - {WidgetHostType? type}) async { + static void runWidget( + Room room, + BuildContext context, + UserWidgetInfo data, { + WidgetHostType? type, + }) async { var widgetComponent = room.client.getComponent(); for (var session in WidgetComponent.currentSessions) { @@ -111,13 +115,15 @@ abstract class WidgetComponent implements Component { } if (!preferences.getWidgetAllowed(room.client.identifier, data.namespace)) { - var confirmed = await AdaptiveDialog.confirmationWithOptions(context, - title: "Widget", - showRememberChoice: true, - defaultRememberSetting: true, - prompt: - """Open `${Uri.parse(data.url).authority}`?\n\n'**${data.name}**' was added by `${data.senderId}`""", - confirmationText: "Open Widget"); + var confirmed = await AdaptiveDialog.confirmationWithOptions( + context, + title: "Widget", + showRememberChoice: true, + defaultRememberSetting: true, + prompt: + """Open `${Uri.parse(data.url).authority}`?\n\n'**${data.name}**' was added by `${data.senderId}`""", + confirmationText: "Open Widget", + ); if (confirmed?.value != true) { return; @@ -125,7 +131,10 @@ abstract class WidgetComponent implements Component { if (confirmed?.remember == true) { preferences.setWidgetAllowed( - room.client.identifier, data.namespace, true); + room.client.identifier, + data.namespace, + true, + ); } } widgetComponent?.openWidget(data, room, context, type: type); @@ -139,10 +148,15 @@ abstract class WidgetComponent implements Component { String? widgetName, }); - Future removeWidget( - {required UserWidgetInfo widget, required Room room}); + Future removeWidget({ + required UserWidgetInfo widget, + required Room room, + }); Future openWidget( - UserWidgetInfo widget, Room room, BuildContext context, - {WidgetHostType? type}); + UserWidgetInfo widget, + Room room, + BuildContext context, { + WidgetHostType? type, + }); } diff --git a/commet/lib/client/matrix/auth/matrix_sso_login_flow.dart b/commet/lib/client/matrix/auth/matrix_sso_login_flow.dart index 02abf2882..6c71ef584 100644 --- a/commet/lib/client/matrix/auth/matrix_sso_login_flow.dart +++ b/commet/lib/client/matrix/auth/matrix_sso_login_flow.dart @@ -25,28 +25,26 @@ class MatrixSSOLoginFlow implements SsoLoginFlow { MatrixSSOLoginFlow({this.id, required this.name, this.icon, this.brand}); factory MatrixSSOLoginFlow.fromJson( - MatrixClient client, Map json) => - MatrixSSOLoginFlow( - id: json['id'], - name: json['name'], - icon: json['icon'] != null - ? getLoginFlowImage( - Uri.parse( - json['icon'], - ), - client, - ) - : null, - brand: json['brand'], - ); + MatrixClient client, + Map json, + ) => MatrixSSOLoginFlow( + id: json['id'], + name: json['name'], + icon: json['icon'] != null + ? getLoginFlowImage(Uri.parse(json['icon']), client) + : null, + brand: json['brand'], + ); static NetworkImage getLoginFlowImage(Uri mxc, MatrixClient client) { var path = '_matrix/media/v3/thumbnail/${Uri.encodeComponent(mxc.authority)}/${Uri.encodeComponent(mxc.pathSegments.first)}'; var server = client.getMatrixClient().baseUri!; - var request = - server.replace(path: path, query: "width=96&height=96&method=crop"); + var request = server.replace( + path: path, + query: "width=96&height=96&method=crop", + ); return NetworkImage(request.toString()); } @@ -54,7 +52,8 @@ class MatrixSSOLoginFlow implements SsoLoginFlow { Future submit(Client client) async { if (client is! MatrixClient) { return LoginResultError( - "Attemted to login with the wrong type of client"); + "Attemted to login with the wrong type of client", + ); } try { @@ -83,21 +82,17 @@ class MatrixSSOLoginFlow implements SsoLoginFlow { ); final result = await FlutterWebAuth2.authenticate( - url: url.toString(), - callbackUrlScheme: callbackScheme, - options: FlutterWebAuth2Options( - useWebview: false, - )); + url: url.toString(), + callbackUrlScheme: callbackScheme, + options: FlutterWebAuth2Options(useWebview: false), + ); var token = Uri.parse(result).queryParameters['loginToken']; if (token?.isEmpty ?? false) { return LoginResultFailed(); } - var login = await mx.login( - matrix.LoginType.mLoginToken, - token: token, - ); + var login = await mx.login(matrix.LoginType.mLoginToken, token: token); if (login.accessToken.isNotEmpty) { return LoginResultSuccess(); diff --git a/commet/lib/client/matrix/auth/matrix_username_password_login_flow.dart b/commet/lib/client/matrix/auth/matrix_username_password_login_flow.dart index 5a0c40d5f..8e47f8378 100644 --- a/commet/lib/client/matrix/auth/matrix_username_password_login_flow.dart +++ b/commet/lib/client/matrix/auth/matrix_username_password_login_flow.dart @@ -7,10 +7,10 @@ import 'package:intl/intl.dart'; import 'package:matrix/matrix.dart' as matrix; String get messageUserDeactivated => Intl.message( - "Your account has been deactivated", - name: "messageUserDeactivated", - desc: - "An error message displayed when the user attempts to log into an account that has been disabled"); + "Your account has been deactivated", + name: "messageUserDeactivated", + desc: "An error message displayed when the user attempts to log into an account that has been disabled", +); class MatrixPasswordLoginFlow implements PasswordLoginFlow { @override @@ -37,10 +37,12 @@ class MatrixPasswordLoginFlow implements PasswordLoginFlow { LoginResult result = LoginResultError("An unknown error occurred"); try { - var response = await mx.login(matrix.LoginType.mLoginPassword, - initialDeviceDisplayName: BuildConfig.appName, - password: password, - identifier: matrix.AuthenticationUserIdentifier(user: username!)); + var response = await mx.login( + matrix.LoginType.mLoginPassword, + initialDeviceDisplayName: BuildConfig.appName, + password: password, + identifier: matrix.AuthenticationUserIdentifier(user: username!), + ); if (response.accessToken.isNotEmpty) { result = LoginResultSuccess(); diff --git a/commet/lib/client/matrix/components/account_switch_prefix/matrix_account_switch_prefix.dart b/commet/lib/client/matrix/components/account_switch_prefix/matrix_account_switch_prefix.dart index 813949c3f..66ab2d67c 100644 --- a/commet/lib/client/matrix/components/account_switch_prefix/matrix_account_switch_prefix.dart +++ b/commet/lib/client/matrix/components/account_switch_prefix/matrix_account_switch_prefix.dart @@ -78,8 +78,11 @@ class MatrixAccountSwitchComponent extends AccountSwitchPrefix { content["prefix"] = prefix.trim(); } - await client.matrixClient - .setAccountData(client.matrixClient.userID!, accountDataKey, content); + await client.matrixClient.setAccountData( + client.matrixClient.userID!, + accountDataKey, + content, + ); } @override diff --git a/commet/lib/client/matrix/components/calendar_room_component/matrix_calendar_room_component.dart b/commet/lib/client/matrix/components/calendar_room_component/matrix_calendar_room_component.dart index e9bf155d5..bf9759edb 100644 --- a/commet/lib/client/matrix/components/calendar_room_component/matrix_calendar_room_component.dart +++ b/commet/lib/client/matrix/components/calendar_room_component/matrix_calendar_room_component.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; + import 'package:collection/collection.dart'; import 'package:commet/client/components/calendar_room/calendar_room_component.dart'; import 'package:commet/client/components/calendar_room/calendar_sync.dart'; @@ -69,8 +70,10 @@ class MatrixCalendarRoomComponent } MatrixCalendarRoomComponent(this.client, this.room) { - var api = - PrivelidgedMatrixWidgetRunner(client.matrixClient, room.matrixRoom); + var api = PrivelidgedMatrixWidgetRunner( + client.matrixClient, + room.matrixRoom, + ); if (isCalendarRoom) { _calendar = MatrixCalendar(api, config: CustomMatrixCalendarConfig(room)); @@ -104,10 +107,14 @@ class MatrixCalendarRoomComponent return _calendar!; } else { if (isCalendarRoom || hasCalendarWidget) { - var api = - PrivelidgedMatrixWidgetRunner(client.matrixClient, room.matrixRoom); - _calendar = - MatrixCalendar(api, config: CustomMatrixCalendarConfig(room)); + var api = PrivelidgedMatrixWidgetRunner( + client.matrixClient, + room.matrixRoom, + ); + _calendar = MatrixCalendar( + api, + config: CustomMatrixCalendarConfig(room), + ); _calendar!.controller.addListener(() { controller.add(()); }); @@ -120,11 +127,14 @@ class MatrixCalendarRoomComponent bool get hasCalendarWidget => room.matrixRoom.states.containsKey("chat.commet.calendar_events") || - room.matrixRoom.states["im.vector.modular.widgets"]?.values.any((i) => - i.content["type"] == "chat.commet.widgets.calendar" || - (i.content["url"] as String?)?.startsWith( - "https://${GlobalConfig.calendarWidgetHost}") == - true) == + room.matrixRoom.states["im.vector.modular.widgets"]?.values.any( + (i) => + i.content["type"] == "chat.commet.widgets.calendar" || + (i.content["url"] as String?)?.startsWith( + "https://${GlobalConfig.calendarWidgetHost}", + ) == + true, + ) == true; @override @@ -152,20 +162,26 @@ class MatrixCalendarRoomComponent if (data != null && room.isE2EE) { if (data.content.isNotEmpty) { Log.w( - "Deleting calendar URL source because this room is encrypted, and the source is stored in plaintext - you should generate a new URL"); + "Deleting calendar URL source because this room is encrypted, and the source is stored in plaintext - you should generate a new URL", + ); Log.w(data.content); room.matrixRoom.client.setAccountDataPerRoom( - client.matrixClient.userID!, - room.identifier, - syncedCalendarsEventType, {}); + client.matrixClient.userID!, + room.identifier, + syncedCalendarsEventType, + {}, + ); } } if (room.isE2EE) { - data = BasicEvent(type: syncedCalendarsEventType, content: { - "remote_calendars": preferences.getCalendarSources(room.identifier) - }); + data = BasicEvent( + type: syncedCalendarsEventType, + content: { + "remote_calendars": preferences.getCalendarSources(room.identifier), + }, + ); } if (data == null) { @@ -260,13 +276,16 @@ class MatrixCalendarRoomComponent if (entry.value.overrideEventName != null) { events = events - .map((i) => RFC8984CalendarEvent( + .map( + (i) => RFC8984CalendarEvent( uid: i.uid, updated: i.updated, title: entry.value.overrideEventName!, start: i.start, timeZone: i.timeZone, - duration: i.duration)) + duration: i.duration, + ), + ) .toList(); } @@ -280,11 +299,13 @@ class MatrixCalendarRoomComponent foundEvents[entry.key] = events; } } - calendar!.syncEvents(foundEvents, - eventType: switch (entry.value.syncType) { - CalendarSyncType.events => "event", - CalendarSyncType.unavailability => "unavailability" - }); + calendar!.syncEvents( + foundEvents, + eventType: switch (entry.value.syncType) { + CalendarSyncType.events => "event", + CalendarSyncType.unavailability => "unavailability", + }, + ); } } @@ -320,7 +341,8 @@ class MatrixCalendarRoomComponent final title = (data["summary"] as String?) ?? "(No title)"; - var updated = (data["lastModified"] as ical.IcsDateTime?)?.toDateTime() ?? + var updated = + (data["lastModified"] as ical.IcsDateTime?)?.toDateTime() ?? DateTime.now(); var uid = sha1.convert("$calendarId/${data["uid"]}".codeUnits); @@ -352,8 +374,9 @@ class MatrixCalendarRoomComponent var frequency = rule["FREQ"]?.toLowerCase(); var firstDayOfWeek = rule["WKST"]?.toLowerCase(); int? count = rule["COUNT"] != null ? int.parse(rule["COUNT"]!) : null; - int? interval = - rule["INTERVAL"] != null ? int.parse(rule["INTERVAL"]!) : null; + int? interval = rule["INTERVAL"] != null + ? int.parse(rule["INTERVAL"]!) + : null; if (frequency == null) return null; @@ -363,11 +386,12 @@ class MatrixCalendarRoomComponent } return RFC8984RecurrenceRule( - firstDayOfWeek: firstDayOfWeek, - frequency: frequency, - interval: interval, - count: count, - byDay: byDays); + firstDayOfWeek: firstDayOfWeek, + frequency: frequency, + interval: interval, + count: count, + byDay: byDays, + ); } List parseByDays(String rule) { @@ -417,8 +441,10 @@ class MatrixCalendarRoomComponent } @override - Future> getEventsFromIcsUrl(Uri uri, - {String? calendarId}) async { + Future> getEventsFromIcsUrl( + Uri uri, { + String? calendarId, + }) async { var result = await http.get(uri); if (result.statusCode != 200) { @@ -436,8 +462,10 @@ class MatrixCalendarRoomComponent return results; } - bool shouldUpdateState(List existingEvents, - List eventsAfterSync) { + bool shouldUpdateState( + List existingEvents, + List eventsAfterSync, + ) { if (existingEvents.length != eventsAfterSync.length) return true; existingEvents.sort((a, b) => a.data.start.compareTo(b.data.start)); @@ -453,7 +481,9 @@ class MatrixCalendarRoomComponent } bool containsEvent( - List list, RFC8984CalendarEvent event) { + List list, + RFC8984CalendarEvent event, + ) { var b = event.toJson(); b.remove("uid"); b.remove("updated"); @@ -472,8 +502,10 @@ class MatrixCalendarRoomComponent return contained != null; } - bool areEventListsIdentical(List existingEvents, - List events) { + bool areEventListsIdentical( + List existingEvents, + List events, + ) { if (existingEvents.any((i) => !containsEvent(events, i))) { return false; } diff --git a/commet/lib/client/matrix/components/command_component/matrix_command_component.dart b/commet/lib/client/matrix/components/command_component/matrix_command_component.dart index 4ba3705ad..3a6e9eec9 100644 --- a/commet/lib/client/matrix/components/command_component/matrix_command_component.dart +++ b/commet/lib/client/matrix/components/command_component/matrix_command_component.dart @@ -43,8 +43,12 @@ class MatrixCommandComponent extends CommandComponent { } @override - Future executeCommand(String string, Room room, - {TimelineEvent? interactingEvent, EventInteractionType? type}) async { + Future executeCommand( + String string, + Room room, { + TimelineEvent? interactingEvent, + EventInteractionType? type, + }) async { var mxRoom = (room as MatrixRoom).matrixRoom; matrix.Event? event; if (interactingEvent != null) { @@ -63,20 +67,22 @@ class MatrixCommandComponent extends CommandComponent { } if (editingEvent != null) { await room.sendMessage( - message: - editingEvent.plainTextBody.replaceFirst(match[1]!, match[2]!), - replaceEvent: editingEvent); + message: editingEvent.plainTextBody.replaceFirst( + match[1]!, + match[2]!, + ), + replaceEvent: editingEvent, + ); return; } } await client.getMatrixClient().parseAndRunCommand( - mxRoom, - string, - inReplyTo: type == EventInteractionType.reply ? event : null, - editEventId: - type == EventInteractionType.edit ? event?.eventId : null, - ); + mxRoom, + string, + inReplyTo: type == EventInteractionType.reply ? event : null, + editEventId: type == EventInteractionType.edit ? event?.eventId : null, + ); } @override @@ -84,7 +90,8 @@ class MatrixCommandComponent extends CommandComponent { if (string.startsWith("/")) { var command = string.substring(1).split(" ").first; return client.getMatrixClient().commands.containsKey(command); - } else if (sed_pattern.firstMatch(string) != null) return true; + } else if (sed_pattern.firstMatch(string) != null) + return true; return false; } @@ -93,9 +100,12 @@ class MatrixCommandComponent extends CommandComponent { var json = const JsonDecoder().convert(args.msg) as Map; var tx = client.getMatrixClient().generateUniqueTransactionId(); - client - .getMatrixClient() - .sendMessage(args.room!.id, json["type"], tx, json['content']); + client.getMatrixClient().sendMessage( + args.room!.id, + json["type"], + tx, + json['content'], + ); return null; } @@ -106,25 +116,33 @@ class MatrixCommandComponent extends CommandComponent { } FutureOr setStatus( - matrix.CommandArgs args, StringBuffer? out) async { + matrix.CommandArgs args, + StringBuffer? out, + ) async { client.getComponent()?.setStatus(args.msg); await client.getMatrixClient().setPresence( - client.getMatrixClient().userID!, PresenceType.online, - statusMsg: args.msg); + client.getMatrixClient().userID!, + PresenceType.online, + statusMsg: args.msg, + ); return null; } FutureOr clearEmojiStats( - matrix.CommandArgs args, StringBuffer? out) async { + matrix.CommandArgs args, + StringBuffer? out, + ) async { var c = client.getComponent(); c?.clear(); return null; } FutureOr setProfile( - matrix.CommandArgs args, StringBuffer? stdout) async { + matrix.CommandArgs args, + StringBuffer? stdout, + ) async { final parts = args.msg.split(" "); final field = parts[0]; final content = parts.sublist(1).join(" "); @@ -142,7 +160,9 @@ class MatrixCommandComponent extends CommandComponent { } FutureOr addWidget( - matrix.CommandArgs args, StringBuffer? out) async { + matrix.CommandArgs args, + StringBuffer? out, + ) async { if (args.room == null) return null; var custom = CustomURI.parse(args.msg); @@ -150,23 +170,32 @@ class MatrixCommandComponent extends CommandComponent { if (custom == null) { var url = Uri.parse(args.msg); custom = AddWidgetURI( - widgetUrl: url.toString(), - widgetName: "Custom", - widgetType: "m.custom"); + widgetUrl: url.toString(), + widgetName: "Custom", + widgetType: "m.custom", + ); } if (custom case AddWidgetURI widgetUri) { - AdaptiveDialog.show(navigator.currentContext!, builder: (dialogContext) { - return AddWidgetDialog( - widgetUri: widgetUri, room: client.getRoom(args.room!.id)!); - }, title: 'Add "${widgetUri.widgetName ?? "Widget"}"?'); + AdaptiveDialog.show( + navigator.currentContext!, + builder: (dialogContext) { + return AddWidgetDialog( + widgetUri: widgetUri, + room: client.getRoom(args.room!.id)!, + ); + }, + title: 'Add "${widgetUri.widgetName ?? "Widget"}"?', + ); } return null; } FutureOr sendRainbow( - matrix.CommandArgs args, StringBuffer? out) async { + matrix.CommandArgs args, + StringBuffer? out, + ) async { if (args.room == null) return null; if (args.msg.isEmpty) return null; diff --git a/commet/lib/client/matrix/components/direct_messages/matrix_direct_messages_component.dart b/commet/lib/client/matrix/components/direct_messages/matrix_direct_messages_component.dart index 8a746423b..218d5fd2b 100644 --- a/commet/lib/client/matrix/components/direct_messages/matrix_direct_messages_component.dart +++ b/commet/lib/client/matrix/components/direct_messages/matrix_direct_messages_component.dart @@ -18,8 +18,9 @@ class MatrixDirectMessagesComponent INotifyingList directMessageRooms = NotifyingList.empty(growable: true); @override - INotifyingList highlightedRoomsList = - NotifyingList.empty(growable: true); + INotifyingList highlightedRoomsList = NotifyingList.empty( + growable: true, + ); String currentRoomId = ""; @@ -29,8 +30,9 @@ class MatrixDirectMessagesComponent MatrixDirectMessagesComponent(this.client) { client.getMatrixClient().onSync.stream.listen(onMatrixSync); - EventBus.onSelectedRoomChanged.stream - .listen((value) => currentRoomId = value?.identifier ?? ""); + EventBus.onSelectedRoomChanged.stream.listen( + (value) => currentRoomId = value?.identifier ?? "", + ); directMessageRooms = NotifyingListFilter( client.rooms, @@ -84,8 +86,9 @@ class MatrixDirectMessagesComponent _directMessagesChanged.add(null); } - if (event.rooms?.join?.entries - .any((e) => e.value.unreadNotifications != null) == + if (event.rooms?.join?.entries.any( + (e) => e.value.unreadNotifications != null, + ) == true) { _notificationsChanged.add(null); } diff --git a/commet/lib/client/matrix/components/donation_awards_component/matrix_donation_awards.dart b/commet/lib/client/matrix/components/donation_awards_component/matrix_donation_awards.dart index 92f47c535..ed44618af 100644 --- a/commet/lib/client/matrix/components/donation_awards_component/matrix_donation_awards.dart +++ b/commet/lib/client/matrix/components/donation_awards_component/matrix_donation_awards.dart @@ -30,7 +30,9 @@ class MatrixDonationAwardsComponent if (validateSecret(secret)) { Log.i("Re-using existing secret"); return SecretClientIdentifier( - clientSecret: secret, encryptedHash: encrypted_hash); + clientSecret: secret, + encryptedHash: encrypted_hash, + ); } } } else { @@ -42,15 +44,21 @@ class MatrixDonationAwardsComponent Log.i("Generated Secret: $secret"); Log.i("Generated id hash: $encryptedIdHash"); - await client.matrixClient.setAccountData(client.matrixClient.userID!, - secretKey, {"secret": secret, "encrypted_id_hash": encryptedIdHash}); + await client.matrixClient.setAccountData( + client.matrixClient.userID!, + secretKey, + {"secret": secret, "encrypted_id_hash": encryptedIdHash}, + ); return SecretClientIdentifier( - clientSecret: secret, encryptedHash: encryptedIdHash); + clientSecret: secret, + encryptedHash: encryptedIdHash, + ); } Log.e( - "Failed to get client secret, one already exists, but it is not valid"); + "Failed to get client secret, one already exists, but it is not valid", + ); return null; } @@ -77,16 +85,21 @@ class MatrixDonationAwardsComponent final secretKey = await algorithm.newSecretKeyFromBytes(secretBytes); - var userIdHash = - sha256.convert(AsciiEncoder().convert(client.matrixClient.userID!)); + var userIdHash = sha256.convert( + AsciiEncoder().convert(client.matrixClient.userID!), + ); Log.i( - "Hash: ${TextUtils.toHexString(Uint8List.fromList(userIdHash.bytes))}"); + "Hash: ${TextUtils.toHexString(Uint8List.fromList(userIdHash.bytes))}", + ); var nonce = await algorithm.newNonce(); - final encrypted = await algorithm.encrypt(userIdHash.bytes, - secretKey: secretKey, nonce: nonce); + final encrypted = await algorithm.encrypt( + userIdHash.bytes, + secretKey: secretKey, + nonce: nonce, + ); final bytes = Uint8List.fromList(encrypted.cipherText); @@ -95,7 +108,8 @@ class MatrixDonationAwardsComponent Log.i("Ciphertext: ${bytes}"); final encryptedUserIdHash = TextUtils.toHexString( - Uint8List.fromList(bytes + Uint8List.fromList(encrypted.mac.bytes))); + Uint8List.fromList(bytes + Uint8List.fromList(encrypted.mac.bytes)), + ); final iv = TextUtils.toHexString(Uint8List.fromList(nonce)); @@ -108,8 +122,11 @@ class MatrixDonationAwardsComponent var id = award["signed"]["id"] as String; var sender = award["signed"]["sender"] as String; - await client.matrixClient.setAccountData(client.matrixClient.userID!, - "chat.commet.profile_badge.${id}${sender}", award); + await client.matrixClient.setAccountData( + client.matrixClient.userID!, + "chat.commet.profile_badge.${id}${sender}", + award, + ); } } } diff --git a/commet/lib/client/matrix/components/emoticon/matrix_emoticon.dart b/commet/lib/client/matrix/components/emoticon/matrix_emoticon.dart index a6e673d0e..15b6e40c8 100644 --- a/commet/lib/client/matrix/components/emoticon/matrix_emoticon.dart +++ b/commet/lib/client/matrix/components/emoticon/matrix_emoticon.dart @@ -23,16 +23,22 @@ class MatrixEmoticon implements Emoticon { EmoticonUsage packUsage; - MatrixEmoticon(this.emojiUrl, matrix.Client client, - {required this.packUsage, - required String shortcode, - required this.usage}) { + MatrixEmoticon( + this.emojiUrl, + matrix.Client client, { + required this.packUsage, + required String shortcode, + required this.usage, + }) { _shortcode = shortcode; - _image = MatrixMxcImage(emojiUrl, client, - fullResHeight: 100, - doThumbnail: false, - doFullres: true, - autoLoadFullRes: true); + _image = MatrixMxcImage( + emojiUrl, + client, + fullResHeight: 100, + doThumbnail: false, + doFullres: true, + autoLoadFullRes: true, + ); } void setShortcode(String shortcode) { diff --git a/commet/lib/client/matrix/components/emoticon/matrix_emoticon_component.dart b/commet/lib/client/matrix/components/emoticon/matrix_emoticon_component.dart index a799ae0ee..a3cbed836 100644 --- a/commet/lib/client/matrix/components/emoticon/matrix_emoticon_component.dart +++ b/commet/lib/client/matrix/components/emoticon/matrix_emoticon_component.dart @@ -46,16 +46,19 @@ class MatrixEmoticonComponent extends EmoticonComponent { void refreshOwnedPacks() { final state = this.state.getAllStates(); - _ownedPacks = state.entries.where((e) { - final val = e.value; - if (val is Map) { - return val.isNotEmpty; - } else { - return false; - } - }).map((e) { - return MatrixEmoticonPack(this, e.key, e.value); - }).toList(); + _ownedPacks = state.entries + .where((e) { + final val = e.value; + if (val is Map) { + return val.isNotEmpty; + } else { + return false; + } + }) + .map((e) { + return MatrixEmoticonPack(this, e.key, e.value); + }) + .toList(); } @override @@ -92,8 +95,8 @@ class MatrixEmoticonComponent extends EmoticonComponent { var content = { "pack": { "display_name": name, - if (avatar != null) "avatar_url": avatar.toString() - } + if (avatar != null) "avatar_url": avatar.toString(), + }, }; String stateKey = getNewPackKeyState(name); @@ -102,8 +105,12 @@ class MatrixEmoticonComponent extends EmoticonComponent { } @override - Future importEmoticonPack(String name, int avatarIndex, - List names, List imageDatas) async { + Future importEmoticonPack( + String name, + int avatarIndex, + List names, + List imageDatas, + ) async { var task = MatrixImportEmoticonPackTask(imageDatas, client); backgroundTaskManager.addTask(task); var uris = await task.uploadImages(); @@ -113,14 +120,14 @@ class MatrixEmoticonComponent extends EmoticonComponent { "display_name": name, "avatar_url": uris[avatarIndex].toString(), }, - "images": {} + "images": {}, }; for (var i = 0; i < names.length; i++) { var name = names[i]; content["images"]![name] = { "display_name": name, - "url": uris[i]!.toString() + "url": uris[i]!.toString(), }; } @@ -159,8 +166,9 @@ class MatrixEmoticonComponent extends EmoticonComponent { if (!matrixClient.accountData.containsKey(globalEmoteRoomsStateKey)) return []; - var rooms = matrixClient.accountData[globalEmoteRoomsStateKey]! - .content['rooms'] as Map; + var rooms = + matrixClient.accountData[globalEmoteRoomsStateKey]!.content['rooms'] + as Map; var packs = List.empty(growable: true); @@ -192,8 +200,9 @@ class MatrixEmoticonComponent extends EmoticonComponent { if (emoji == null) continue; - var matchingPacks = - emoji.where((element) => element.identifier == packKey); + var matchingPacks = emoji.where( + (element) => element.identifier == packKey, + ); if (matchingPacks.isEmpty) continue; @@ -229,8 +238,12 @@ class MatrixEmoticonComponent extends EmoticonComponent { return state.setState(packKey, content); } - Future updatePack(String packKey, - {EmoticonUsage? usage, String? name, Uint8List? imageData}) async { + Future updatePack( + String packKey, { + EmoticonUsage? usage, + String? name, + Uint8List? imageData, + }) async { var content = state.getState(packKey); if (usage != null) { @@ -324,7 +337,8 @@ class MatrixEmoticonComponent extends EmoticonComponent { globalPacks() + ownedPacks + UnicodeEmojis.packs!; Map> getEmotePacksFlat( - matrix.ImagePackUsage emoticon) { + matrix.ImagePackUsage emoticon, + ) { var packs = globalPacks() + ownedPacks; var result = >{}; @@ -333,8 +347,8 @@ class MatrixEmoticonComponent extends EmoticonComponent { var key = "${pack.displayName}-${pack.hashCode}"; result[key] = {}; for (var emote in pack.emotes) { - result[key]![emote.shortcode!] = - (emote as MatrixEmoticon).emojiUrl.toString(); + result[key]![emote.shortcode!] = (emote as MatrixEmoticon).emojiUrl + .toString(); } } diff --git a/commet/lib/client/matrix/components/emoticon/matrix_emoticon_pack.dart b/commet/lib/client/matrix/components/emoticon/matrix_emoticon_pack.dart index cbd4b7e7f..e63fa83a1 100644 --- a/commet/lib/client/matrix/components/emoticon/matrix_emoticon_pack.dart +++ b/commet/lib/client/matrix/components/emoticon/matrix_emoticon_pack.dart @@ -35,8 +35,13 @@ class MatrixEmoticonPack implements EmoticonPack { final usage = usagesArrayToUsage(usages); - return MatrixEmoticon(Uri.parse(url), component.client.getMatrixClient(), - packUsage: this.usage, shortcode: shortCode, usage: usage); + return MatrixEmoticon( + Uri.parse(url), + component.client.getMatrixClient(), + packUsage: this.usage, + shortcode: shortCode, + usage: usage, + ); }).toList(); } @@ -57,8 +62,12 @@ class MatrixEmoticonPack implements EmoticonPack { final url = pack?.tryGet("avatar_url"); if (url != null) { - return MatrixMxcImage(Uri.parse(url), component.client.getMatrixClient(), - doFullres: true, fullResHeight: 64); + return MatrixMxcImage( + Uri.parse(url), + component.client.getMatrixClient(), + doFullres: true, + fullResHeight: 64, + ); } return null; @@ -102,15 +111,21 @@ class MatrixEmoticonPack implements EmoticonPack { } @override - Future updateEmoticon( - {String? slug, - String? shortcode, - Uint8List? data, - String? mimeType, - EmoticonUsage? usage, - required Emoticon previous}) async { - await component.updateEmoticon(identifier, shortcode!, - data: data, usage: usage, previous: previous); + Future updateEmoticon({ + String? slug, + String? shortcode, + Uint8List? data, + String? mimeType, + EmoticonUsage? usage, + required Emoticon previous, + }) async { + await component.updateEmoticon( + identifier, + shortcode!, + data: data, + usage: usage, + previous: previous, + ); } @override @@ -168,10 +183,17 @@ class MatrixEmoticonPack implements EmoticonPack { } @override - Future updatePack( - {EmoticonUsage? usage, String? name, Uint8List? imageData}) { - return component.updatePack(identifier, - usage: usage, name: name, imageData: imageData); + Future updatePack({ + EmoticonUsage? usage, + String? name, + Uint8List? imageData, + }) { + return component.updatePack( + identifier, + usage: usage, + name: name, + imageData: imageData, + ); } @override @@ -234,7 +256,8 @@ class MatrixEmoticonPack implements EmoticonPack { } final data = room - .client.accountData[MatrixEmoticonComponent.globalEmoteRoomsStateKey]; + .client + .accountData[MatrixEmoticonComponent.globalEmoteRoomsStateKey]; if (data == null) { return false; } diff --git a/commet/lib/client/matrix/components/emoticon/matrix_emoticon_state_manager.dart b/commet/lib/client/matrix/components/emoticon/matrix_emoticon_state_manager.dart index 022f1916d..d4b22a6b2 100644 --- a/commet/lib/client/matrix/components/emoticon/matrix_emoticon_state_manager.dart +++ b/commet/lib/client/matrix/components/emoticon/matrix_emoticon_state_manager.dart @@ -28,17 +28,19 @@ class MatrixEmoticonPersonalStateManager implements MatrixEmoticonStateManager { mx.onLoginStateChanged.stream .where((event) => event == matrix.LoginState.loggedIn) .listen((event) async { - if (mx.accountDataLoading != null) { - await mx.accountDataLoading; - } + if (mx.accountDataLoading != null) { + await mx.accountDataLoading; + } - onStateChangedController.add(null); - }); + onStateChangedController.add(null); + }); mx.onSync.stream.where((e) => e.accountData != null).listen((update) { - if (update.accountData?.any((e) => - e.type == "im.ponies.user_emotes" || - e.type == "im.ponies.emote_rooms") == + if (update.accountData?.any( + (e) => + e.type == "im.ponies.user_emotes" || + e.type == "im.ponies.emote_rooms", + ) == true) { onStateChangedController.add(null); } @@ -58,7 +60,10 @@ class MatrixEmoticonPersonalStateManager implements MatrixEmoticonStateManager { @override Future setState(String packKey, Map content) { return client.getMatrixClient().setAccountData( - client.getMatrixClient().userID!, "im.ponies.user_emotes", content); + client.getMatrixClient().userID!, + "im.ponies.user_emotes", + content, + ); } @override @@ -84,12 +89,14 @@ class MatrixEmoticonRoomStateManager implements MatrixEmoticonStateManager { var mx = room.client; mx.onRoomState.stream - .where((event) => - event.roomId == room.id && - event.state.type == MatrixEmoticonComponent.roomEmotesStateKey) + .where( + (event) => + event.roomId == room.id && + event.state.type == MatrixEmoticonComponent.roomEmotesStateKey, + ) .listen((event) { - onStateChangedController.add(null); - }); + onStateChangedController.add(null); + }); onStateChangedController.add(null); } @@ -99,8 +106,9 @@ class MatrixEmoticonRoomStateManager implements MatrixEmoticonStateManager { if (!room.states.containsKey(MatrixEmoticonComponent.roomEmotesStateKey)) return {}; - var state = (room.states[MatrixEmoticonComponent.roomEmotesStateKey] - as Map); + var state = + (room.states[MatrixEmoticonComponent.roomEmotesStateKey] + as Map); var result = {}; @@ -121,7 +129,11 @@ class MatrixEmoticonRoomStateManager implements MatrixEmoticonStateManager { @override Future setState(String packKey, Map content) async { var event = await room.client.setRoomStateWithKey( - room.id, MatrixEmoticonComponent.roomEmotesStateKey, packKey, content); + room.id, + MatrixEmoticonComponent.roomEmotesStateKey, + packKey, + content, + ); var result = await room.getEventById(event); room.states[MatrixEmoticonComponent.roomEmotesStateKey]![packKey] = result!; diff --git a/commet/lib/client/matrix/components/emoticon/matrix_room_emoticon_component.dart b/commet/lib/client/matrix/components/emoticon/matrix_room_emoticon_component.dart index c2e263e79..bb264ce72 100644 --- a/commet/lib/client/matrix/components/emoticon/matrix_room_emoticon_component.dart +++ b/commet/lib/client/matrix/components/emoticon/matrix_room_emoticon_component.dart @@ -24,7 +24,7 @@ class MatrixRoomEmoticonComponent extends MatrixEmoticonComponent MatrixRoom room; MatrixRoomEmoticonComponent(MatrixClient client, this.room) - : super(client, MatrixEmoticonRoomStateManager(room.matrixRoom)); + : super(client, MatrixEmoticonRoomStateManager(room.matrixRoom)); @override List get availableEmoji => @@ -51,8 +51,9 @@ class MatrixRoomEmoticonComponent extends MatrixEmoticonComponent List get availablePacks { List packs = List.from(ownedPacks, growable: true); - for (var space in room.client.spaces - .where((element) => element.containsRoom(room.identifier))) { + for (var space in room.client.spaces.where( + (element) => element.containsRoom(room.identifier), + )) { var component = space.getComponent(); if (component == null) continue; packs.addAll(component.ownedPacks); @@ -63,17 +64,21 @@ class MatrixRoomEmoticonComponent extends MatrixEmoticonComponent if (component == null) return packs; packs.addAll( - component.globalPacks().where((element) => !packs.contains(element))); + component.globalPacks().where((element) => !packs.contains(element)), + ); packs.addAll( - component.ownedPacks.where((element) => !packs.contains(element))); + component.ownedPacks.where((element) => !packs.contains(element)), + ); return packs; } @override Future sendSticker( - Emoticon sticker, TimelineEvent? inReplyTo) async { + Emoticon sticker, + TimelineEvent? inReplyTo, + ) async { if (sticker is! MatrixEmoticon) return null; var image = await ImageUtils.imageProviderToImage(sticker.image); @@ -90,8 +95,10 @@ class MatrixRoomEmoticonComponent extends MatrixEmoticonComponent // Sometimes MatrixMxcImage doesnt have mimetype loaded, so we need to look it up manually if (mimeType == null) { - var provider = - MxcFileProvider(client.getMatrixClient(), sticker.emojiUrl); + var provider = MxcFileProvider( + client.getMatrixClient(), + sticker.emojiUrl, + ); var data = await provider.getFileData(); mimeType = Mime.lookupType("", data: data); } @@ -112,20 +119,24 @@ class MatrixRoomEmoticonComponent extends MatrixEmoticonComponent "info": { "w": image.width, "h": image.height, - if (mimeType != null) "mimetype": mimeType - } + if (mimeType != null) "mimetype": mimeType, + }, }; - var id = await room.matrixRoom.sendEvent(content, - type: preferences.stickerCompatibilityMode.value - ? matrix.EventTypes.Message - : matrix.EventTypes.Sticker, - inReplyTo: replyingTo); + var id = await room.matrixRoom.sendEvent( + content, + type: preferences.stickerCompatibilityMode.value + ? matrix.EventTypes.Message + : matrix.EventTypes.Sticker, + inReplyTo: replyingTo, + ); if (id != null) { var event = await room.matrixRoom.getEventById(id); - return room.convertEvent(event!, - timeline: (room.timeline as MatrixTimeline?)?.matrixTimeline); + return room.convertEvent( + event!, + timeline: (room.timeline as MatrixTimeline?)?.matrixTimeline, + ); } return null; @@ -134,8 +145,9 @@ class MatrixRoomEmoticonComponent extends MatrixEmoticonComponent List _getAvailablePacks({bool includeUnicode = false}) { var result = List.of(ownedPacks); - for (var space in room.client.spaces - .where((element) => element.containsRoom(room.identifier))) { + for (var space in room.client.spaces.where( + (element) => element.containsRoom(room.identifier), + )) { var component = space.getComponent(); if (component != null) { result.addAll(component.ownedPacks.where((e) => !result.contains(e))); @@ -152,8 +164,9 @@ class MatrixRoomEmoticonComponent extends MatrixEmoticonComponent } if (globalComponent != null) { - result - .addAll(globalComponent.ownedPacks.where((e) => !result.contains(e))); + result.addAll( + globalComponent.ownedPacks.where((e) => !result.contains(e)), + ); } if (includeUnicode) result.addAll(UnicodeEmojis.packs!); @@ -163,21 +176,28 @@ class MatrixRoomEmoticonComponent extends MatrixEmoticonComponent @override bool isGloballyAvailable(String packId) { - return room.matrixRoom.client - .isEmoticonPackGloballyAvailable(room.matrixRoom.id, packId); + return room.matrixRoom.client.isEmoticonPackGloballyAvailable( + room.matrixRoom.id, + packId, + ); } Future markAsGlobal(bool isGlobal, String packKey) async { if (isGlobal) - return room.matrixRoom.client - .addEmoticonRoomPack(room.matrixRoom.id, packKey); - - return room.matrixRoom.client - .removeEmoticonRoomPack(room.matrixRoom.id, packKey); + return room.matrixRoom.client.addEmoticonRoomPack( + room.matrixRoom.id, + packKey, + ); + + return room.matrixRoom.client.removeEmoticonRoomPack( + room.matrixRoom.id, + packKey, + ); } Map> getEmotePacksFlat( - matrix.ImagePackUsage emoticon) { + matrix.ImagePackUsage emoticon, + ) { var packs = availablePacks; var result = >{}; @@ -186,8 +206,8 @@ class MatrixRoomEmoticonComponent extends MatrixEmoticonComponent var key = "${pack.displayName}-${pack.hashCode}"; result[key] = {}; for (var emote in pack.emotes) { - result[key]![emote.shortcode!] = - (emote as MatrixEmoticon).emojiUrl.toString(); + result[key]![emote.shortcode!] = (emote as MatrixEmoticon).emojiUrl + .toString(); } } diff --git a/commet/lib/client/matrix/components/emoticon/matrix_space_emoticon_component.dart b/commet/lib/client/matrix/components/emoticon/matrix_space_emoticon_component.dart index acbbc63b8..e8dc7658d 100644 --- a/commet/lib/client/matrix/components/emoticon/matrix_space_emoticon_component.dart +++ b/commet/lib/client/matrix/components/emoticon/matrix_space_emoticon_component.dart @@ -19,14 +19,14 @@ class MatrixSpaceEmoticonComponent extends MatrixEmoticonComponent @override String get ownerDisplayName => space.displayName; - MatrixSpaceEmoticonComponent( - MatrixClient client, - this.space, - ) : super(client, MatrixEmoticonRoomStateManager(space.matrixRoom)); + MatrixSpaceEmoticonComponent(MatrixClient client, this.space) + : super(client, MatrixEmoticonRoomStateManager(space.matrixRoom)); @override bool isGloballyAvailable(String packId) { - return space.matrixRoom.client - .isEmoticonPackGloballyAvailable(space.matrixRoom.id, packId); + return space.matrixRoom.client.isEmoticonPackGloballyAvailable( + space.matrixRoom.id, + packId, + ); } } diff --git a/commet/lib/client/matrix/components/emoticon_recent/matrix_recent_emoticon_component.dart b/commet/lib/client/matrix/components/emoticon_recent/matrix_recent_emoticon_component.dart index 41878c196..9cbd33790 100644 --- a/commet/lib/client/matrix/components/emoticon_recent/matrix_recent_emoticon_component.dart +++ b/commet/lib/client/matrix/components/emoticon_recent/matrix_recent_emoticon_component.dart @@ -59,7 +59,8 @@ class MatrixRecentEmoticonComponent var comp = room?.getComponent(); - var availablePacks = comp?.availablePacks ?? + var availablePacks = + comp?.availablePacks ?? client.getComponent()?.availablePacks; if (availablePacks == null) return []; @@ -93,10 +94,10 @@ class MatrixRecentEmoticonComponent .characters .map((i) => UnicodeEmoticon(i.toString())) .forEach((i) { - if (result.contains(i) == false) { - result.add(i); - } - }); + if (result.contains(i) == false) { + result.add(i); + } + }); return result; } @@ -136,9 +137,10 @@ class MatrixRecentEmoticonComponent } return RecentEmoji( - key: key, - customPackId: customPackid, - customPackRoomId: customPackRoomId); + key: key, + customPackId: customPackid, + customPackRoomId: customPackRoomId, + ); } @override @@ -166,10 +168,12 @@ class MatrixRecentEmoticonComponent list = list.sublist(0, maxLen); } - var existing = list.firstWhereOrNull((i) => - i.customPackId == emoji.customPackId && - i.customPackRoomId == emoji.customPackRoomId && - i.key == emoji.key); + var existing = list.firstWhereOrNull( + (i) => + i.customPackId == emoji.customPackId && + i.customPackRoomId == emoji.customPackRoomId && + i.key == emoji.key, + ); if (existing != null) { existing.count++; @@ -182,17 +186,23 @@ class MatrixRecentEmoticonComponent Future storeRecentReactions() async { var content = { - "recent_emoji": _reactionEmoji.map((i) => i.toJson()).toList() + "recent_emoji": _reactionEmoji.map((i) => i.toJson()).toList(), }; - client.matrixClient - .setAccountData(client.matrixClient.userID!, reactionsKey, content); + client.matrixClient.setAccountData( + client.matrixClient.userID!, + reactionsKey, + content, + ); } Future storeRecentlyTyped() async { var content = {"recent_emoji": _typedEmoji.map((i) => i.toJson()).toList()}; - await client.matrixClient - .setAccountData(client.matrixClient.userID!, typedKey, content); + await client.matrixClient.setAccountData( + client.matrixClient.userID!, + typedKey, + content, + ); } List toRecentsList(BasicEvent data) { @@ -218,11 +228,12 @@ class MatrixRecentEmoticonComponent } class RecentEmoji { - RecentEmoji( - {required this.key, - this.customPackId, - this.customPackRoomId, - this.count = 1}); + RecentEmoji({ + required this.key, + this.customPackId, + this.customPackRoomId, + this.count = 1, + }); String key; String? customPackId; @@ -245,10 +256,11 @@ class RecentEmoji { var count = data["count"] as int? ?? 1; if (key == null) return null; return RecentEmoji( - key: data["key"], - customPackId: packId, - customPackRoomId: customPackRoomId, - count: count); + key: data["key"], + customPackId: packId, + customPackRoomId: customPackRoomId, + count: count, + ); } @override diff --git a/commet/lib/client/matrix/components/event_search/matrix_event_search_component.dart b/commet/lib/client/matrix/components/event_search/matrix_event_search_component.dart index 04b725a01..d6d357c54 100644 --- a/commet/lib/client/matrix/components/event_search/matrix_event_search_component.dart +++ b/commet/lib/client/matrix/components/event_search/matrix_event_search_component.dart @@ -24,8 +24,10 @@ class MatrixEncryptedRoomEventSearchSession extends EventSearchSession { List> results = List.empty(growable: true); @override - Stream>> startSearch(String searchTerm, - {String? nextBatch}) async* { + Stream>> startSearch( + String searchTerm, { + String? nextBatch, + }) async* { currentSearchTerm = searchTerm.toLowerCase(); if (nextBatch == null) { @@ -37,9 +39,10 @@ class MatrixEncryptedRoomEventSearchSession extends EventSearchSession { var params = MatrixSearchParameters.parse(searchTerm); var search = timeline.matrixTimeline!.startSearch( - searchTerm: searchTerm, - searchFunc: (ev) => searchFunc(params, ev), - prevBatch: nextBatch); + searchTerm: searchTerm, + searchFunc: (ev) => searchFunc(params, ev), + prevBatch: nextBatch, + ); await for (final chunk in search) { var result = chunk.$1 @@ -63,7 +66,8 @@ class MatrixEncryptedRoomEventSearchSession extends EventSearchSession { result.sort((a, b) => b.originServerTs.compareTo(a.originServerTs)); results.addAll( - result.where((i) => !results.any((e) => i.eventId == e.eventId))); + result.where((i) => !results.any((e) => i.eventId == e.eventId)), + ); yield results; } @@ -208,8 +212,9 @@ class MatrixServerEventSearchSession extends EventSearchSession { MatrixServerEventSearchSession(this.timeline); - NotifyingList> events = - NotifyingList.empty(growable: true); + NotifyingList> events = NotifyingList.empty( + growable: true, + ); @override bool currentlySearching = false; @@ -227,8 +232,10 @@ class MatrixServerEventSearchSession extends EventSearchSession { } @override - Stream>> startSearch(String searchTerm, - {String? nextBatch}) { + Stream>> startSearch( + String searchTerm, { + String? nextBatch, + }) { currentSearchTerm = searchTerm; var client = (timeline.client as MatrixClient).matrixClient; @@ -244,12 +251,13 @@ class MatrixServerEventSearchSession extends EventSearchSession { searchTerm: parameters.words.join(" "), orderBy: matrix.SearchOrder.recent, filter: matrix.SearchFilter( - rooms: [timeline.room.identifier], - limit: 20, - senders: parameters.requiredSender != null - ? [parameters.requiredSender!] - : null, - containsUrl: parameters.requireUrl == true ? true : null), + rooms: [timeline.room.identifier], + limit: 20, + senders: parameters.requiredSender != null + ? [parameters.requiredSender!] + : null, + containsUrl: parameters.requireUrl == true ? true : null, + ), includeState: false, ); @@ -258,30 +266,40 @@ class MatrixServerEventSearchSession extends EventSearchSession { client .search(matrix.Categories(roomEvents: criteria), nextBatch: nextBatch) .then((result) { - currentlySearching = false; - - var resultEvents = result.searchCategories.roomEvents?.results; - nextBatchToken = result.searchCategories.roomEvents?.nextBatch; - - events.clear(); - - if (resultEvents != null) { - events.addAll(resultEvents - .where((i) => i.result != null) - .sorted((a, b) => - b.result!.originServerTs.compareTo(a.result!.originServerTs)) - .map((i) => (timeline.room as MatrixRoom).convertEvent(matrix.Event( - content: i.result!.content, - type: i.result!.type, - eventId: i.result!.eventId, - senderId: i.result!.senderId, - originServerTs: i.result!.originServerTs, - room: timeline.matrixTimeline!.room)))); - } - - events.update(); - Log.i("Got events: ${resultEvents}"); - }); + currentlySearching = false; + + var resultEvents = result.searchCategories.roomEvents?.results; + nextBatchToken = result.searchCategories.roomEvents?.nextBatch; + + events.clear(); + + if (resultEvents != null) { + events.addAll( + resultEvents + .where((i) => i.result != null) + .sorted( + (a, b) => b.result!.originServerTs.compareTo( + a.result!.originServerTs, + ), + ) + .map( + (i) => (timeline.room as MatrixRoom).convertEvent( + matrix.Event( + content: i.result!.content, + type: i.result!.type, + eventId: i.result!.eventId, + senderId: i.result!.senderId, + originServerTs: i.result!.originServerTs, + room: timeline.matrixTimeline!.room, + ), + ), + ), + ); + } + + events.update(); + Log.i("Got events: ${resultEvents}"); + }); return events.onListUpdated.map((i) => events); } @@ -312,7 +330,7 @@ class MatrixEventSearchComponent implements EventSearchComponent { MatrixSearchParameters.hasFileString, MatrixSearchParameters.hasImageString, MatrixSearchParameters.hasVideoString, - "from:@user:example.com" + "from:@user:example.com", ]; } else { return ["from:@user:example.com"]; diff --git a/commet/lib/client/matrix/components/gif/matrix_gif_component.dart b/commet/lib/client/matrix/components/gif/matrix_gif_component.dart index cf44ec30e..2a325d266 100644 --- a/commet/lib/client/matrix/components/gif/matrix_gif_component.dart +++ b/commet/lib/client/matrix/components/gif/matrix_gif_component.dart @@ -33,8 +33,12 @@ class MatrixFavoriteGif implements FavoriteGif { @override ImageProvider get image { var url = data.tryGet("url"); - return MatrixMxcImage(Uri.parse(url!), client.matrixClient, - doThumbnail: false, doFullres: true); + return MatrixMxcImage( + Uri.parse(url!), + client.matrixClient, + doThumbnail: false, + doFullres: true, + ); } @override @@ -69,7 +73,10 @@ class MatrixGifComponent implements GifComponent { if (!preferences.tenorGifSearchEnabled.value) return []; var uri = Uri.https( - preferences.proxyUrl.value, "/proxy/klipy/api/v2/search", {"q": query}); + preferences.proxyUrl.value, + "/proxy/klipy/api/v2/search", + {"q": query}, + ); // var uri = // Uri.http("localhost:8788", "/proxy/klipy/api/v2/search", {"q": query}); @@ -92,15 +99,21 @@ class MatrixGifComponent implements GifComponent { @override Future sendGif( - Room room, GifSearchResult gif, TimelineEvent? inReplyTo) async { + Room room, + GifSearchResult gif, + TimelineEvent? inReplyTo, + ) async { var matrixRoom = (room as MatrixRoom).matrixRoom; var response = await matrixRoom.client.httpClient.get(gif.fullResUrl); if (response.statusCode == 200) { var data = response.bodyBytes; matrix.Event? replyingTo; - var uri = await matrixRoom.client - .uploadContent(data, filename: "sticker", contentType: gif.mimeType); + var uri = await matrixRoom.client.uploadContent( + data, + filename: "sticker", + contentType: gif.mimeType, + ); var content = { "body": gif.fullResUrl.pathSegments.last, @@ -112,24 +125,28 @@ class MatrixGifComponent implements GifComponent { "chat.commet.animated": true, "w": gif.x.toInt(), "h": gif.y.toInt(), - "mimetype": gif.mimeType - } + "mimetype": gif.mimeType, + }, }; if (inReplyTo != null) { replyingTo = await matrixRoom.getEventById(inReplyTo.eventId); } - var id = await matrixRoom.sendEvent(content, - type: preferences.stickerCompatibilityMode.value - ? matrix.EventTypes.Message - : matrix.EventTypes.Sticker, - inReplyTo: replyingTo); + var id = await matrixRoom.sendEvent( + content, + type: preferences.stickerCompatibilityMode.value + ? matrix.EventTypes.Message + : matrix.EventTypes.Sticker, + inReplyTo: replyingTo, + ); if (id != null) { var event = await matrixRoom.getEventById(id); - return room.convertEvent(event!, - timeline: (room.timeline as MatrixTimeline).matrixTimeline); + return room.convertEvent( + event!, + timeline: (room.timeline as MatrixTimeline).matrixTimeline, + ); } } @@ -165,18 +182,21 @@ class MatrixGifComponent implements GifComponent { List dimensions = fullRes['dims']! as List; return GifSearchResult( - convertUrl(preview['url']), - convertUrl(fullRes['url']), - (dimensions[0] as int).roundToDouble(), - (dimensions[1] as int).roundToDouble(), - mimeType); + convertUrl(preview['url']), + convertUrl(fullRes['url']), + (dimensions[0] as int).roundToDouble(), + (dimensions[1] as int).roundToDouble(), + mimeType, + ); } Uri convertUrl(String url) { var uri = Uri.parse(url); - var proxyUri = - Uri.https(preferences.proxyUrl.value, "/proxy/klipy/media${uri.path}"); + var proxyUri = Uri.https( + preferences.proxyUrl.value, + "/proxy/klipy/media${uri.path}", + ); // proxyUri = Uri.http("localhost:8788", "/proxy/klipy/media${uri.path}"); @@ -187,7 +207,8 @@ class MatrixGifComponent implements GifComponent { bool isGif(TimelineEvent ev) { final event = (ev as MatrixTimelineEvent).event; - bool isSticker = event.type == "m.sticker" || + bool isSticker = + event.type == "m.sticker" || (event.type == "m.room.message" && event.content["chat.commet.type"] == "chat.commet.sticker"); @@ -195,7 +216,8 @@ class MatrixGifComponent implements GifComponent { var info = event.content.tryGetMap("info"); - bool isAnimated = event.attachmentMimetype == "image/gif" || + bool isAnimated = + event.attachmentMimetype == "image/gif" || info?["chat.commet.animated"] == true; bool isGif = isSticker && isGifMimeType && isAnimated; @@ -210,7 +232,8 @@ class MatrixGifComponent implements GifComponent { var body = event.content.tryGet("body"); var url = event.content.tryGet("url"); - var favorites = client.matrixClient.accountData[favoritesKey]?.content + var favorites = + client.matrixClient.accountData[favoritesKey]?.content .tryGetList>("favorites") ?? List>.empty(); @@ -219,21 +242,21 @@ class MatrixGifComponent implements GifComponent { } final newFavorites = List.from(favorites, growable: true); - newFavorites.add({ - "info": info, - "body": body, - "url": url, - }); + newFavorites.add({"info": info, "body": body, "url": url}); print(newFavorites); await client.matrixClient.setAccountData( - client.matrixClient.userID!, favoritesKey, {"favorites": newFavorites}); + client.matrixClient.userID!, + favoritesKey, + {"favorites": newFavorites}, + ); } @override bool isFavoriteGif(TimelineEvent ev) { - var favorites = client.matrixClient.accountData[favoritesKey]?.content + var favorites = + client.matrixClient.accountData[favoritesKey]?.content .tryGetList>("favorites") ?? List>.empty(); @@ -258,7 +281,10 @@ class MatrixGifComponent implements GifComponent { @override Future?> sendFavoriteGif( - Room room, FavoriteGif gif, TimelineEvent? inReplyTo) async { + Room room, + FavoriteGif gif, + TimelineEvent? inReplyTo, + ) async { var fav = gif as MatrixFavoriteGif; matrix.Event? replyingTo; var matrixRoom = (room as MatrixRoom).matrixRoom; @@ -269,23 +295,27 @@ class MatrixGifComponent implements GifComponent { if (preferences.stickerCompatibilityMode.value) "msgtype": "m.image", if (preferences.stickerCompatibilityMode.value) "chat.commet.type": "chat.commet.sticker", - "info": fav.data["info"] + "info": fav.data["info"], }; if (inReplyTo != null) { replyingTo = await matrixRoom.getEventById(inReplyTo.eventId); } - var id = await matrixRoom.sendEvent(content, - type: preferences.stickerCompatibilityMode.value - ? matrix.EventTypes.Message - : matrix.EventTypes.Sticker, - inReplyTo: replyingTo); + var id = await matrixRoom.sendEvent( + content, + type: preferences.stickerCompatibilityMode.value + ? matrix.EventTypes.Message + : matrix.EventTypes.Sticker, + inReplyTo: replyingTo, + ); if (id != null) { var event = await matrixRoom.getEventById(id); - return room.convertEvent(event!, - timeline: (room.timeline as MatrixTimeline).matrixTimeline); + return room.convertEvent( + event!, + timeline: (room.timeline as MatrixTimeline).matrixTimeline, + ); } return null; @@ -296,17 +326,23 @@ class MatrixGifComponent implements GifComponent { final event = (ev as MatrixTimelineEvent).event; var url = event.content.tryGet("url"); - var favorites = client.matrixClient.accountData[favoritesKey]?.content + var favorites = + client.matrixClient.accountData[favoritesKey]?.content .tryGetList>("favorites") ?? List>.empty(); - var newFavorites = - List>.from(favorites, growable: true); + var newFavorites = List>.from( + favorites, + growable: true, + ); newFavorites.removeWhere((i) => i["url"] == url); await client.matrixClient.setAccountData( - client.matrixClient.userID!, favoritesKey, {"favorites": newFavorites}); + client.matrixClient.userID!, + favoritesKey, + {"favorites": newFavorites}, + ); } void _onSync(matrix.SyncUpdate event) { @@ -317,16 +353,22 @@ class MatrixGifComponent implements GifComponent { @override Future removeFavorite(FavoriteGif gif) async { - var favorites = client.matrixClient.accountData[favoritesKey]?.content + var favorites = + client.matrixClient.accountData[favoritesKey]?.content .tryGetList>("favorites") ?? List>.empty(); - var newFavorites = - List>.from(favorites, growable: true); + var newFavorites = List>.from( + favorites, + growable: true, + ); newFavorites.removeWhere((i) => i["url"] == gif.url); await client.matrixClient.setAccountData( - client.matrixClient.userID!, favoritesKey, {"favorites": newFavorites}); + client.matrixClient.userID!, + favoritesKey, + {"favorites": newFavorites}, + ); } } diff --git a/commet/lib/client/matrix/components/invitation/matrix_invitation_component.dart b/commet/lib/client/matrix/components/invitation/matrix_invitation_component.dart index 042033a64..ad1042b87 100644 --- a/commet/lib/client/matrix/components/invitation/matrix_invitation_component.dart +++ b/commet/lib/client/matrix/components/invitation/matrix_invitation_component.dart @@ -56,23 +56,27 @@ class MatrixInvitationComponent var state = room.states[matrix.EventTypes.RoomMember]?[mx.userID]; var sender = state?.senderId; - var avatar = - room.avatar != null ? MatrixMxcImage(room.avatar!, mx) : null; + var avatar = room.avatar != null + ? MatrixMxcImage(room.avatar!, mx) + : null; var entry = Invitation( - roomId: room.id, - avatar: avatar, - senderId: sender, - color: MatrixPeer.hashColor(room.id), - displayName: room.getLocalizedDisplayname()); + roomId: room.id, + avatar: avatar, + senderId: sender, + color: MatrixPeer.hashColor(room.id), + displayName: room.getLocalizedDisplayname(), + ); invitations.add(entry); } } @override - Future inviteUserToRoom( - {required String userId, required String roomId}) { + Future inviteUserToRoom({ + required String userId, + required String roomId, + }) { var mx = client.getMatrixClient(); return mx.inviteUser(roomId, userId); } @@ -82,13 +86,16 @@ class MatrixInvitationComponent var mx = client.getMatrixClient(); var result = await mx.searchUserDirectory(term); - var finalResult = - result.results.map((e) => MatrixProfile(client, e)).toList(); + var finalResult = result.results + .map((e) => MatrixProfile(client, e)) + .toList(); if (term.isValidMatrixId && !finalResult.any((i) => i.identifier == term)) { finalResult = [ MatrixProfile( - client, matrix.Profile(userId: term, displayName: term.localpart)), - ...finalResult + client, + matrix.Profile(userId: term, displayName: term.localpart), + ), + ...finalResult, ]; } @@ -107,15 +114,13 @@ class MatrixInvitationComponent Future setInvitationsAllowed(bool allowed) async { var mx = client.getMatrixClient(); - Map content = allowed - ? {} - : { - "default_action": "block", - }; + Map content = allowed ? {} : {"default_action": "block"}; await mx.setAccountData(mx.userID!, "m.invite_permission_config", content); - mx.accountData["m.invite_permission_config"] = - matrix.BasicEvent(type: "m.invite_permission_config", content: content); + mx.accountData["m.invite_permission_config"] = matrix.BasicEvent( + type: "m.invite_permission_config", + content: content, + ); } } diff --git a/commet/lib/client/matrix/components/message_effects/matrix_message_effects_component.dart b/commet/lib/client/matrix/components/message_effects/matrix_message_effects_component.dart index 61db7437a..02dfc8cd9 100644 --- a/commet/lib/client/matrix/components/message_effects/matrix_message_effects_component.dart +++ b/commet/lib/client/matrix/components/message_effects/matrix_message_effects_component.dart @@ -31,19 +31,25 @@ class MatrixMessageEffectsComponent var mx = client.getMatrixClient(); mx.addCommand( - "snowfall", - (args, _) => - sendWithMsgType(args, msgType: effectTypeSnowfall, fallback: "❄️")); + "snowfall", + (args, _) => + sendWithMsgType(args, msgType: effectTypeSnowfall, fallback: "❄️"), + ); mx.addCommand( - "confetti", - (args, _) => - sendWithMsgType(args, msgType: effectTypeConfetti, fallback: "🎉")); + "confetti", + (args, _) => + sendWithMsgType(args, msgType: effectTypeConfetti, fallback: "🎉"), + ); mx.addCommand( - "spaceinvaders", - (args, _) => sendWithMsgType(args, - msgType: effectTypeSpaceInvaders, fallback: "👾")); + "spaceinvaders", + (args, _) => sendWithMsgType( + args, + msgType: effectTypeSpaceInvaders, + fallback: "👾", + ), + ); } static const Set knownEffectTypes = { @@ -107,8 +113,11 @@ class MatrixMessageEffectsComponent return null; } - FutureOr sendWithMsgType(matrix.CommandArgs args, - {required String msgType, required String fallback}) async { + FutureOr sendWithMsgType( + matrix.CommandArgs args, { + required String msgType, + required String fallback, + }) async { args.room?.sendEvent({ "msgtype": msgType, "body": args.msg.trim().isEmpty ? fallback : args.msg, diff --git a/commet/lib/client/matrix/components/photo_album_room/matrix_photo.dart b/commet/lib/client/matrix/components/photo_album_room/matrix_photo.dart index e9c8b6dec..05f691b9e 100644 --- a/commet/lib/client/matrix/components/photo_album_room/matrix_photo.dart +++ b/commet/lib/client/matrix/components/photo_album_room/matrix_photo.dart @@ -11,9 +11,7 @@ class MatrixPhoto implements Photo { Attachment? get attachment => (event as MatrixTimelineEventMessage).attachments?.firstOrNull; - MatrixPhoto( - this.event, - ); + MatrixPhoto(this.event); @override double? get height => diff --git a/commet/lib/client/matrix/components/photo_album_room/matrix_photo_album_timeline.dart b/commet/lib/client/matrix/components/photo_album_room/matrix_photo_album_timeline.dart index 1ee11e104..f2a0612e2 100644 --- a/commet/lib/client/matrix/components/photo_album_room/matrix_photo_album_timeline.dart +++ b/commet/lib/client/matrix/components/photo_album_room/matrix_photo_album_timeline.dart @@ -118,7 +118,8 @@ class MatrixPhotoAlbumTimeline implements PhotoAlbumTimeline { void onEventRemoved(int index) { var event = matrixTimeline.events[index]; - _photos - .removeWhere((e) => (e as MatrixPhoto).event.eventId == event.eventId); + _photos.removeWhere( + (e) => (e as MatrixPhoto).event.eventId == event.eventId, + ); } } diff --git a/commet/lib/client/matrix/components/photo_album_room/matrix_upload_photos_task.dart b/commet/lib/client/matrix/components/photo_album_room/matrix_upload_photos_task.dart index eb1267f95..56e2557f0 100644 --- a/commet/lib/client/matrix/components/photo_album_room/matrix_upload_photos_task.dart +++ b/commet/lib/client/matrix/components/photo_album_room/matrix_upload_photos_task.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:commet/client/attachment.dart'; import 'package:commet/client/components/photo_album_room/photo_album_room_component.dart'; import 'package:commet/client/matrix/matrix_room.dart'; @@ -21,8 +22,12 @@ class MatrixUploadPhotosTask implements BackgroundTaskWithIntegerProgress { StreamController progressStream = StreamController.broadcast(); StreamController controller = StreamController.broadcast(); - MatrixUploadPhotosTask(this.files, this.room, - {this.extractMetadata = true, this.sendOriginal = false}) { + MatrixUploadPhotosTask( + this.files, + this.room, { + this.extractMetadata = true, + this.sendOriginal = false, + }) { total = files.length; } @@ -109,10 +114,13 @@ class MatrixUploadPhotosTask implements BackgroundTaskWithIntegerProgress { } var processed = await room.processAttachment( - PendingFileAttachment(name: name, data: imageData)); + PendingFileAttachment(name: name, data: imageData), + ); await room.sendMessage( - processedAttachments: [processed!], fileExtraContent: extraInfo); + processedAttachments: [processed!], + fileExtraContent: extraInfo, + ); current += 1; progressStream.add(current); } diff --git a/commet/lib/client/matrix/components/polls/matrix_poll_component.dart b/commet/lib/client/matrix/components/polls/matrix_poll_component.dart index b72e5d3ed..54cf741a3 100644 --- a/commet/lib/client/matrix/components/polls/matrix_poll_component.dart +++ b/commet/lib/client/matrix/components/polls/matrix_poll_component.dart @@ -38,9 +38,7 @@ class MatrixPollComponent implements PollComponent { @override List getAllowedPollAnswers(TimelineEvent event) { - return _parse(event) - .pollStartContent - .answers + return _parse(event).pollStartContent.answers .map((i) => PollAnswer(i.id, i.mText)) .toList(); } @@ -52,13 +50,16 @@ class MatrixPollComponent implements PollComponent { @override Map> getPollResponses( - Timeline timeline, TimelineEvent event) { + Timeline timeline, + TimelineEvent event, + ) { Map> responses = {}; var mxEvent = (event as MatrixTimelineEvent).event; - var mxResponses = - mxEvent.getPollResponses((timeline as MatrixTimeline).matrixTimeline!); + var mxResponses = mxEvent.getPollResponses( + (timeline as MatrixTimeline).matrixTimeline!, + ); for (var userId in mxResponses.keys) { for (var answer in mxResponses[userId]!) { @@ -79,7 +80,10 @@ class MatrixPollComponent implements PollComponent { @override Future setAnswer( - TimelineEvent event, Room room, List answers) async { + TimelineEvent event, + Room room, + List answers, + ) async { var mxEvent = (event as MatrixTimelineEvent).event; await mxEvent.answerPoll(answers.map((i) => i.id).toList()); } @@ -92,30 +96,37 @@ class MatrixPollComponent implements PollComponent { return true; } - return mxEvent - .getPollHasBeenEnded((timeline as MatrixTimeline).matrixTimeline!); + return mxEvent.getPollHasBeenEnded( + (timeline as MatrixTimeline).matrixTimeline!, + ); } @override bool isFinished(TimelineEvent event, Timeline timeline) { var mxEvent = (event as MatrixTimelineEvent).event; - return mxEvent - .getPollHasBeenEnded((timeline as MatrixTimeline).matrixTimeline!); + return mxEvent.getPollHasBeenEnded( + (timeline as MatrixTimeline).matrixTimeline!, + ); } @override Future createPoll(Room room, PollCreateArgs args) async { await (room as MatrixRoom).matrixRoom.startPoll( - question: args.question, - answers: args.options - .map((i) => matrix.PollAnswer( - id: RandomUtils.getRandomString(10), mText: i)) - .toList(), - kind: args.publicAnswers - ? matrix.PollKind.disclosed - : matrix.PollKind.undisclosed, - maxSelections: args.multiAnswer ? args.options.length : 1); + question: args.question, + answers: args.options + .map( + (i) => matrix.PollAnswer( + id: RandomUtils.getRandomString(10), + mText: i, + ), + ) + .toList(), + kind: args.publicAnswers + ? matrix.PollKind.disclosed + : matrix.PollKind.undisclosed, + maxSelections: args.multiAnswer ? args.options.length : 1, + ); } @override diff --git a/commet/lib/client/matrix/components/profile/matrix_profile_component.dart b/commet/lib/client/matrix/components/profile/matrix_profile_component.dart index f0c0b805e..8f738c737 100644 --- a/commet/lib/client/matrix/components/profile/matrix_profile_component.dart +++ b/commet/lib/client/matrix/components/profile/matrix_profile_component.dart @@ -110,13 +110,12 @@ class MatrixProfile @override Brightness? get brightness => fields.containsKey(MatrixProfileComponent.colorSchemeKey) == false - ? null - : switch (fields[MatrixProfileComponent.colorSchemeKey] - ["brightness"]) { - "light" => Brightness.light, - "dark" => Brightness.dark, - _ => null, - }; + ? null + : switch (fields[MatrixProfileComponent.colorSchemeKey]["brightness"]) { + "light" => Brightness.light, + "dark" => Brightness.dark, + _ => null, + }; @override Color? get color { diff --git a/commet/lib/client/matrix/components/push_notifications/matrix_push_notification_component.dart b/commet/lib/client/matrix/components/push_notifications/matrix_push_notification_component.dart index 37559fdb5..b762c2a20 100644 --- a/commet/lib/client/matrix/components/push_notifications/matrix_push_notification_component.dart +++ b/commet/lib/client/matrix/components/push_notifications/matrix_push_notification_component.dart @@ -15,8 +15,11 @@ class MatrixPushNotificationComponent @override Future ensurePushNotificationsRegistered( - String pushKey, Uri pushServer, String deviceName, - {Map? extraData}) async { + String pushKey, + Uri pushServer, + String deviceName, { + Map? extraData, + }) async { var matrixClient = client.getMatrixClient(); Log.i("Current push key: $pushKey"); @@ -30,26 +33,32 @@ class MatrixPushNotificationComponent ); if (pushers != null && - pushers.any((element) => - element.pushkey == pushKey && - element.data.toJson() == data.toJson())) { + pushers.any( + (element) => + element.pushkey == pushKey && + element.data.toJson() == data.toJson(), + )) { return; } var pusher = Pusher( - appId: "chat.commet.commetapp.android", - pushkey: pushKey, - appDisplayName: BuildConfig.appName, - data: data, - deviceDisplayName: deviceName, - kind: "http", - lang: "en"); + appId: "chat.commet.commetapp.android", + pushkey: pushKey, + appDisplayName: BuildConfig.appName, + data: data, + deviceDisplayName: deviceName, + kind: "http", + lang: "en", + ); await matrixClient.postPusher(pusher, append: true); } Future cleanOldPushers( - String? currentPushKey, String deviceName, Uri pushGateway) async { + String? currentPushKey, + String deviceName, + Uri pushGateway, + ) async { var matrixClient = client.getMatrixClient(); var pushers = await matrixClient.getPushers(); @@ -87,10 +96,11 @@ class MatrixPushNotificationComponent } uri = Uri( - scheme: uri.scheme, - host: uri.host, - port: uri.port, - path: "/_matrix/push/v1/notify"); + scheme: uri.scheme, + host: uri.host, + port: uri.port, + path: "/_matrix/push/v1/notify", + ); await cleanOldPushers(key, name, uri); @@ -98,8 +108,12 @@ class MatrixPushNotificationComponent return; } - await ensurePushNotificationsRegistered(key, uri, name, - extraData: extraData); + await ensurePushNotificationsRegistered( + key, + uri, + name, + extraData: extraData, + ); } @override diff --git a/commet/lib/client/matrix/components/read_receipts/matrix_read_receipt_component.dart b/commet/lib/client/matrix/components/read_receipts/matrix_read_receipt_component.dart index 10361eaf5..69035022f 100644 --- a/commet/lib/client/matrix/components/read_receipts/matrix_read_receipt_component.dart +++ b/commet/lib/client/matrix/components/read_receipts/matrix_read_receipt_component.dart @@ -37,7 +37,9 @@ class MatrixReadReceiptComponent @override bool? get usePublicReadReceiptsForRoom { var publicReadReceiptsForRoom = room - .matrixRoom.roomAccountData[publicReadReceiptsKey]?.content["enabled"]; + .matrixRoom + .roomAccountData[publicReadReceiptsKey] + ?.content["enabled"]; return publicReadReceiptsForRoom is bool ? publicReadReceiptsForRoom : null; } diff --git a/commet/lib/client/matrix/components/room_activities/matrix_activities_component.dart b/commet/lib/client/matrix/components/room_activities/matrix_activities_component.dart index 53efb6c9f..0e85d2417 100644 --- a/commet/lib/client/matrix/components/room_activities/matrix_activities_component.dart +++ b/commet/lib/client/matrix/components/room_activities/matrix_activities_component.dart @@ -42,8 +42,9 @@ class MatrixActivitiesComponent var application = entry.value.content.tryGet("application"); if (application == null) continue; - var activity = - activities.firstWhereOrNull((i) => i.application == application); + var activity = activities.firstWhereOrNull( + (i) => i.application == application, + ); var expires = entry.value.content.tryGet("expires"); @@ -77,12 +78,13 @@ class MatrixActivitiesComponent } activity = RoomActivitySession( - participants: Set(), - application: application, - appName: name, - icon: icon, - associatedWidget: widget, - thirdparty: thirdparty); + participants: Set(), + application: application, + appName: name, + icon: icon, + associatedWidget: widget, + thirdparty: thirdparty, + ); activities.add(activity); } @@ -128,7 +130,11 @@ class MatrixActivitiesComponent if (entry.value.content.isEmpty) continue; await room.matrixRoom.client.setRoomStateWithKey( - room.identifier, callMemberStateEvent, entry.value.stateKey!, {}); + room.identifier, + callMemberStateEvent, + entry.value.stateKey!, + {}, + ); } } } diff --git a/commet/lib/client/matrix/components/rtc_data_channel/matrix_rtc_data_channel_component.dart b/commet/lib/client/matrix/components/rtc_data_channel/matrix_rtc_data_channel_component.dart index ca9690f72..7681de3a1 100644 --- a/commet/lib/client/matrix/components/rtc_data_channel/matrix_rtc_data_channel_component.dart +++ b/commet/lib/client/matrix/components/rtc_data_channel/matrix_rtc_data_channel_component.dart @@ -22,14 +22,18 @@ class MatrixRTCDataChannelComponent StreamController.broadcast(); @override - Future createDataChannel(VoipSession session, - {required String purpose}) async { + Future createDataChannel( + VoipSession session, { + required String purpose, + }) async { var uuid = const Uuid(); var label = uuid.v4(); var sesh = session as MatrixVoipSession; - var channel = await sesh.session.pc - ?.createDataChannel(label, RTCDataChannelInit()..id = 1337); + var channel = await sesh.session.pc?.createDataChannel( + label, + RTCDataChannelInit()..id = 1337, + ); sesh.session.addLocalStream(RTCDataMediaStream(channel!), purpose); @@ -37,7 +41,9 @@ class MatrixRTCDataChannelComponent } void dataChannelOpenedCallback( - MatrixVoipSession session, RTCDataChannel channel) { + MatrixVoipSession session, + RTCDataChannel channel, + ) { var newChannel = MatrixRtcDataChannel(session, channel); if (newChannel.purpose == diff --git a/commet/lib/client/matrix/components/rtc_data_channel/matrix_rtc_data_media_stream.dart b/commet/lib/client/matrix/components/rtc_data_channel/matrix_rtc_data_media_stream.dart index ee3aecc54..5cad1e625 100644 --- a/commet/lib/client/matrix/components/rtc_data_channel/matrix_rtc_data_media_stream.dart +++ b/commet/lib/client/matrix/components/rtc_data_channel/matrix_rtc_data_media_stream.dart @@ -21,8 +21,10 @@ class RTCDataMediaStream implements webrtc.MediaStream { bool? get active => throw UnimplementedError(); @override - Future addTrack(webrtc.MediaStreamTrack track, - {bool addToNative = true}) async {} + Future addTrack( + webrtc.MediaStreamTrack track, { + bool addToNative = true, + }) async {} @override Future clone() async { @@ -58,6 +60,8 @@ class RTCDataMediaStream implements webrtc.MediaStream { } @override - Future removeTrack(webrtc.MediaStreamTrack track, - {bool removeFromNative = true}) async {} + Future removeTrack( + webrtc.MediaStreamTrack track, { + bool removeFromNative = true, + }) async {} } diff --git a/commet/lib/client/matrix/components/rtc_screen_share_annotation/matrix_rtc_screen_share_annotation_component.dart b/commet/lib/client/matrix/components/rtc_screen_share_annotation/matrix_rtc_screen_share_annotation_component.dart index 86d45b70c..35c8560ed 100644 --- a/commet/lib/client/matrix/components/rtc_screen_share_annotation/matrix_rtc_screen_share_annotation_component.dart +++ b/commet/lib/client/matrix/components/rtc_screen_share_annotation/matrix_rtc_screen_share_annotation_component.dart @@ -32,9 +32,11 @@ class MatrixRtcScreenShareAnnotationComponent @override Future createSession( - VoipSession session) async { - var annotationSession = - MatrixRTCScreenShareAnnotationSession(session as MatrixVoipSession); + VoipSession session, + ) async { + var annotationSession = MatrixRTCScreenShareAnnotationSession( + session as MatrixVoipSession, + ); await annotationSession.create(); _sessions[session.sessionId] = annotationSession; @@ -43,7 +45,8 @@ class MatrixRtcScreenShareAnnotationComponent @override Future getOrCreateSession( - VoipSession session) async { + VoipSession session, + ) async { var existing = _sessions[session.sessionId]; if (existing != null) { return existing; @@ -70,11 +73,13 @@ class MatrixRTCScreenShareAnnotationSession MatrixRTCScreenShareAnnotationSession(this.session); Future create() async { - var dataChannelComp = - session.client.getComponent()!; + var dataChannelComp = session.client + .getComponent()!; - channel = await dataChannelComp.createDataChannel(session, - purpose: MatrixRtcScreenShareAnnotationComponent.rtcChannelPurpose); + channel = await dataChannelComp.createDataChannel( + session, + purpose: MatrixRtcScreenShareAnnotationComponent.rtcChannelPurpose, + ); } void listen(DataChannel? remoteChannel) { @@ -84,8 +89,11 @@ class MatrixRTCScreenShareAnnotationSession } @override - void setCursorPosition( - {required String streamId, required double x, required double y}) { + void setCursorPosition({ + required String streamId, + required double x, + required double y, + }) { var now = DateTime.now(); var diff = now.difference(lastSetCursorTime); @@ -95,11 +103,7 @@ class MatrixRTCScreenShareAnnotationSession lastSetCursorTime = now; - var msg = const JsonEncoder().convert({ - "stream": streamId, - "x": x, - "y": y, - }); + var msg = const JsonEncoder().convert({"stream": streamId, "x": x, "y": y}); channel?.sendMessage(msg); } @@ -114,7 +118,9 @@ class MatrixRTCScreenShareAnnotationSession final member = room?.getMemberOrFallback(userId); constellation.createCursor( - userId, session.remoteUserName ?? "Unknown User"); + userId, + session.remoteUserName ?? "Unknown User", + ); if (member != null) { constellation.setCursorColor(userId, member.defaultColor); @@ -128,8 +134,9 @@ class MatrixRTCScreenShareAnnotationSession var x = obj["x"] as num; var y = obj["y"] as num; - var stream = - session.streams.where((e) => e.streamId == streamId).firstOrNull; + var stream = session.streams + .where((e) => e.streamId == streamId) + .firstOrNull; if (stream != null && stream.direction == VoipStreamDirection.outgoing) { if (session.currentScreenshare != null) { final share = session.currentScreenshare as DesktopCapturerSourceNative; diff --git a/commet/lib/client/matrix/components/sidebar_entries/matrix_sidebar_entries_component.dart b/commet/lib/client/matrix/components/sidebar_entries/matrix_sidebar_entries_component.dart index 01fa51ade..38f73fce5 100644 --- a/commet/lib/client/matrix/components/sidebar_entries/matrix_sidebar_entries_component.dart +++ b/commet/lib/client/matrix/components/sidebar_entries/matrix_sidebar_entries_component.dart @@ -18,7 +18,7 @@ class MatrixSidebarEntryData { Map toJson() { return { if (folderId != null) "group": folderId, - if (order != null) "order": order + if (order != null) "order": order, }; } } @@ -134,8 +134,10 @@ class MatrixSidebarEntriesComponent order = orderGen.get(space.localId); } - data[space.identifier] = - MatrixSidebarEntryData(order: order, folderId: folder); + data[space.identifier] = MatrixSidebarEntryData( + order: order, + folderId: folder, + ); } var spaceData = Map.new(); @@ -158,26 +160,35 @@ class MatrixSidebarEntriesComponent if (groupData.isNotEmpty) "groups": groupData, }; - client.matrixClient - .setAccountData(client.matrixClient.userID!, key, result); + client.matrixClient.setAccountData( + client.matrixClient.userID!, + key, + result, + ); } @override List getEntries() { var spaces = client.spaces - .where((i) => - i.isTopLevel && spaceToFolder.containsKey(i.identifier) == false) + .where( + (i) => + i.isTopLevel && spaceToFolder.containsKey(i.identifier) == false, + ) .map((i) => SpaceSidebarEntry(i, order: getOrder(i))) .toList(); - var spacesInFolders = client.spaces - .where((i) => spaceToFolder.containsKey(i.identifier) && i.isTopLevel); + var spacesInFolders = client.spaces.where( + (i) => spaceToFolder.containsKey(i.identifier) && i.isTopLevel, + ); Map folders = {}; for (var value in spaceToFolder.values) { - folders[value] = SpaceGroupSidebarEntry(value, List.empty(growable: true), - order: getGroupOrder(value)); + folders[value] = SpaceGroupSidebarEntry( + value, + List.empty(growable: true), + order: getGroupOrder(value), + ); } for (var space in spacesInFolders) { @@ -188,9 +199,9 @@ class MatrixSidebarEntriesComponent order.set(space.localId, RandomUtils.getRandomString(10)); } - folders[folder]! - .spaces - .add(SpaceSidebarEntry(space, order: order.get(space.localId)!)); + folders[folder]!.spaces.add( + SpaceSidebarEntry(space, order: order.get(space.localId)!), + ); } return [...spaces, ...folders.values]; diff --git a/commet/lib/client/matrix/components/space_banner/matrix_space_banner_component.dart b/commet/lib/client/matrix/components/space_banner/matrix_space_banner_component.dart index 23c92b13e..bc4cf50f2 100644 --- a/commet/lib/client/matrix/components/space_banner/matrix_space_banner_component.dart +++ b/commet/lib/client/matrix/components/space_banner/matrix_space_banner_component.dart @@ -34,8 +34,10 @@ class MatrixSpaceBannerComponent @override Future setBanner(Uint8List data, {String? mimeType}) async { - var uploadResponse = - await client.matrixClient.uploadContent(data, contentType: mimeType); + var uploadResponse = await client.matrixClient.uploadContent( + data, + contentType: mimeType, + ); await client.matrixClient.setRoomStateWithKey( space.matrixRoom.id, diff --git a/commet/lib/client/matrix/components/space_color_scheme/matrix_space_color_scheme_component.dart b/commet/lib/client/matrix/components/space_color_scheme/matrix_space_color_scheme_component.dart index c2a9ce721..c871c4893 100644 --- a/commet/lib/client/matrix/components/space_color_scheme/matrix_space_color_scheme_component.dart +++ b/commet/lib/client/matrix/components/space_color_scheme/matrix_space_color_scheme_component.dart @@ -37,8 +37,9 @@ class MatrixSpaceColorSchemeComponent if (space.avatar != null) { var scheme = await ColorScheme.fromImageProvider( - provider: space.avatar!, - dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot); + provider: space.avatar!, + dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot, + ); _scheme = scheme; } diff --git a/commet/lib/client/matrix/components/threads/matrix_thread_timeline.dart b/commet/lib/client/matrix/components/threads/matrix_thread_timeline.dart index e80b0f672..041ba75b1 100644 --- a/commet/lib/client/matrix/components/threads/matrix_thread_timeline.dart +++ b/commet/lib/client/matrix/components/threads/matrix_thread_timeline.dart @@ -78,23 +78,28 @@ class MatrixThreadTimeline implements Timeline { events = List.empty(growable: true); } - Future> getThreadEvents( - {int limit = 20, String? nextBatch}) async { + Future> getThreadEvents({ + int limit = 20, + String? nextBatch, + }) async { var client = this.client as MatrixClient; var room = this.room as MatrixRoom; var mx = client.getMatrixClient(); - var data = await mx.request(matrix.RequestType.GET, - "/client/unstable/rooms/${room.identifier}/relations/$threadRootId/m.thread", - query: { - "limit": limit.toString(), - if (nextBatch != null) "from": nextBatch - }); + var data = await mx.request( + matrix.RequestType.GET, + "/client/unstable/rooms/${room.identifier}/relations/$threadRootId/m.thread", + query: { + "limit": limit.toString(), + if (nextBatch != null) "from": nextBatch, + }, + ); var chunk = List>.from(data["chunk"] as Iterable); - var mxevents = - chunk.map((e) => matrix.Event.fromJson(e, room.matrixRoom)).toList(); + var mxevents = chunk + .map((e) => matrix.Event.fromJson(e, room.matrixRoom)) + .toList(); for (var i = 0; i < mxevents.length; i++) { var event = mxevents[i]; @@ -112,8 +117,10 @@ class MatrixThreadTimeline implements Timeline { } var convertedEvents = mxevents - .map((e) => - room.convertEvent(e, timeline: mainRoomTimeline.matrixTimeline)) + .map( + (e) => + room.convertEvent(e, timeline: mainRoomTimeline.matrixTimeline), + ) .toList(); this.nextBatch = data["next_batch"] as String?; @@ -284,8 +291,9 @@ class MatrixThreadTimeline implements Timeline { void onMainTimelineEventChanged(int index) { var event = mainRoomTimeline.events[index]; if (isEventInThisThread(event)) { - var originalIndex = - events.indexWhere((element) => element.eventId == event.eventId); + var originalIndex = events.indexWhere( + (element) => element.eventId == event.eventId, + ); var finalIndex = originalIndex; @@ -303,8 +311,9 @@ class MatrixThreadTimeline implements Timeline { void onMainTimelineEventRemoved(int index) { var event = mainRoomTimeline.events[index]; if (isEventInThisThread(event)) { - var index = - events.indexWhere((element) => element.eventId == event.eventId); + var index = events.indexWhere( + (element) => element.eventId == event.eventId, + ); events.removeAt(index); diff --git a/commet/lib/client/matrix/components/threads/matrix_threads_component.dart b/commet/lib/client/matrix/components/threads/matrix_threads_component.dart index 17f0e1dc3..efa97e43e 100644 --- a/commet/lib/client/matrix/components/threads/matrix_threads_component.dart +++ b/commet/lib/client/matrix/components/threads/matrix_threads_component.dart @@ -108,8 +108,10 @@ class MatrixThreadsComponent implements ThreadsComponent { if (relations.containsKey("m.thread")) { var info = relations["m.thread"] as Map; if (info.containsKey("latest_event") == true) { - var matrixEvent = - matrix.Event.fromJson(info["latest_event"], tl.room); + var matrixEvent = matrix.Event.fromJson( + info["latest_event"], + tl.room, + ); tl.addAggregatedEvent(matrixEvent); @@ -118,8 +120,10 @@ class MatrixThreadsComponent implements ThreadsComponent { } } - var events = - event.event.aggregatedEvents(tl, matrix.RelationshipTypes.thread); + var events = event.event.aggregatedEvents( + tl, + matrix.RelationshipTypes.thread, + ); var firstEvent = events.firstOrNull; if (firstEvent == null) { @@ -129,9 +133,10 @@ class MatrixThreadsComponent implements ThreadsComponent { } @override - Future getThreadTimeline( - {required Timeline roomTimeline, - required String threadRootEventId}) async { + Future getThreadTimeline({ + required Timeline roomTimeline, + required String threadRootEventId, + }) async { if (roomTimeline is! MatrixTimeline) { return null; } @@ -140,11 +145,12 @@ class MatrixThreadsComponent implements ThreadsComponent { var room = (roomTimeline.room as MatrixRoom); var timeline = MatrixThreadTimeline( - client: client, - room: room, - threadRootId: threadRootEventId, - mainRoomTimeline: roomTimeline, - component: this); + client: client, + room: room, + threadRootId: threadRootEventId, + mainRoomTimeline: roomTimeline, + component: this, + ); await timeline.loadMoreHistory(); @@ -152,31 +158,34 @@ class MatrixThreadsComponent implements ThreadsComponent { } @override - Future sendMessage( - {required String threadRootEventId, - required Room room, - String? message, - TimelineEvent? inReplyTo, - TimelineEvent? replaceEvent, - List? processedAttachments}) async { + Future sendMessage({ + required String threadRootEventId, + required Room room, + String? message, + TimelineEvent? inReplyTo, + TimelineEvent? replaceEvent, + List? processedAttachments, + }) async { if (room is! MatrixRoom) { return null; } var newMessage = await room.sendMessage( - message: message, - inReplyTo: inReplyTo, - replaceEvent: replaceEvent, - processedAttachments: processedAttachments, - threadRootEventId: threadRootEventId) as MatrixTimelineEvent?; + message: message, + inReplyTo: inReplyTo, + replaceEvent: replaceEvent, + processedAttachments: processedAttachments, + threadRootEventId: threadRootEventId, + ) as MatrixTimelineEvent?; if (room.timeline != null) { - var index = room.timeline!.events - .indexWhere((element) => element.eventId == threadRootEventId); + var index = room.timeline!.events.indexWhere( + (element) => element.eventId == threadRootEventId, + ); - (room.timeline as MatrixTimeline) - .matrixTimeline! - .addAggregatedEvent(newMessage!.event); + (room.timeline as MatrixTimeline).matrixTimeline!.addAggregatedEvent( + newMessage!.event, + ); if (index != -1) { room.timeline!.notifyChanged(index); diff --git a/commet/lib/client/matrix/components/typing_indicators/matrix_typing_indicators_component.dart b/commet/lib/client/matrix/components/typing_indicators/matrix_typing_indicators_component.dart index 8e192deb9..2519b8e13 100644 --- a/commet/lib/client/matrix/components/typing_indicators/matrix_typing_indicators_component.dart +++ b/commet/lib/client/matrix/components/typing_indicators/matrix_typing_indicators_component.dart @@ -27,8 +27,10 @@ class MatrixTypingIndicatorsComponent @override bool? get typingIndicatorEnabledForRoom { - var publicTypingIndicatorForRoom = room.matrixRoom - .roomAccountData[publicTypingIndicatorKey]?.content["enabled"]; + var publicTypingIndicatorForRoom = room + .matrixRoom + .roomAccountData[publicTypingIndicatorKey] + ?.content["enabled"]; return publicTypingIndicatorForRoom is bool ? publicTypingIndicatorForRoom : null; diff --git a/commet/lib/client/matrix/components/url_preview/matrix_url_preview_component.dart b/commet/lib/client/matrix/components/url_preview/matrix_url_preview_component.dart index 169d0e3af..a649dfba9 100644 --- a/commet/lib/client/matrix/components/url_preview/matrix_url_preview_component.dart +++ b/commet/lib/client/matrix/components/url_preview/matrix_url_preview_component.dart @@ -27,7 +27,9 @@ class MatrixUrlPreviewComponent implements UrlPreviewComponent { @override Future getPreview( - Timeline timeline, TimelineEvent event) async { + Timeline timeline, + TimelineEvent event, + ) async { if (event is! TimelineEventMessage) { return null; } @@ -36,7 +38,8 @@ class MatrixUrlPreviewComponent implements UrlPreviewComponent { if (room.isE2EE && preferences.urlPreviewInE2EEChat.value == false) { Log.i( - "Not getting url preview because chat is encrypted and its not enabled"); + "Not getting url preview because chat is encrypted and its not enabled", + ); return null; } @@ -99,7 +102,9 @@ class MatrixUrlPreviewComponent implements UrlPreviewComponent { @override bool shouldGetPreviewDataForTimelineEvent( - Timeline timeline, TimelineEvent event) { + Timeline timeline, + TimelineEvent event, + ) { if (event is! TimelineEventMessage) { return false; } @@ -140,8 +145,10 @@ class MatrixUrlPreviewComponent implements UrlPreviewComponent { var data = null; try { - data = - await fetchPreviewData((room as MatrixRoom).matrixRoom.client, uri); + data = await fetchPreviewData( + (room as MatrixRoom).matrixRoom.client, + uri, + ); } catch (_) { return null; } @@ -154,12 +161,16 @@ class MatrixUrlPreviewComponent implements UrlPreviewComponent { } Future fetchPreviewData( - matrix.Client client, Uri url) async { + matrix.Client client, + Uri url, + ) async { late Map response; try { response = await client.request( - matrix.RequestType.GET, await getRequestPath(), - query: {"url": url.toString()}); + matrix.RequestType.GET, + await getRequestPath(), + query: {"url": url.toString()}, + ); } catch (e, s) { if (e is MatrixException) { if (e.error == MatrixError.M_UNRECOGNIZED) { @@ -226,12 +237,14 @@ class MatrixUrlPreviewComponent implements UrlPreviewComponent { var uri = Uri.parse(video); if (uri.scheme == "https") { - videoAttachment = VideoAttachment(WebFileProvider(uri), - width: videoWidth?.toDouble(), - height: videoHeight?.toDouble(), - streamUrl: uri, - thumbnail: image, - mimeType: videoType); + videoAttachment = VideoAttachment( + WebFileProvider(uri), + width: videoWidth?.toDouble(), + height: videoHeight?.toDouble(), + streamUrl: uri, + thumbnail: image, + mimeType: videoType, + ); } } @@ -239,12 +252,14 @@ class MatrixUrlPreviewComponent implements UrlPreviewComponent { description = description.replaceAll("\n", " "); } - return UrlPreviewData(url, - siteName: siteName, - title: title, - image: image, - video: videoAttachment, - type: destinationType, - description: description); + return UrlPreviewData( + url, + siteName: siteName, + title: title, + image: image, + video: videoAttachment, + type: destinationType, + description: description, + ); } } diff --git a/commet/lib/client/matrix/components/user_color/matrix_user_color_component.dart b/commet/lib/client/matrix/components/user_color/matrix_user_color_component.dart index e34db15d1..971c557f7 100644 --- a/commet/lib/client/matrix/components/user_color/matrix_user_color_component.dart +++ b/commet/lib/client/matrix/components/user_color/matrix_user_color_component.dart @@ -35,8 +35,11 @@ class MatrixUserColorComponent overrides[identifier] = color.toHexCode(); } - await client.matrixClient - .setAccountData(client.matrixClient.userID!, key, overrides); + await client.matrixClient.setAccountData( + client.matrixClient.userID!, + key, + overrides, + ); } @override diff --git a/commet/lib/client/matrix/components/user_presence/matrix_user_presence.dart b/commet/lib/client/matrix/components/user_presence/matrix_user_presence.dart index ff775ee71..cc6d146e8 100644 --- a/commet/lib/client/matrix/components/user_presence/matrix_user_presence.dart +++ b/commet/lib/client/matrix/components/user_presence/matrix_user_presence.dart @@ -23,8 +23,9 @@ class MatrixUserPresenceComponent client.matrixClient.onSync.stream.listen(onSync); lastSeen = InMemoryCache( - maxRetention: Duration(minutes: 2), - pollFrequency: Duration(seconds: 100)); + maxRetention: Duration(minutes: 2), + pollFrequency: Duration(seconds: 100), + ); lastSeen.onRemove.listen(onLastSeenRemoved); UserPresenceLifecycleWatcher().init(); @@ -95,7 +96,9 @@ class MatrixUserPresenceComponent if (presence.statusMsg != null) { message = UserPresenceMessage( - presence.statusMsg!, PresenceMessageType.userCustom); + presence.statusMsg!, + PresenceMessageType.userCustom, + ); } return UserPresence(status, message: message); @@ -109,21 +112,25 @@ class MatrixUserPresenceComponent Stream<(String, UserPresence)> get onPresenceChanged => _controller.stream; @override - Future setStatus(UserPresenceStatus status, - {String? message, bool clearMessage = false}) async { + Future setStatus( + UserPresenceStatus status, { + String? message, + bool clearMessage = false, + }) async { final self = client.self!.identifier; final current = await client.matrixClient.getPresence(self); await client.matrixClient.setPresence( - self, - statusMsg: clearMessage ? null : message ?? current.statusMsg, - switch (status) { - UserPresenceStatus.offline => PresenceType.offline, - UserPresenceStatus.unknown => PresenceType.offline, - UserPresenceStatus.online => PresenceType.online, - UserPresenceStatus.unavailable => PresenceType.unavailable, - }); + self, + statusMsg: clearMessage ? null : message ?? current.statusMsg, + switch (status) { + UserPresenceStatus.offline => PresenceType.offline, + UserPresenceStatus.unknown => PresenceType.offline, + UserPresenceStatus.online => PresenceType.online, + UserPresenceStatus.unavailable => PresenceType.unavailable, + }, + ); } void onSync(SyncUpdate event) { @@ -175,8 +182,10 @@ class MatrixUserPresenceComponent var value = entry.value as Map; if (value.containsKey("ts")) { - sawUser(entry.key, - DateTime.fromMicrosecondsSinceEpoch((value["ts"] as int) * 1000)); + sawUser( + entry.key, + DateTime.fromMicrosecondsSinceEpoch((value["ts"] as int) * 1000), + ); } } } @@ -191,8 +200,10 @@ class MatrixUserPresenceComponent } void sawUser(String id, DateTime timestamp) async { - final presence = await client.matrixClient - .fetchCurrentPresence(id, fetchOnlyFromCached: true); + final presence = await client.matrixClient.fetchCurrentPresence( + id, + fetchOnlyFromCached: true, + ); if (presence.presence != PresenceType.offline || presence.statusMsg != null) { @@ -215,8 +226,10 @@ class MatrixUserPresenceComponent } void onLastSeenRemoved(String event) async { - final presence = await client.matrixClient - .fetchCurrentPresence(event, fetchOnlyFromCached: true); + final presence = await client.matrixClient.fetchCurrentPresence( + event, + fetchOnlyFromCached: true, + ); if (presence.presence == PresenceType.offline) { _controller.add((event, UserPresence(UserPresenceStatus.offline))); } diff --git a/commet/lib/client/matrix/components/voip/matrix_voip_component.dart b/commet/lib/client/matrix/components/voip/matrix_voip_component.dart index b8d31f395..27cc91054 100644 --- a/commet/lib/client/matrix/components/voip/matrix_voip_component.dart +++ b/commet/lib/client/matrix/components/voip/matrix_voip_component.dart @@ -78,13 +78,15 @@ class MatrixVoipComponent mx.EventTypes.CallHangup, mx.EventTypes.CallAnswer, mx.EventTypes.CallInvite, - mx.EventTypes.CallReject + mx.EventTypes.CallReject, ].contains(event.event.type); } @override - Widget? displayTimelineEvent(TimelineEvent event, - {required String senderName}) { + Widget? displayTimelineEvent( + TimelineEvent event, { + required String senderName, + }) { if (event is! MatrixTimelineEvent) { return null; } @@ -116,7 +118,8 @@ class MatrixVoipComponent } Future> alterPeerConfiguration( - Map configuration) async { + Map configuration, + ) async { List> newServers = List.empty(growable: true); // Split up the urls in to individual servers, this helps flutter_webrtc to get all candidates correctly @@ -139,11 +142,13 @@ class MatrixVoipComponent var servers = configuration["iceServers"] as List; if (servers.isEmpty) { if (preferences.useFallbackTurnServer.value == false) { - var result = await AdaptiveDialog.show(navigator.currentContext!, - builder: (context) => - VoipTurnFallbackDialog(client.getMatrixClient().homeserver!), - dismissible: false, - title: "Call Error"); + var result = await AdaptiveDialog.show( + navigator.currentContext!, + builder: (context) => + VoipTurnFallbackDialog(client.getMatrixClient().homeserver!), + dismissible: false, + title: "Call Error", + ); preferences.useFallbackTurnServer.set(result ?? false); } @@ -151,8 +156,8 @@ class MatrixVoipComponent if (preferences.useFallbackTurnServer.value) { servers = [ { - "urls": [preferences.fallbackTurnServer.value] - } + "urls": [preferences.fallbackTurnServer.value], + }, ]; configuration["iceServers"] = servers; } @@ -163,15 +168,17 @@ class MatrixVoipComponent @override Future createPeerConnection( - Map configuration, - [Map constraints = const {}]) async { + Map configuration, [ + Map constraints = const {}, + ]) async { configuration = await alterPeerConfiguration(configuration); var servers = configuration['iceServers'] as List; if (servers.isEmpty) { throw Exception( - "No Turn servers are configured, this call cannot be connected"); + "No Turn servers are configured, this call cannot be connected", + ); } var pc = await webrtc.createPeerConnection(configuration, constraints); @@ -203,7 +210,7 @@ class MatrixVoipComponent var callType = switch (type) { CallType.voice => mx.CallType.kVoice, - CallType.video => mx.CallType.kVideo + CallType.video => mx.CallType.kVideo, }; var room = client.getMatrixClient().getRoomById(roomId); diff --git a/commet/lib/client/matrix/components/voip/matrix_voip_session.dart b/commet/lib/client/matrix/components/voip/matrix_voip_session.dart index e4fc46413..69787832d 100644 --- a/commet/lib/client/matrix/components/voip/matrix_voip_session.dart +++ b/commet/lib/client/matrix/components/voip/matrix_voip_session.dart @@ -55,8 +55,8 @@ class MatrixVoipSession implements VoipSession { final dataComponent = client.getComponent(); if (dataComponent != null) { - session.pc?.onDataChannel = - (channel) => dataComponent.dataChannelOpenedCallback(this, channel); + session.pc?.onDataChannel = (channel) => + dataComponent.dataChannelOpenedCallback(this, channel); } } @@ -115,7 +115,7 @@ class MatrixVoipSession implements VoipSession { matrix.CallState.kConnected => VoipState.connected, matrix.CallState.kRinging => VoipState.incoming, matrix.CallState.kEnded => VoipState.ended, - _ => VoipState.unknown + _ => VoipState.unknown, }; } @@ -123,8 +123,10 @@ class MatrixVoipSession implements VoipSession { String get roomName => session.room.getLocalizedDisplayname(); @override - Future acceptCall( - {bool withMicrophone = false, bool withCamera = false}) async { + Future acceptCall({ + bool withMicrophone = false, + bool withCamera = false, + }) async { WebrtcDefaultDevices.selectOutputDevice(); var defaultStream = await WebrtcDefaultDevices.getDefaultMicrophone(); @@ -132,15 +134,16 @@ class MatrixVoipSession implements VoipSession { if (defaultStream != null) { return session.answerWithStreams([ matrix.WrappedMediaStream( - stream: defaultStream, - room: session.room, - participant: session.localParticipant!, - purpose: matrix.SDPStreamMetadataPurpose.Usermedia, - client: session.room.client, - audioMuted: false, - videoMuted: true, - isGroupCall: false, - voip: session.voip), + stream: defaultStream, + room: session.room, + participant: session.localParticipant!, + purpose: matrix.SDPStreamMetadataPurpose.Usermedia, + client: session.room.client, + audioMuted: false, + videoMuted: true, + isGroupCall: false, + voip: session.voip, + ), ]); } else { return session.answer(); @@ -190,7 +193,7 @@ class MatrixVoipSession implements VoipSession { if (source is WebrtcAndroidScreencaptureSource) { stream = await webrtc.navigator.mediaDevices.getDisplayMedia({ 'video': { - 'mandatory': {'frameRate': preferences.streamFramerate.value} + 'mandatory': {'frameRate': preferences.streamFramerate.value}, }, }); } @@ -201,7 +204,7 @@ class MatrixVoipSession implements VoipSession { 'width': 1920, 'height': 1080, 'deviceId': {'exact': source.source.id}, - 'mandatory': {'frameRate': preferences.streamFramerate.value} + 'mandatory': {'frameRate': preferences.streamFramerate.value}, }, 'audio': true, }); @@ -211,23 +214,27 @@ class MatrixVoipSession implements VoipSession { currentScreenshare = source; await stopScreenshare(); session.addLocalStream( - stream, matrix.SDPStreamMetadataPurpose.Screenshare); + stream, + matrix.SDPStreamMetadataPurpose.Screenshare, + ); } } @override Future stopScreenshare() async { - for (var element in session.getLocalStreams.where((element) => - element.purpose == matrix.SDPStreamMetadataPurpose.Screenshare)) { + for (var element in session.getLocalStreams.where( + (element) => + element.purpose == matrix.SDPStreamMetadataPurpose.Screenshare, + )) { await session.removeLocalStream(element); } } @override Future setCamera(MediaDeviceInfo? device) async { - if (session.localUserMediaStream!.stream! - .getTracks() - .any((element) => element.kind == "video") == + if (session.localUserMediaStream!.stream!.getTracks().any( + (element) => element.kind == "video", + ) == false) { await session.insertVideoTrackToAudioOnlyStream(); } @@ -243,8 +250,10 @@ class MatrixVoipSession implements VoipSession { void initStreams() { List result = List.empty(growable: true); - var s = List.from(session.getLocalStreams, - growable: true); + var s = List.from( + session.getLocalStreams, + growable: true, + ); s.addAll(session.getRemoteStreams); for (var stream in s) { @@ -252,8 +261,9 @@ class MatrixVoipSession implements VoipSession { continue; } - if (!result - .any((element) => element.stream.stream?.id == stream.stream?.id)) { + if (!result.any( + (element) => element.stream.stream?.id == stream.stream?.id, + )) { result.add(MatrixVoipStream(stream, this)); } } @@ -269,7 +279,7 @@ class MatrixVoipSession implements VoipSession { if (![ matrix.SDPStreamMetadataPurpose.Screenshare, - matrix.SDPStreamMetadataPurpose.Usermedia + matrix.SDPStreamMetadataPurpose.Usermedia, ].contains(stream.purpose)) { return false; } diff --git a/commet/lib/client/matrix/components/voip/matrix_voip_stream.dart b/commet/lib/client/matrix/components/voip/matrix_voip_stream.dart index aee7f55b5..c18cb28cd 100644 --- a/commet/lib/client/matrix/components/voip/matrix_voip_stream.dart +++ b/commet/lib/client/matrix/components/voip/matrix_voip_stream.dart @@ -129,7 +129,9 @@ class MatrixVoipStream implements VoipStream { if (fit == BoxFit.contain) { return AspectRatio( - aspectRatio: aspectRatio ?? 1, child: RTCVideoView(renderer!)); + aspectRatio: aspectRatio ?? 1, + child: RTCVideoView(renderer!), + ); } else { if (renderer!.textureId != null) { return RTCVideoView( diff --git a/commet/lib/client/matrix/components/voip_room/matrix_livekit_backend.dart b/commet/lib/client/matrix/components/voip_room/matrix_livekit_backend.dart index f7884ac89..7341d2d3b 100644 --- a/commet/lib/client/matrix/components/voip_room/matrix_livekit_backend.dart +++ b/commet/lib/client/matrix/components/voip_room/matrix_livekit_backend.dart @@ -21,13 +21,12 @@ class MatrixLivekitBackend { final selectedFocus = findSelectedFocus(); var wellKnown = await room.matrixRoom.client.getWellknown(); - final livekitJwtServiceUrl = wellKnown - .additionalProperties["org.matrix.msc4143.rtc_foci"] as List?; + final livekitJwtServiceUrl = + wellKnown.additionalProperties["org.matrix.msc4143.rtc_foci"] + as List?; if (livekitJwtServiceUrl == null) { - return [ - if (selectedFocus != null) selectedFocus, - ]; + return [if (selectedFocus != null) selectedFocus]; } Uri? fociUrl; @@ -47,9 +46,7 @@ class MatrixLivekitBackend { ]; } - return [ - if (selectedFocus != null) selectedFocus, - ]; + return [if (selectedFocus != null) selectedFocus]; } Uri? findSelectedFocus() { @@ -63,8 +60,9 @@ class MatrixLivekitBackend { values.sort((a, b) => a.originServerTs.compareTo(b.originServerTs)); for (var entry in values) { - final focusActive = - entry.content.tryGet>("focus_active"); + final focusActive = entry.content.tryGet>( + "focus_active", + ); if (focusActive == null) { continue; @@ -77,12 +75,14 @@ class MatrixLivekitBackend { if (focusActive['focus_selection'] != "oldest_membership") { Log.e( - "Unknown focus selection algorithm: ${focusActive['focus_selection']}"); + "Unknown focus selection algorithm: ${focusActive['focus_selection']}", + ); continue; } - final fociPreferred = - entry.content.tryGet>("foci_preferred"); + final fociPreferred = entry.content.tryGet>( + "foci_preferred", + ); Log.e("Selecting focus"); if (fociPreferred == null) { continue; @@ -111,8 +111,10 @@ class MatrixLivekitBackend { final selectedFocus = fociUrl.first; Log.d("Got Foci Url: ${fociUrl}"); - final token = await room.matrixRoom.client - .requestOpenIdToken(room.matrixRoom.client.userID!, {}); + final token = await room.matrixRoom.client.requestOpenIdToken( + room.matrixRoom.client.userID!, + {}, + ); if (selectedFocus.scheme != "https") { throw Exception("Selected focus JWT does not use HTTPS"); @@ -128,7 +130,7 @@ class MatrixLivekitBackend { "matrix_server_name": token.matrixServerName, "access_token": token.accessToken, "expires_in": token.expiresIn, - } + }, }; var result = await http.post(uri, body: jsonEncode(body)); @@ -146,20 +148,22 @@ class MatrixLivekitBackend { MatrixLivekitEncryptionKeyProvider? provider; if (room.isE2EE) { - provider = - await MatrixLivekitEncryptionKeyProvider.create(room.matrixRoom); + provider = await MatrixLivekitEncryptionKeyProvider.create( + room.matrixRoom, + ); e2eeOptions = lk.E2EEOptions(keyProvider: provider); } final roomOptions = lk.RoomOptions( - adaptiveStream: true, - dynacast: true, - e2eeOptions: e2eeOptions, - defaultAudioPublishOptions: lk.AudioPublishOptions( - encoding: lk.AudioEncoding( - maxBitrate: - (preferences.streamAudioBitrate.value * 1000).toInt()), - )); + adaptiveStream: true, + dynacast: true, + e2eeOptions: e2eeOptions, + defaultAudioPublishOptions: lk.AudioPublishOptions( + encoding: lk.AudioEncoding( + maxBitrate: (preferences.streamAudioBitrate.value * 1000).toInt(), + ), + ), + ); final lkRoom = lk.Room(roomOptions: roomOptions); @@ -167,25 +171,31 @@ class MatrixLivekitBackend { final stateKey = "_${room.client.self!.identifier}_${room.matrixRoom.client.deviceID!}_m.call"; - await room.matrixRoom.client.setRoomStateWithKey(room.matrixRoom.id, - MatrixVoipRoomComponent.callMemberStateEvent, stateKey, { - "application": "m.call", - "call_id": "", - "device_id": room.matrixRoom.client.deviceID!, - "expires": 14400000, - "foci_preferred": fociUrl - .map((e) => { + await room.matrixRoom.client.setRoomStateWithKey( + room.matrixRoom.id, + MatrixVoipRoomComponent.callMemberStateEvent, + stateKey, + { + "application": "m.call", + "call_id": "", + "device_id": room.matrixRoom.client.deviceID!, + "expires": 14400000, + "foci_preferred": fociUrl + .map( + (e) => { "type": "livekit", "livekit_alias": room.identifier, - "livekit_service_url": e.toString() - }) - .toList(), - "focus_active": { - "focus_selection": "oldest_membership", - "type": "livekit" + "livekit_service_url": e.toString(), + }, + ) + .toList(), + "focus_active": { + "focus_selection": "oldest_membership", + "type": "livekit", + }, + "scope": "m.room", }, - "scope": "m.room" - }); + ); await lkRoom.connect(sfuUrl, jwt); @@ -193,8 +203,10 @@ class MatrixLivekitBackend { print("Using default device: ${device}"); - lkRoom.localParticipant?.setMicrophoneEnabled(true, - audioCaptureOptions: lk.AudioCaptureOptions(deviceId: device)); + lkRoom.localParticipant?.setMicrophoneEnabled( + true, + audioCaptureOptions: lk.AudioCaptureOptions(deviceId: device), + ); livekitRoom = lkRoom; return MatrixLivekitVoipSession(room, lkRoom, keyProvider: provider); diff --git a/commet/lib/client/matrix/components/voip_room/matrix_livekit_encryption_key_provider.dart b/commet/lib/client/matrix/components/voip_room/matrix_livekit_encryption_key_provider.dart index b4ffc76c7..8f2cf6da1 100644 --- a/commet/lib/client/matrix/components/voip_room/matrix_livekit_encryption_key_provider.dart +++ b/commet/lib/client/matrix/components/voip_room/matrix_livekit_encryption_key_provider.dart @@ -39,18 +39,19 @@ class MatrixLivekitEncryptionKeyProvider implements BaseKeyProvider { static Future create(mx.Room room) async { final rtc.KeyProviderOptions options = rtc.KeyProviderOptions( - sharedKey: false, - ratchetSalt: Uint8List.fromList(defaultRatchetSalt.codeUnits), - ratchetWindowSize: 10, - uncryptedMagicBytes: Uint8List.fromList(defaultMagicBytes.codeUnits), - failureTolerance: -1, - keyRingSize: 256, - keyDerivationAlgorithm: KeyDerivationAlgorithm.kHKDF, - discardFrameWhenCryptorNotReady: - defaultDiscardFrameWhenCryptorNotReady); - - final keyProvider = - await rtc.frameCryptorFactory.createDefaultKeyProvider(options); + sharedKey: false, + ratchetSalt: Uint8List.fromList(defaultRatchetSalt.codeUnits), + ratchetWindowSize: 10, + uncryptedMagicBytes: Uint8List.fromList(defaultMagicBytes.codeUnits), + failureTolerance: -1, + keyRingSize: 256, + keyDerivationAlgorithm: KeyDerivationAlgorithm.kHKDF, + discardFrameWhenCryptorNotReady: defaultDiscardFrameWhenCryptorNotReady, + ); + + final keyProvider = await rtc.frameCryptorFactory.createDefaultKeyProvider( + options, + ); var provider = BaseKeyProvider(keyProvider, options); @@ -92,15 +93,24 @@ class MatrixLivekitEncryptionKeyProvider implements BaseKeyProvider { @override Future setKey(String key, {String? participantId, int? keyIndex}) { - return _keyProvider.setKey(key, - participantId: participantId, keyIndex: keyIndex); + return _keyProvider.setKey( + key, + participantId: participantId, + keyIndex: keyIndex, + ); } @override - Future setRawKey(Uint8List key, - {String? participantId, int? keyIndex}) { - return _keyProvider.setRawKey(key, - participantId: participantId, keyIndex: keyIndex); + Future setRawKey( + Uint8List key, { + String? participantId, + int? keyIndex, + }) { + return _keyProvider.setRawKey( + key, + participantId: participantId, + keyIndex: keyIndex, + ); } @override @@ -146,8 +156,10 @@ class MatrixLivekitEncryptionKeyProvider implements BaseKeyProvider { } setRawKey(bytes, participantId: localParticipant!, keyIndex: index); - lkRoom.e2eeManager - ?.setKeyIndex(index, participantIdentity: localParticipant!); + lkRoom.e2eeManager?.setKeyIndex( + index, + participantIdentity: localParticipant!, + ); } Future sendKeyToParticipants(Uint8List bytes, int keyIndex) async { @@ -157,18 +169,11 @@ class MatrixLivekitEncryptionKeyProvider implements BaseKeyProvider { } var content = { - "keys": { - "index": keyIndex, - "key": base64Encode(bytes), - }, + "keys": {"index": keyIndex, "key": base64Encode(bytes)}, "member": {"claimed_device_id": room.client.deviceID!}, "room_id": room.id, "sent_ts": DateTime.now().millisecondsSinceEpoch, - "session": { - "application": "m.call", - "call_id": "", - "scope": "m.room", - } + "session": {"application": "m.call", "call_id": "", "scope": "m.room"}, }; List sendToDevices = List.empty(growable: true); @@ -197,14 +202,15 @@ class MatrixLivekitEncryptionKeyProvider implements BaseKeyProvider { if (sendToDevices.isNotEmpty) { room.client.sendToDeviceEncrypted( - sendToDevices, "io.element.call.encryption_keys", content); + sendToDevices, + "io.element.call.encryption_keys", + content, + ); } } void onToDeviceEvent(mx.ToDeviceEvent event) { - Log.i( - "Received to device event: ${event.toJson()}", - ); + Log.i("Received to device event: ${event.toJson()}"); if (event.type == "io.element.call.encryption_keys") { var data = event.content["keys"] as Map; @@ -216,8 +222,9 @@ class MatrixLivekitEncryptionKeyProvider implements BaseKeyProvider { var b = base64Decode(key); - var deviceId = (event.content["member"] - as Map)["claimed_device_id"] as String; + var deviceId = + (event.content["member"] as Map)["claimed_device_id"] + as String; var participantId = event.senderId + ":" + deviceId; @@ -253,12 +260,14 @@ class MatrixLivekitEncryptionKeyProvider implements BaseKeyProvider { if (application != "m.call") { Log.w( - "Received membership state change for invalid application, not sending key"); + "Received membership state change for invalid application, not sending key", + ); } if (callid != "") { Log.w( - "Received membership state change for invalid call id, not sending key"); + "Received membership state change for invalid call id, not sending key", + ); continue; } diff --git a/commet/lib/client/matrix/components/voip_room/matrix_livekit_voip_session.dart b/commet/lib/client/matrix/components/voip_room/matrix_livekit_voip_session.dart index 3e688d947..eed07324f 100644 --- a/commet/lib/client/matrix/components/voip_room/matrix_livekit_voip_session.dart +++ b/commet/lib/client/matrix/components/voip_room/matrix_livekit_voip_session.dart @@ -100,8 +100,10 @@ class MatrixLivekitVoipSession implements VoipSession { } @override - Future acceptCall( - {bool withMicrophone = false, bool withCamera = false}) { + Future acceptCall({ + bool withMicrophone = false, + bool withCamera = false, + }) { throw UnimplementedError(); } @@ -117,9 +119,11 @@ class MatrixLivekitVoipSession implements VoipSession { void onTrackMutedEvent(lk.TrackMutedEvent event) { if (event.publication.track?.mediaType == RTCRtpMediaType.RTCRtpMediaTypeVideo) { - streams.removeWhere((e) => - (e as MatrixLivekitVoipStream).publication.sid == - event.publication.sid); + streams.removeWhere( + (e) => + (e as MatrixLivekitVoipStream).publication.sid == + event.publication.sid, + ); } for (var track in streams) { @@ -135,8 +139,10 @@ class MatrixLivekitVoipSession implements VoipSession { } void onTrackUnmutedEvent(lk.TrackUnmutedEvent event) { - final participant = - event.participant.identity.split(":").getRange(0, 2).join(":"); + final participant = event.participant.identity + .split(":") + .getRange(0, 2) + .join(":"); for (var track in streams) { final t = track as MatrixLivekitVoipStream; @@ -154,8 +160,10 @@ class MatrixLivekitVoipSession implements VoipSession { } void onTrackPublished(lk.TrackPublishedEvent event) { - final participant = - event.participant.identity.split(":").getRange(0, 2).join(":"); + final participant = event.participant.identity + .split(":") + .getRange(0, 2) + .join(":"); _addStream(event.publication, participant); @@ -174,8 +182,11 @@ class MatrixLivekitVoipSession implements VoipSession { for (var track in streams) { if (track.type == VoipStreamType.audio) { final t = track as MatrixLivekitVoipStream; - t.markAsSpeaker(event.speakers - .any((i) => i.identity == track.publication.participant.identity)); + t.markAsSpeaker( + event.speakers.any( + (i) => i.identity == track.publication.participant.identity, + ), + ); } } @@ -183,24 +194,30 @@ class MatrixLivekitVoipSession implements VoipSession { } void onLocalTrackPublished(lk.LocalTrackPublishedEvent event) { - final participant = - event.participant.identity.split(":").getRange(0, 2).join(":"); + final participant = event.participant.identity + .split(":") + .getRange(0, 2) + .join(":"); _addStream(event.publication, participant); } void onLocalTrackUnpublished(lk.LocalTrackUnpublishedEvent event) { - streams.removeWhere((e) => - (e as MatrixLivekitVoipStream).publication.sid == - event.publication.sid); + streams.removeWhere( + (e) => + (e as MatrixLivekitVoipStream).publication.sid == + event.publication.sid, + ); _stateChanged.add(()); } void onTrackUnpublished(lk.TrackUnpublishedEvent event) { - streams.removeWhere((e) => - (e as MatrixLivekitVoipStream).publication.sid == - event.publication.sid); + streams.removeWhere( + (e) => + (e as MatrixLivekitVoipStream).publication.sid == + event.publication.sid, + ); _stateChanged.add(()); } @@ -300,71 +317,96 @@ class MatrixLivekitVoipSession implements VoipSession { } Log.i( - "Starting stream with settings: ${preferences.streamBitrate.value}Mbps, ${framerate}FPS, $codec ${res}"); + "Starting stream with settings: ${preferences.streamBitrate.value}Mbps, ${framerate}FPS, $codec ${res}", + ); if (WebrtcScreencaptureSource.supportsSystemAudio) { var tracks = await lk.LocalVideoTrack.createScreenShareTracksWithAudio( - lk.ScreenShareCaptureOptions( - sourceId: srcid, - maxFrameRate: framerate, - captureScreenAudio: true, - params: lk.VideoParameters( - dimensions: lk.VideoDimensionsPresets.h720_169, - encoding: lk.VideoEncoding( - maxFramerate: framerate.toInt(), maxBitrate: bitrate), + lk.ScreenShareCaptureOptions( + sourceId: srcid, + maxFrameRate: framerate, + captureScreenAudio: true, + params: lk.VideoParameters( + dimensions: lk.VideoDimensionsPresets.h720_169, + encoding: lk.VideoEncoding( + maxFramerate: framerate.toInt(), + maxBitrate: bitrate, + ), + ), ), - )); + ); print(tracks); for (var track in tracks) { if (track is lk.LocalVideoTrack) { - await livekitRoom.localParticipant?.publishVideoTrack(track, - publishOptions: lk.VideoPublishOptions( - simulcast: preferences.doSimulcast.value, - screenShareEncoding: lk.VideoEncoding( - maxFramerate: framerate.toInt(), maxBitrate: bitrate), - videoEncoding: lk.VideoEncoding( - maxFramerate: framerate.toInt(), maxBitrate: bitrate), - videoCodec: preferences.streamCodec.value, - )); + await livekitRoom.localParticipant?.publishVideoTrack( + track, + publishOptions: lk.VideoPublishOptions( + simulcast: preferences.doSimulcast.value, + screenShareEncoding: lk.VideoEncoding( + maxFramerate: framerate.toInt(), + maxBitrate: bitrate, + ), + videoEncoding: lk.VideoEncoding( + maxFramerate: framerate.toInt(), + maxBitrate: bitrate, + ), + videoCodec: preferences.streamCodec.value, + ), + ); track.setDegradationPreference( - lk.DegradationPreference.maintainFramerate); + lk.DegradationPreference.maintainFramerate, + ); } if (track is lk.LocalAudioTrack) { - await livekitRoom.localParticipant?.publishAudioTrack(track, - publishOptions: lk.AudioPublishOptions( - name: "screenshare", - dtx: false, - red: false, - encoding: lk.AudioEncoding.presetMusicHighQualityStereo)); + await livekitRoom.localParticipant?.publishAudioTrack( + track, + publishOptions: lk.AudioPublishOptions( + name: "screenshare", + dtx: false, + red: false, + encoding: lk.AudioEncoding.presetMusicHighQualityStereo, + ), + ); } } } else { var track = await lk.LocalVideoTrack.createScreenShareTrack( - lk.ScreenShareCaptureOptions( - sourceId: srcid, - maxFrameRate: framerate, - params: lk.VideoParameters( - dimensions: lk.VideoDimensionsPresets.h720_169, - encoding: lk.VideoEncoding( - maxFramerate: framerate.toInt(), maxBitrate: bitrate), - ))); - - await livekitRoom.localParticipant?.publishVideoTrack(track, - publishOptions: lk.VideoPublishOptions( - simulcast: preferences.doSimulcast.value, - screenShareEncoding: lk.VideoEncoding( - maxFramerate: framerate.toInt(), maxBitrate: bitrate), - videoEncoding: lk.VideoEncoding( - maxFramerate: framerate.toInt(), maxBitrate: bitrate), - videoCodec: preferences.streamCodec.value, - )); - - track - .setDegradationPreference(lk.DegradationPreference.maintainFramerate); + lk.ScreenShareCaptureOptions( + sourceId: srcid, + maxFrameRate: framerate, + params: lk.VideoParameters( + dimensions: lk.VideoDimensionsPresets.h720_169, + encoding: lk.VideoEncoding( + maxFramerate: framerate.toInt(), + maxBitrate: bitrate, + ), + ), + ), + ); + + await livekitRoom.localParticipant?.publishVideoTrack( + track, + publishOptions: lk.VideoPublishOptions( + simulcast: preferences.doSimulcast.value, + screenShareEncoding: lk.VideoEncoding( + maxFramerate: framerate.toInt(), + maxBitrate: bitrate, + ), + videoEncoding: lk.VideoEncoding( + maxFramerate: framerate.toInt(), + maxBitrate: bitrate, + ), + videoCodec: preferences.streamCodec.value, + ), + ); + + track.setDegradationPreference( + lk.DegradationPreference.maintainFramerate, + ); } _stateChanged.add(()); @@ -428,8 +470,12 @@ class MatrixLivekitVoipSession implements VoipSession { final stateKey = "_${room.client.self!.identifier}_${room.matrixRoom.client.deviceID!}_m.call"; - await room.matrixRoom.client.setRoomStateWithKey(room.matrixRoom.id, - MatrixVoipRoomComponent.callMemberStateEvent, stateKey, {}); + await room.matrixRoom.client.setRoomStateWithKey( + room.matrixRoom.id, + MatrixVoipRoomComponent.callMemberStateEvent, + stateKey, + {}, + ); Log.i("Cleared call state"); } @@ -442,10 +488,12 @@ class MatrixLivekitVoipSession implements VoipSession { return; } - await room.matrixRoom.client.request(RequestType.POST, - "/client/unstable/org.matrix.msc4140/delayed_events/${Uri.encodeComponent(heartbeatDelayId!)}", - contentType: "application/json", - data: jsonEncode({"action": "cancel"})); + await room.matrixRoom.client.request( + RequestType.POST, + "/client/unstable/org.matrix.msc4140/delayed_events/${Uri.encodeComponent(heartbeatDelayId!)}", + contentType: "application/json", + data: jsonEncode({"action": "cancel"}), + ); heartbeatDelayId = null; Log.i("Stopped heartbeat"); @@ -464,32 +512,39 @@ class MatrixLivekitVoipSession implements VoipSession { final timerLength = Duration(seconds: 30); - final result = await room.matrixRoom.client.request(RequestType.PUT, - "/client/v3/rooms/${Uri.encodeComponent(room.matrixRoom.id)}/state/${Uri.encodeComponent(MatrixVoipRoomComponent.callMemberStateEvent)}/${Uri.encodeComponent(stateKey)}", - contentType: "application/json", - data: "{}", - query: { - "org.matrix.msc4140.delay": timerLength.inMilliseconds.toString() - }); + final result = await room.matrixRoom.client.request( + RequestType.PUT, + "/client/v3/rooms/${Uri.encodeComponent(room.matrixRoom.id)}/state/${Uri.encodeComponent(MatrixVoipRoomComponent.callMemberStateEvent)}/${Uri.encodeComponent(stateKey)}", + contentType: "application/json", + data: "{}", + query: { + "org.matrix.msc4140.delay": timerLength.inMilliseconds.toString(), + }, + ); final delayId = result["delay_id"] as String; heartbeatDelayId = delayId; - heartbeatTimer = - Timer.periodic(timerLength - Duration(seconds: 5), (timer) async { + heartbeatTimer = Timer.periodic(timerLength - Duration(seconds: 5), ( + timer, + ) async { print("Sending heartbeat"); - final result = await room.matrixRoom.client.request(RequestType.POST, - "/client/unstable/org.matrix.msc4140/delayed_events/${Uri.encodeComponent(delayId)}", - contentType: "application/json", - data: jsonEncode({"action": "restart"})); + final result = await room.matrixRoom.client.request( + RequestType.POST, + "/client/unstable/org.matrix.msc4140/delayed_events/${Uri.encodeComponent(delayId)}", + contentType: "application/json", + data: jsonEncode({"action": "restart"}), + ); print(result); }); } @override double get generalAudioLevel { - double result = - streams.fold(0.0, (value, stream) => max(value, stream.audiolevel)); + double result = streams.fold( + 0.0, + (value, stream) => max(value, stream.audiolevel), + ); return result; } diff --git a/commet/lib/client/matrix/components/voip_room/matrix_livekit_voip_stream.dart b/commet/lib/client/matrix/components/voip_room/matrix_livekit_voip_stream.dart index 0baedbbca..daa9a080d 100644 --- a/commet/lib/client/matrix/components/voip_room/matrix_livekit_voip_stream.dart +++ b/commet/lib/client/matrix/components/voip_room/matrix_livekit_voip_stream.dart @@ -92,10 +92,10 @@ class MatrixLivekitVoipStream implements VoipStream { @override // TODO: implement stats String get stats => JsonEncoder.withIndent(" ").convert({ - "is encrypted": publication.participant.isEncrypted, - "encryption type": publication.encryptionType.toString(), - "publication": publication.name - }); + "is encrypted": publication.participant.isEncrypted, + "encryption type": publication.encryptionType.toString(), + "publication": publication.name, + }); String get volumeKey => type == VoipStreamType.screenshareAudio ? "stream:${userId}" : userId; diff --git a/commet/lib/client/matrix/components/voip_room/matrix_voip_room_component.dart b/commet/lib/client/matrix/components/voip_room/matrix_voip_room_component.dart index 502b1cf44..f5566b500 100644 --- a/commet/lib/client/matrix/components/voip_room/matrix_voip_room_component.dart +++ b/commet/lib/client/matrix/components/voip_room/matrix_voip_room_component.dart @@ -99,8 +99,8 @@ class MatrixVoipRoomComponent @override bool get canJoinCall => room.matrixRoom.canChangeStateEvent( - MatrixVoipRoomComponent.callMemberStateEvent, - ); + MatrixVoipRoomComponent.callMemberStateEvent, + ); @override Future clearAllCallMembershipStatus() async { diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_always_on_screen.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_always_on_screen.dart index 482454b4f..3c5476005 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_always_on_screen.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_always_on_screen.dart @@ -11,8 +11,10 @@ class MatrixCapabilityAlwaysOnScreen implements MatrixWidgetCapability { static const String name = "m.always_on_screen"; - static MatrixWidgetCapabilityConstructorEntry entry = MapEntry(name, - (runner, type, key) => MatrixCapabilityAlwaysOnScreen(runner: runner)); + static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( + name, + (runner, type, key) => MatrixCapabilityAlwaysOnScreen(runner: runner), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_delayed_events.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_delayed_events.dart index e03c56e55..2359feb42 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_delayed_events.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_delayed_events.dart @@ -16,8 +16,10 @@ class MatrixCapabilitySendDelayedEvent implements MatrixWidgetCapability { static const String name = "org.matrix.msc4157.send.delayed_event"; - static MatrixWidgetCapabilityConstructorEntry entry = MapEntry(name, - (runner, type, key) => MatrixCapabilitySendDelayedEvent(runner: runner)); + static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( + name, + (runner, type, key) => MatrixCapabilitySendDelayedEvent(runner: runner), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; @@ -50,9 +52,9 @@ class MatrixCapabilityUpdateDelayedEvent implements MatrixWidgetCapability { static const String name = "org.matrix.msc4157.update_delayed_event"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, - (runner, type, key) => - MatrixCapabilityUpdateDelayedEvent(runner: runner)); + name, + (runner, type, key) => MatrixCapabilityUpdateDelayedEvent(runner: runner), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; @@ -81,10 +83,11 @@ class MatrixCapabilityUpdateDelayedEvent implements MatrixWidgetCapability { throw UnsupportedError("Invalid request"); final result = await runner.room!.matrixRoom.client.request( - RequestType.POST, - "/client/unstable/org.matrix.msc4140/delayed_events/${Uri.encodeComponent(delayId)}", - contentType: "application/json", - data: jsonEncode({"action": action})); + RequestType.POST, + "/client/unstable/org.matrix.msc4140/delayed_events/${Uri.encodeComponent(delayId)}", + contentType: "application/json", + data: jsonEncode({"action": action}), + ); Log.i("Got result from delayed event update ${result}"); diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_download_file.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_download_file.dart index 40741bec6..f6ddd8a63 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_download_file.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_download_file.dart @@ -27,7 +27,9 @@ class MatrixCapabilityDownloadFile implements MatrixWidgetCapability { static const String name = "org.matrix.msc4039.download_file"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, (runner, type, key) => MatrixCapabilityDownloadFile(runner)); + name, + (runner, type, key) => MatrixCapabilityDownloadFile(runner), + ); @override Future handleRequest(MatrixWidgetMessage message) async { @@ -46,8 +48,9 @@ class MatrixCapabilityDownloadFile implements MatrixWidgetCapability { Uint8List? bytes; if (!kIsWeb) { - var cached = - await fileCache?.getFile(MatrixMxcImage.getThumbnailIdentifier(uri)); + var cached = await fileCache?.getFile( + MatrixMxcImage.getThumbnailIdentifier(uri), + ); if (cached != null) { bytes = await File.fromUri(cached).readAsBytes(); @@ -59,8 +62,9 @@ class MatrixCapabilityDownloadFile implements MatrixWidgetCapability { bytes = response.data; } - return message - .createResponseObject(response: {"file": MatrixWidgetBlob(bytes)}); + return message.createResponseObject( + response: {"file": MatrixWidgetBlob(bytes)}, + ); } @override diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_get_media_config.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_get_media_config.dart index 25ef57c28..29f2b84d6 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_get_media_config.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_get_media_config.dart @@ -20,7 +20,9 @@ class MatrixCapabilityGetMediaConfig implements MatrixWidgetCapability { static const String name = "org.matrix.msc4039.get_media_config"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, (runner, type, key) => MatrixCapabilityGetMediaConfig(runner)); + name, + (runner, type, key) => MatrixCapabilityGetMediaConfig(runner), + ); @override Future handleRequest(MatrixWidgetMessage message) async { @@ -35,11 +37,15 @@ class MatrixCapabilityGetMediaConfig implements MatrixWidgetCapability { @override bool canHandleRequest(MatrixWidgetMessage message) { - if (!capabilities.grantedCapabilities - .containsKey(MatrixCapabilityDownloadFile.name)) return false; - - if (!capabilities.grantedCapabilities - .containsKey(MatrixCapabilityUploadFile.name)) return false; + if (!capabilities.grantedCapabilities.containsKey( + MatrixCapabilityDownloadFile.name, + )) + return false; + + if (!capabilities.grantedCapabilities.containsKey( + MatrixCapabilityUploadFile.name, + )) + return false; return message.action == name; } diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_oidc.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_oidc.dart index 41ede4d9c..d47176973 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_oidc.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_oidc.dart @@ -15,7 +15,9 @@ class MatrixCapabilityOIDC implements MatrixWidgetCapability { static const String name = "m.oidc"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, (runner, type, key) => MatrixCapabilityOIDC(runner: runner)); + name, + (runner, type, key) => MatrixCapabilityOIDC(runner: runner), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; @@ -49,10 +51,14 @@ class MatrixCapabilityOIDC implements MatrixWidgetCapability { "chat.commet.internal.get_openid_auto_accept"; Future promptUserConfirmation(String requestId) async { var capabilities = await preferences.getAcceptedWidgetCapabilities( - runner.client.identifier, runner.info.namespace); + runner.client.identifier, + runner.info.namespace, + ); var rejected = await preferences.getRejectedWidgetCapabilities( - runner.client.identifier, runner.info.namespace); + runner.client.identifier, + runner.info.namespace, + ); bool? result; @@ -60,37 +66,45 @@ class MatrixCapabilityOIDC implements MatrixWidgetCapability { result = true; Log.i( - "Widget OIDC previous permission prompt was accepted, accepting by default"); + "Widget OIDC previous permission prompt was accepted, accepting by default", + ); } if (rejected.contains(autoAcceptConfirmationKey)) { result = false; Log.i( - "Widget OIDC previous permission prompt was rejected, rejecting by default"); + "Widget OIDC previous permission prompt was rejected, rejecting by default", + ); } if (result == null) { if (currentConfirmationRequest == null) { currentConfirmationRequest = currentConfirmationRequest = - AdaptiveDialog.confirmationWithOptions(navigator.currentContext!, - showRememberChoice: true, - defaultRememberSetting: true, - title: "Allow ${runner.info.name} to verify your user id"); + AdaptiveDialog.confirmationWithOptions( + navigator.currentContext!, + showRememberChoice: true, + defaultRememberSetting: true, + title: "Allow ${runner.info.name} to verify your user id", + ); } var promptResult = await currentConfirmationRequest!; if (promptResult?.remember == true) { if (promptResult?.value == true) { - preferences.allowWidgetCapabilityPermissions(runner.client.identifier, - runner.info.namespace, [autoAcceptConfirmationKey]); + preferences.allowWidgetCapabilityPermissions( + runner.client.identifier, + runner.info.namespace, + [autoAcceptConfirmationKey], + ); } if (promptResult?.value == false) { preferences.rejectWidgetCapabilityPermissions( - runner.client.identifier, - runner.info.namespace, - [autoAcceptConfirmationKey]); + runner.client.identifier, + runner.info.namespace, + [autoAcceptConfirmationKey], + ); } } @@ -103,25 +117,34 @@ class MatrixCapabilityOIDC implements MatrixWidgetCapability { if (result == true) { var room = runner.room!; - final token = await room.matrixRoom.client - .requestOpenIdToken(room.matrixRoom.client.userID!, {}); - - runner.messageTransport.send(runner.eventHandler - .generateToWidgetEvent(action: "openid_credentials", data: { - "state": "allowed", - "original_request_id": requestId, - "access_token": token.accessToken, - "token_type": token.tokenType, - "matrix_server_name": token.matrixServerName, - "expires_in": token.expiresIn, - })); + final token = await room.matrixRoom.client.requestOpenIdToken( + room.matrixRoom.client.userID!, + {}, + ); + + runner.messageTransport.send( + runner.eventHandler.generateToWidgetEvent( + action: "openid_credentials", + data: { + "state": "allowed", + "original_request_id": requestId, + "access_token": token.accessToken, + "token_type": token.tokenType, + "matrix_server_name": token.matrixServerName, + "expires_in": token.expiresIn, + }, + ), + ); return; } - runner.messageTransport.send(runner.eventHandler.generateToWidgetEvent( + runner.messageTransport.send( + runner.eventHandler.generateToWidgetEvent( action: "openid_credentials", - data: {"state": "blocked", "original_request_id": requestId})); + data: {"state": "blocked", "original_request_id": requestId}, + ), + ); } @override diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_read_relations.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_read_relations.dart index 8f0f10cc7..1c4e911c3 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_read_relations.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_read_relations.dart @@ -14,9 +14,9 @@ class MatrixCapabilityReadEventRelations implements MatrixWidgetCapability { static const String name = "org.matrix.msc3869.read_relations"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, - (runner, type, key) => - MatrixCapabilityReadEventRelations(runner: runner)); + name, + (runner, type, key) => MatrixCapabilityReadEventRelations(runner: runner), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; @@ -50,8 +50,9 @@ class MatrixCapabilityReadEventRelations implements MatrixWidgetCapability { if (capabilities.canWidgetReadEvent(event) == false) { return message.createResponseError( - message: - "Rejected: Cannot read type of requested event: ${event.eventId} (${event.type})"); + message: + "Rejected: Cannot read type of requested event: ${event.eventId} (${event.type})", + ); } var relType = message.data.tryGet("rel_type"); @@ -74,8 +75,14 @@ class MatrixCapabilityReadEventRelations implements MatrixWidgetCapability { if (requestEventType != null && relType != null) { var result = await runner.room!.matrixRoom.client .getRelatingEventsWithRelTypeAndEventType( - runner.room!.identifier, eventId, relType, requestEventType, - from: from, to: to, limit: limit); + runner.room!.identifier, + eventId, + relType, + requestEventType, + from: from, + to: to, + limit: limit, + ); chunk = result.chunk; prevBatch = result.prevBatch; @@ -83,16 +90,25 @@ class MatrixCapabilityReadEventRelations implements MatrixWidgetCapability { } else if (relType != null) { var result = await runner.room!.matrixRoom.client .getRelatingEventsWithRelType( - runner.room!.identifier, eventId, relType, - from: from, to: to, limit: limit); + runner.room!.identifier, + eventId, + relType, + from: from, + to: to, + limit: limit, + ); chunk = result.chunk; prevBatch = result.prevBatch; nextBatch = result.nextBatch; } else { var result = await runner.room!.matrixRoom.client.getRelatingEvents( - runner.room!.identifier, eventId, - from: from, to: to, limit: limit); + runner.room!.identifier, + eventId, + from: from, + to: to, + limit: limit, + ); chunk = result.chunk; prevBatch = result.prevBatch; @@ -102,8 +118,10 @@ class MatrixCapabilityReadEventRelations implements MatrixWidgetCapability { if (runner.room!.isE2EE) { for (var i = 0; i < chunk.length; i++) { try { - var ev = - matrix.Event.fromMatrixEvent(chunk[i], runner.room!.matrixRoom); + var ev = matrix.Event.fromMatrixEvent( + chunk[i], + runner.room!.matrixRoom, + ); chunk[i] = await runner.room!.matrixRoom.client.encryption! .decryptRoomEvent(ev); } catch (_) {} @@ -115,21 +133,25 @@ class MatrixCapabilityReadEventRelations implements MatrixWidgetCapability { } var allowedEvents = chunk.where((i) => capabilities.canWidgetReadEvent(i)); - var response = message.createResponseObject(response: { - "next_batch": nextBatch, - "prev_batch": prevBatch, - "chunk": allowedEvents - .map((i) => { + var response = message.createResponseObject( + response: { + "next_batch": nextBatch, + "prev_batch": prevBatch, + "chunk": allowedEvents + .map( + (i) => { "content": i.content, "sender": i.senderId, if (i.stateKey != null) "state_key": i.stateKey!, "type": i.type, "event_id": i.eventId, "origin_server_ts": i.originServerTs.millisecondsSinceEpoch, - "room_id": runner.room!.identifier - }) - .toList() - }); + "room_id": runner.room!.identifier, + }, + ) + .toList(), + }, + ); return response; } diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_receive_event.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_receive_event.dart index 93e8f255f..3a6844269 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_receive_event.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_receive_event.dart @@ -20,8 +20,11 @@ class MatrixCapabilityReceiveEvent implements MatrixWidgetCapability { StreamSubscription? sub; - MatrixCapabilityReceiveEvent( - {required this.runner, required this.eventType, this.eventKey}) { + MatrixCapabilityReceiveEvent({ + required this.runner, + required this.eventType, + this.eventKey, + }) { sub = runner.client.matrixClient.onTimelineEvent.stream.listen(onEvent); } @@ -33,29 +36,36 @@ class MatrixCapabilityReceiveEvent implements MatrixWidgetCapability { static const String name = "org.matrix.msc2762.receive.event"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, - (runner, type, key) => MatrixCapabilityReceiveEvent( - runner: runner, eventType: type!, eventKey: key)); + name, + (runner, type, key) => MatrixCapabilityReceiveEvent( + runner: runner, + eventType: type!, + eventKey: key, + ), + ); @override Future handleRequest(MatrixWidgetMessage message) async { - var timeline = (runner.room?.timeline ?? await runner.room!.getTimeline()) - as MatrixTimeline; + var timeline = + (runner.room?.timeline ?? await runner.room!.getTimeline()) + as MatrixTimeline; var events = timeline.matrixTimeline!.events; var filtered = events.where((i) => canGetEvent(i)); var result = filtered - .map((i) => { - "type": i.type, - "sender": i.senderId, - "content": i.content, - "origin_server_ts": i.originServerTs.millisecondsSinceEpoch, - if (i.unsigned != null) "unsigned": i.unsigned, - "event_id": i.eventId, - "room_id": i.roomId!, - }) + .map( + (i) => { + "type": i.type, + "sender": i.senderId, + "content": i.content, + "origin_server_ts": i.originServerTs.millisecondsSinceEpoch, + if (i.unsigned != null) "unsigned": i.unsigned, + "event_id": i.eventId, + "room_id": i.roomId!, + }, + ) .toList(); return message.createResponseObject(response: {"events": result}); @@ -98,15 +108,19 @@ class MatrixCapabilityReceiveEvent implements MatrixWidgetCapability { var i = event; runner.messageTransport.send( - runner.eventHandler.generateToWidgetEvent(action: "send_event", data: { - "type": i.type, - "sender": i.senderId, - "content": i.content, - "origin_server_ts": i.originServerTs.millisecondsSinceEpoch, - if (i.unsigned != null) "unsigned": i.unsigned, - "event_id": i.eventId, - "room_id": i.roomId!, - })); + runner.eventHandler.generateToWidgetEvent( + action: "send_event", + data: { + "type": i.type, + "sender": i.senderId, + "content": i.content, + "origin_server_ts": i.originServerTs.millisecondsSinceEpoch, + if (i.unsigned != null) "unsigned": i.unsigned, + "event_id": i.eventId, + "room_id": i.roomId!, + }, + ), + ); } bool canGetEvent(Event i) { diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_receive_state.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_receive_state.dart index 172d8c59a..e42b32490 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_receive_state.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_receive_state.dart @@ -17,8 +17,11 @@ class MatrixCapabilityReceiveStateEvent implements MatrixWidgetCapability { // If null, allow all keys String? eventKey; - MatrixCapabilityReceiveStateEvent( - {required this.runner, required this.eventType, this.eventKey}) { + MatrixCapabilityReceiveStateEvent({ + required this.runner, + required this.eventType, + this.eventKey, + }) { sub = runner.client.matrixClient.onRoomState.stream.listen(onEvent); Log.i("Created Receive State Event Capability"); @@ -29,9 +32,13 @@ class MatrixCapabilityReceiveStateEvent implements MatrixWidgetCapability { static String name = "org.matrix.msc2762.receive.state_event"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, - (runner, type, key) => MatrixCapabilityReceiveStateEvent( - runner: runner, eventType: type!, eventKey: key)); + name, + (runner, type, key) => MatrixCapabilityReceiveStateEvent( + runner: runner, + eventType: type!, + eventKey: key, + ), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; @@ -53,7 +60,8 @@ class MatrixCapabilityReceiveStateEvent implements MatrixWidgetCapability { if (type != eventType) return false; if (eventKey != null && - message.data.tryGet("state_key") != eventKey) return false; + message.data.tryGet("state_key") != eventKey) + return false; if (message.data.containsKey("state_key") == false) return false; @@ -64,14 +72,12 @@ class MatrixCapabilityReceiveStateEvent implements MatrixWidgetCapability { Future handleRequest(MatrixWidgetMessage message) async { var events = eventKey == null ? runner.room!.matrixRoom.states[eventType]?.entries - .map((i) => i.value) - .toList() + .map((i) => i.value) + .toList() : [runner.room!.matrixRoom.states[eventType]?[eventKey]]; if (events == null || events.nonNulls.isEmpty == true) { - return message.createResponseObject(response: { - "events": [], - }); + return message.createResponseObject(response: {"events": []}); } var key = message.data.tryGet("state_key"); @@ -81,12 +87,14 @@ class MatrixCapabilityReceiveStateEvent implements MatrixWidgetCapability { var finalEvents = events.nonNulls; - return message - .createResponseObject(response: {"events": convertEvents(finalEvents)}); + return message.createResponseObject( + response: {"events": convertEvents(finalEvents)}, + ); } List> convertEvents( - Iterable events) { + Iterable events, + ) { return events.map((i) { if (i is Event) { return { @@ -97,7 +105,7 @@ class MatrixCapabilityReceiveStateEvent implements MatrixWidgetCapability { "event_id": i.eventId, if (i.unsigned != null) "unsigned": i.unsigned, "origin_server_ts": i.originServerTs.millisecondsSinceEpoch, - "room_id": runner.room!.identifier + "room_id": runner.room!.identifier, }; } else if (i is User) { return { @@ -105,7 +113,7 @@ class MatrixCapabilityReceiveStateEvent implements MatrixWidgetCapability { "sender": i.senderId, "state_key": i.stateKey!, "type": i.type, - "room_id": runner.room!.identifier + "room_id": runner.room!.identifier, }; } else { throw UnimplementedError(); @@ -127,15 +135,19 @@ class MatrixCapabilityReceiveStateEvent implements MatrixWidgetCapability { Log.i("Received new state event, notifying widget"); runner.messageTransport.send( - runner.eventHandler.generateToWidgetEvent(action: "send_event", data: { - "type": i.type, - "sender": i.senderId, - "content": i.content, - "origin_server_ts": i.originServerTs.millisecondsSinceEpoch, - if (i.unsigned != null) "unsigned": i.unsigned, - "event_id": i.eventId, - "room_id": i.roomId!, - })); + runner.eventHandler.generateToWidgetEvent( + action: "send_event", + data: { + "type": i.type, + "sender": i.senderId, + "content": i.content, + "origin_server_ts": i.originServerTs.millisecondsSinceEpoch, + if (i.unsigned != null) "unsigned": i.unsigned, + "event_id": i.eventId, + "room_id": i.roomId!, + }, + ), + ); updateState(); } @@ -149,19 +161,26 @@ class MatrixCapabilityReceiveStateEvent implements MatrixWidgetCapability { Log.i("Sending initial state: $eventType"); var events = eventKey == null ? runner.room!.matrixRoom.states[eventType]?.entries - .map((i) => i.value) - .toList() + .map((i) => i.value) + .toList() : [runner.room!.matrixRoom.states[eventType]?[eventKey]]; if (events == null || events.nonNulls.isEmpty == true) { - runner.messageTransport.send(runner.eventHandler - .generateToWidgetEvent(action: "update_state", data: {"state": []})); + runner.messageTransport.send( + runner.eventHandler.generateToWidgetEvent( + action: "update_state", + data: {"state": []}, + ), + ); return; } - runner.messageTransport.send(runner.eventHandler.generateToWidgetEvent( + runner.messageTransport.send( + runner.eventHandler.generateToWidgetEvent( action: "update_state", - data: {"state": convertEvents(events.nonNulls)})); + data: {"state": convertEvents(events.nonNulls)}, + ), + ); } } diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_receive_to_device.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_receive_to_device.dart index c0563272c..9f8c75dd9 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_receive_to_device.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_receive_to_device.dart @@ -16,18 +16,26 @@ class MatrixCapabilityReceiveToDeviceEvent implements MatrixWidgetCapability { StreamSubscription? sub; - MatrixCapabilityReceiveToDeviceEvent( - {required this.runner, required this.eventType, this.eventKey}) { - sub = runner.client.matrixClient.onToDeviceEvent.stream - .listen(onToDeviceMessage); + MatrixCapabilityReceiveToDeviceEvent({ + required this.runner, + required this.eventType, + this.eventKey, + }) { + sub = runner.client.matrixClient.onToDeviceEvent.stream.listen( + onToDeviceMessage, + ); } static String name = "org.matrix.msc3819.receive.to_device"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, - (runner, type, key) => MatrixCapabilityReceiveToDeviceEvent( - runner: runner, eventType: type!, eventKey: key)); + name, + (runner, type, key) => MatrixCapabilityReceiveToDeviceEvent( + runner: runner, + eventType: type!, + eventKey: key, + ), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; @@ -53,13 +61,17 @@ class MatrixCapabilityReceiveToDeviceEvent implements MatrixWidgetCapability { Log.i("Sending to device event to widget!"); - runner.messageTransport.send(runner.eventHandler - .generateToWidgetEvent(action: "send_to_device", data: { - "type": event.type, - "sender": event.senderId, - "encrypted": event.encryptedContent != null, - "content": event.content - })); + runner.messageTransport.send( + runner.eventHandler.generateToWidgetEvent( + action: "send_to_device", + data: { + "type": event.type, + "sender": event.senderId, + "encrypted": event.encryptedContent != null, + "content": event.content, + }, + ), + ); } @override diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_send_event.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_send_event.dart index 7a3e1a804..d4d041926 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_send_event.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_send_event.dart @@ -11,15 +11,22 @@ class MatrixCapabilitySendEvent implements MatrixWidgetCapability { String eventType; String? eventKey; - MatrixCapabilitySendEvent( - {required this.runner, required this.eventType, this.eventKey}); + MatrixCapabilitySendEvent({ + required this.runner, + required this.eventType, + this.eventKey, + }); static const String name = "org.matrix.msc2762.send.event"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, - (runner, type, key) => MatrixCapabilitySendEvent( - runner: runner, eventType: type!, eventKey: key)); + name, + (runner, type, key) => MatrixCapabilitySendEvent( + runner: runner, + eventType: type!, + eventKey: key, + ), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; @@ -61,10 +68,9 @@ class MatrixCapabilitySendEvent implements MatrixWidgetCapability { var id = await runner.room!.matrixRoom.sendEvent(content, type: eventType); - return message.createResponseObject(response: { - "room_id": runner.room!.identifier, - "event_id": id!, - }); + return message.createResponseObject( + response: {"room_id": runner.room!.identifier, "event_id": id!}, + ); } @override diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_send_state.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_send_state.dart index c27e15460..18d71cfc6 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_send_state.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_send_state.dart @@ -21,15 +21,22 @@ class MatrixCapabilitySendStateEvent implements MatrixWidgetCapability { String eventType; String? eventKey; - MatrixCapabilitySendStateEvent( - {required this.runner, required this.eventType, this.eventKey}); + MatrixCapabilitySendStateEvent({ + required this.runner, + required this.eventType, + this.eventKey, + }); static String name = "org.matrix.msc2762.send.state_event"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, - (runner, type, key) => MatrixCapabilitySendStateEvent( - runner: runner, eventType: type!, eventKey: key)); + name, + (runner, type, key) => MatrixCapabilitySendStateEvent( + runner: runner, + eventType: type!, + eventKey: key, + ), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; @@ -110,48 +117,51 @@ class MatrixCapabilitySendStateEvent implements MatrixWidgetCapability { throw Exception("Request denied"); } - final result = await runner.room!.matrixRoom.client.request(RequestType.PUT, - "/client/v3/rooms/${Uri.encodeComponent(runner.room!.matrixRoom.id)}/state/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(key!)}", - contentType: "application/json", - data: jsonEncode(content), - query: { - if (delay != null) "org.matrix.msc4140.delay": delay.toString() - }); + final result = await runner.room!.matrixRoom.client.request( + RequestType.PUT, + "/client/v3/rooms/${Uri.encodeComponent(runner.room!.matrixRoom.id)}/state/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(key!)}", + contentType: "application/json", + data: jsonEncode(content), + query: {if (delay != null) "org.matrix.msc4140.delay": delay.toString()}, + ); if (delay != null) { - runner.messageTransport.send(runner.eventHandler - .generateToWidgetEvent(action: "send_event", data: { - "content": content, - "sender": runner.client.self!.identifier, - "state_key": key, - "type": eventType, - "event_id": result, - "origin_server_ts": DateTime.now().millisecondsSinceEpoch, - "room_id": runner.room!.identifier - })); + runner.messageTransport.send( + runner.eventHandler.generateToWidgetEvent( + action: "send_event", + data: { + "content": content, + "sender": runner.client.self!.identifier, + "state_key": key, + "type": eventType, + "event_id": result, + "origin_server_ts": DateTime.now().millisecondsSinceEpoch, + "room_id": runner.room!.identifier, + }, + ), + ); } if (delay != null) { - Log.i( - "Got delayed event result: ${result}", + Log.i("Got delayed event result: ${result}"); + return message.createResponseObject( + response: { + "room_id": runner.room!.identifier, + "delay_id": result["delay_id"], + }, ); - return message.createResponseObject(response: { - "room_id": runner.room!.identifier, - "delay_id": result["delay_id"] - }); } return message.createResponseObject( - response: {"room_id": runner.room!.identifier, "event_id": result}); + response: {"room_id": runner.room!.identifier, "event_id": result}, + ); } @override void dispose() { - WidgetsBinding.instance.addPostFrameCallback( - (timeStamp) { - cleanUpCallMemberships(); - }, - ); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + cleanUpCallMemberships(); + }); } Future cleanUpCallMemberships() async { @@ -170,8 +180,12 @@ class MatrixCapabilitySendStateEvent implements MatrixWidgetCapability { if (current == null) return; if (current.content.isNotEmpty) { - await runner.client.matrixClient - .setRoomStateWithKey(runner.room!.identifier, type, key, {}); + await runner.client.matrixClient.setRoomStateWithKey( + runner.room!.identifier, + type, + key, + {}, + ); } } } diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_send_to_device.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_send_to_device.dart index c8e24f1c5..829914c31 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_send_to_device.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_send_to_device.dart @@ -11,15 +11,22 @@ class MatrixCapabilitySendToDeviceEvent implements MatrixWidgetCapability { String eventType; String? eventKey; - MatrixCapabilitySendToDeviceEvent( - {required this.runner, required this.eventType, this.eventKey}); + MatrixCapabilitySendToDeviceEvent({ + required this.runner, + required this.eventType, + this.eventKey, + }); static String name = "org.matrix.msc3819.send.to_device"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, - (runner, type, key) => MatrixCapabilitySendToDeviceEvent( - runner: runner, eventType: type!, eventKey: key)); + name, + (runner, type, key) => MatrixCapabilitySendToDeviceEvent( + runner: runner, + eventType: type!, + eventKey: key, + ), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; @@ -71,12 +78,18 @@ class MatrixCapabilitySendToDeviceEvent implements MatrixWidgetCapability { if (encrypted) { for (var user in map.entries) { for (var device in user.value.entries) { - final deviceKey = runner.client.matrixClient.userDeviceKeys[user.key] + final deviceKey = runner + .client + .matrixClient + .userDeviceKeys[user.key] ?.deviceKeys[device.key]; if (deviceKey != null) { - await runner.client.matrixClient - .sendToDeviceEncrypted([deviceKey], eventType, device.value); + await runner.client.matrixClient.sendToDeviceEncrypted( + [deviceKey], + eventType, + device.value, + ); } } } diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_sticky_events.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_sticky_events.dart index 3ad665b24..9b756a149 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_sticky_events.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_sticky_events.dart @@ -11,8 +11,10 @@ class MatrixCapabilitySendStickyEvent implements MatrixWidgetCapability { static const String name = "org.matrix.msc4407.send.sticky_event"; - static MatrixWidgetCapabilityConstructorEntry entry = MapEntry(name, - (runner, type, key) => MatrixCapabilitySendStickyEvent(runner: runner)); + static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( + name, + (runner, type, key) => MatrixCapabilitySendStickyEvent(runner: runner), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; @@ -45,9 +47,9 @@ class MatrixCapabilityReceiveStickyEvent implements MatrixWidgetCapability { static const String name = "org.matrix.msc4407.receive.sticky_event"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, - (runner, type, key) => - MatrixCapabilityReceiveStickyEvent(runner: runner)); + name, + (runner, type, key) => MatrixCapabilityReceiveStickyEvent(runner: runner), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_theme.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_theme.dart index 7ee0ea779..7245caee9 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_theme.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_theme.dart @@ -20,7 +20,9 @@ class MatrixCapabilityTheme implements MatrixWidgetCapability { static const String name = "org.matrix.msc2873.client_theme"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, (runner, type, key) => MatrixCapabilityTheme(runner: runner)); + name, + (runner, type, key) => MatrixCapabilityTheme(runner: runner), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; @@ -46,10 +48,14 @@ class MatrixCapabilityTheme implements MatrixWidgetCapability { } void onThemeChanged(ThemeData event) { - runner.messageTransport.send(runner.eventHandler - .generateToWidgetEvent(action: "theme_change", data: { - "name": event.brightness == Brightness.light ? "light" : "dark", - "chat.commet.color_scheme": event.colorScheme.toJson(), - })); + runner.messageTransport.send( + runner.eventHandler.generateToWidgetEvent( + action: "theme_change", + data: { + "name": event.brightness == Brightness.light ? "light" : "dark", + "chat.commet.color_scheme": event.colorScheme.toJson(), + }, + ), + ); } } diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_timeline.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_timeline.dart index deace3a8e..a234fb4f0 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_timeline.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_timeline.dart @@ -14,9 +14,10 @@ class MatrixCapabilityTimeline implements MatrixWidgetCapability { static const String name = "org.matrix.msc2762.timeline"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, - (runner, type, key) => - MatrixCapabilityTimeline(roomId: type!, runner: runner)); + name, + (runner, type, key) => + MatrixCapabilityTimeline(roomId: type!, runner: runner), + ); static String getNameForType(String eventType, String? key) => key == null ? "$name:$eventType" : "$name:$eventType#$key"; diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_turn_servers.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_turn_servers.dart index 25854f687..423a81695 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_turn_servers.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_turn_servers.dart @@ -12,7 +12,9 @@ class MatrixCapabilityTurnServers implements MatrixWidgetCapability { static String name = "town.robin.msc3846.turn_servers"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, (runner, type, key) => MatrixCapabilityTurnServers(runner: runner)); + name, + (runner, type, key) => MatrixCapabilityTurnServers(runner: runner), + ); @override String toString() { @@ -28,13 +30,16 @@ class MatrixCapabilityTurnServers implements MatrixWidgetCapability { Future handleRequest(MatrixWidgetMessage message) async { if (message.action == "watch_turn_servers") { runner.client.matrixClient.getTurnServer().then((config) async { - runner.messageTransport.send(runner.eventHandler.generateToWidgetEvent( + runner.messageTransport.send( + runner.eventHandler.generateToWidgetEvent( action: "update_turn_servers", data: { "uris": config.uris, "username": config.username, - "password": config.password - })); + "password": config.password, + }, + ), + ); }); return message.createResponseObject(); diff --git a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_upload_file.dart b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_upload_file.dart index 8603846e4..384dac50b 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_upload_file.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/mx_capability_upload_file.dart @@ -20,8 +20,10 @@ class MatrixCapabilityUploadFile implements MatrixWidgetCapability { static const String name = "org.matrix.msc4039.upload_file"; - static MatrixWidgetCapabilityConstructorEntry entry = - MapEntry(name, (runner, type, key) => MatrixCapabilityUploadFile(runner)); + static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( + name, + (runner, type, key) => MatrixCapabilityUploadFile(runner), + ); @override Future handleRequest(MatrixWidgetMessage message) async { @@ -35,7 +37,9 @@ class MatrixCapabilityUploadFile implements MatrixWidgetCapability { Log.d("Upload finished!"); return message.createResponseObject( - data: {}, response: {"content_uri": result.toString()}); + data: {}, + response: {"content_uri": result.toString()}, + ); } else { return message.createResponseError(message: "Invalid message"); } diff --git a/commet/lib/client/matrix/components/widgets/capabilities/voip_state_capability.dart b/commet/lib/client/matrix/components/widgets/capabilities/voip_state_capability.dart index 70c32770f..fd05e945d 100644 --- a/commet/lib/client/matrix/components/widgets/capabilities/voip_state_capability.dart +++ b/commet/lib/client/matrix/components/widgets/capabilities/voip_state_capability.dart @@ -30,7 +30,9 @@ class MatrixCapabilityVoipState implements MatrixWidgetCapability { static String name = "chat.commet.voip_overlay.voip_state"; static MatrixWidgetCapabilityConstructorEntry entry = MapEntry( - name, (runner, type, key) => MatrixCapabilityVoipState(runner: runner)); + name, + (runner, type, key) => MatrixCapabilityVoipState(runner: runner), + ); @override String toString() { @@ -56,8 +58,9 @@ class MatrixCapabilityVoipState implements MatrixWidgetCapability { subs.addAll([ session.onStateChanged.listen((_) => onSessionStateChanged(session)), - session.onUpdateVolumeVisualizers - .listen((_) => onSessionStateChanged(session)) + session.onUpdateVolumeVisualizers.listen( + (_) => onSessionStateChanged(session), + ), ]); sendCurrentState(); @@ -94,15 +97,14 @@ class MatrixCapabilityVoipState implements MatrixWidgetCapability { var str = jsonEncode(state); if (str != lastState) { - Log.i( - "Current voip state: ${state}", - ); + Log.i("Current voip state: ${state}"); - runner.messageTransport.send(runner.eventHandler.generateToWidgetEvent( + runner.messageTransport.send( + runner.eventHandler.generateToWidgetEvent( action: "chat.commet.voip_overlay.voip_state", - data: { - "state": state, - })); + data: {"state": state}, + ), + ); lastState = str; } else { diff --git a/commet/lib/client/matrix/components/widgets/matrix_widget_capabilities_manager.dart b/commet/lib/client/matrix/components/widgets/matrix_widget_capabilities_manager.dart index 2f1ff7f92..bca290df3 100644 --- a/commet/lib/client/matrix/components/widgets/matrix_widget_capabilities_manager.dart +++ b/commet/lib/client/matrix/components/widgets/matrix_widget_capabilities_manager.dart @@ -29,10 +29,13 @@ import 'package:matrix/matrix_api_lite/utils/try_get_map_extension.dart'; import 'package:matrix/matrix.dart' as matrix; typedef MatrixWidgetCapability MatrixCapabilityConstructor( - MatrixWidgetRunner runner, String? type, String? key); + MatrixWidgetRunner runner, + String? type, + String? key, +); -typedef MatrixWidgetCapabilityConstructorEntry - = MapEntry; +typedef MatrixWidgetCapabilityConstructorEntry = + MapEntry; class MatrixWidgetCapabilitiesManager implements WidgetCapabilityManager { @@ -40,16 +43,20 @@ class MatrixWidgetCapabilitiesManager Set rejectedCapabilities = {}; @override - NotifyingList grantedCapabilityNames = - NotifyingList.empty(growable: true); + NotifyingList grantedCapabilityNames = NotifyingList.empty( + growable: true, + ); MatrixWidgetRunner runner; final BuildContext context; final bool privileged; - MatrixWidgetCapabilitiesManager( - {required this.runner, required this.context, this.privileged = false}) { + MatrixWidgetCapabilitiesManager({ + required this.runner, + required this.context, + this.privileged = false, + }) { runner.onClosed.listen((_) { dispose(); }); @@ -74,9 +81,13 @@ class MatrixWidgetCapabilitiesManager List allowed = List.empty(growable: true); var rejected = await preferences.getRejectedWidgetCapabilities( - runner.client.identifier, runner.info.namespace); + runner.client.identifier, + runner.info.namespace, + ); var accepted = await preferences.getAcceptedWidgetCapabilities( - runner.client.identifier, runner.info.namespace); + runner.client.identifier, + runner.info.namespace, + ); for (var c in rejected) { needsPermission.remove(c); @@ -88,9 +99,7 @@ class MatrixWidgetCapabilitiesManager } for (var defaultcapability in defaultCapabilities) { - Log.i( - "Allowing capability by default: $defaultcapability", - ); + Log.i("Allowing capability by default: $defaultcapability"); allowed.add(defaultcapability); needsPermission.remove(defaultcapability); @@ -100,8 +109,12 @@ class MatrixWidgetCapabilitiesManager if (canCreateCapability(capability) == false) { needsPermission.remove(capability); - runner.logs.add(LogEntry(LogType.error, - "Cannot handle capability: $capability, rejecting by default")); + runner.logs.add( + LogEntry( + LogType.error, + "Cannot handle capability: $capability, rejecting by default", + ), + ); Log.w("Cannot handle capability: $capability, rejecting by default"); if (rejectedCapabilities.contains(capability) == false) { @@ -114,16 +127,18 @@ class MatrixWidgetCapabilitiesManager if (privileged) { allowed.addAll(needsPermission); } else { - var groups = - MatrixWidgetPermissionGroup.groupPermissions(needsPermission); + var groups = MatrixWidgetPermissionGroup.groupPermissions( + needsPermission, + ); var picked = await AdaptiveDialog.show>>( navigator.currentContext!, title: "Widget Permissions", builder: (context) => MatrixWidgetPermissionsView( - runner: runner, - groupedPermissions: groups.$1, - ungrouped: groups.$2), + runner: runner, + groupedPermissions: groups.$1, + ungrouped: groups.$2, + ), ); if (picked != null) { @@ -135,10 +150,16 @@ class MatrixWidgetCapabilitiesManager if (picked.remember) { preferences.allowWidgetCapabilityPermissions( - runner.client.identifier, runner.info.namespace, picked.value); + runner.client.identifier, + runner.info.namespace, + picked.value, + ); preferences.rejectWidgetCapabilityPermissions( - runner.client.identifier, runner.info.namespace, rejected); + runner.client.identifier, + runner.info.namespace, + rejected, + ); } } } @@ -159,21 +180,28 @@ class MatrixWidgetCapabilitiesManager } void notifyCapabilities(List requested) { - List approved = - List.from(grantedCapabilities.keys.toList(), growable: true); + List approved = List.from( + grantedCapabilities.keys.toList(), + growable: true, + ); if (approved.contains("io.element.requires_client") == false) { approved.add("io.element.requires_client"); } - runner.messageTransport.send(runner.eventHandler.generateToWidgetEvent( + runner.messageTransport.send( + runner.eventHandler.generateToWidgetEvent( action: "notify_capabilities", - data: {"requested": requested, "approved": approved})); + data: {"requested": requested, "approved": approved}, + ), + ); } - static Map - capabilityBuilders = Map.fromEntries([ + static Map< + String, + MatrixWidgetCapability Function(MatrixWidgetRunner, String?, String?) + > + capabilityBuilders = Map.fromEntries([ MatrixCapabilityReceiveEvent.entry, MatrixCapabilitySendEvent.entry, MatrixCapabilityUploadFile.entry, @@ -219,7 +247,10 @@ class MatrixWidgetCapabilitiesManager if (builders.containsKey(parsed.capability)) { var created = builders[parsed.capability]!( - runner, parsed.eventType, parsed.eventKey); + runner, + parsed.eventType, + parsed.eventKey, + ); grantedCapabilities[name] = created; granted.add(name); @@ -239,9 +270,11 @@ class MatrixWidgetCapabilitiesManager Log.i(g); } - var unknown = capabilities.where((i) => - grantedCapabilities.containsKey(i) == false && - rejectedCapabilities.contains(i) == false); + var unknown = capabilities.where( + (i) => + grantedCapabilities.containsKey(i) == false && + rejectedCapabilities.contains(i) == false, + ); Log.w("Unhandled Capabilities"); for (var g in unknown) { @@ -280,7 +313,7 @@ class MatrixWidgetCapabilitiesManager data: { "type": event.type, if (msgType != null) "msgtype": msgType, - if (event.stateKey != null) "state_key": event.stateKey + if (event.stateKey != null) "state_key": event.stateKey, }, ); @@ -318,7 +351,8 @@ class MatrixWidgetCapabilitiesManager } return event.createResponseError( - message: "Unhandled widget request ${event.action}\n${event.data}"); + message: "Unhandled widget request ${event.action}\n${event.data}", + ); } @override diff --git a/commet/lib/client/matrix/components/widgets/matrix_widget_component.dart b/commet/lib/client/matrix/components/widgets/matrix_widget_component.dart index f0cdf8cdc..b365ae9c2 100644 --- a/commet/lib/client/matrix/components/widgets/matrix_widget_component.dart +++ b/commet/lib/client/matrix/components/widgets/matrix_widget_component.dart @@ -122,7 +122,8 @@ class MatrixWidgetComponent implements WidgetComponent { url = Uri.encodeFull(url); - result.add(MatrixUserWidgetInfo( + result.add( + MatrixUserWidgetInfo( id: id, name: name, stateKey: s.key, @@ -130,7 +131,9 @@ class MatrixWidgetComponent implements WidgetComponent { type: type, roomId: room.identifier, event: s.value, - icon: icon)); + icon: icon, + ), + ); } return result; @@ -141,8 +144,9 @@ class MatrixWidgetComponent implements WidgetComponent { WidgetComponent.currentSessions.add(runner); - runner.onClosed - .listen((_) => WidgetComponent.currentSessions.remove(runner)); + runner.onClosed.listen( + (_) => WidgetComponent.currentSessions.remove(runner), + ); } @override @@ -172,7 +176,7 @@ class MatrixWidgetComponent implements WidgetComponent { return const [ WidgetHostType.childProcess, WidgetHostType.embedded, - WidgetHostType.remoteHttpClient + WidgetHostType.remoteHttpClient, ]; } @@ -196,8 +200,11 @@ class MatrixWidgetComponent implements WidgetComponent { @override Future openWidget( - UserWidgetInfo widget, Room room, BuildContext context, - {WidgetHostType? type}) async { + UserWidgetInfo widget, + Room room, + BuildContext context, { + WidgetHostType? type, + }) async { ErrorUtils.tryRun(context, () async { var info = widget as MatrixUserWidgetInfo; var url = Uri.encodeFull(info.url); @@ -209,8 +216,10 @@ class MatrixWidgetComponent implements WidgetComponent { "\$matrix_display_name": room.client.self!.displayName, "\$org.matrix.msc3819.matrix_device_id": (room.client as MatrixClient).matrixClient.deviceID!, - "\$org.matrix.msc4039.matrix_base_url": - (room.client as MatrixClient).matrixClient.baseUri.toString(), + "\$org.matrix.msc4039.matrix_base_url": (room.client as MatrixClient) + .matrixClient + .baseUri + .toString(), "\$chat.commet.color_scheme": Uri.encodeComponent(colorScheme), "\$org.matrix.msc2873.client_theme": Theme.of(context).brightness == Brightness.light ? "light" : "dark", @@ -225,16 +234,17 @@ class MatrixWidgetComponent implements WidgetComponent { var uri = Uri.parse(url); uri = Uri( - scheme: uri.scheme, - host: uri.host, - port: uri.port, - path: uri.path, - fragment: uri.fragment.isEmpty ? null : uri.fragment, - queryParameters: { - ...uri.queryParameters, - "parentUrl": "commet://widget", - "widgetId": info.id, - }); + scheme: uri.scheme, + host: uri.host, + port: uri.port, + path: uri.path, + fragment: uri.fragment.isEmpty ? null : uri.fragment, + queryParameters: { + ...uri.queryParameters, + "parentUrl": "commet://widget", + "widgetId": info.id, + }, + ); url = uri.toString(); @@ -258,49 +268,66 @@ class MatrixWidgetComponent implements WidgetComponent { } uri = Uri( - scheme: uri.scheme, - host: uri.host, - port: uri.port, - path: uri.path, - fragment: uri.fragment.isEmpty ? null : uri.fragment, - queryParameters: { - ...uri.queryParameters, - "parentUrl": server == null - ? "http://localhost/widget" - : "http://localhost:${server.port}", - "widgetId": info.id, - }); + scheme: uri.scheme, + host: uri.host, + port: uri.port, + path: uri.path, + fragment: uri.fragment.isEmpty ? null : uri.fragment, + queryParameters: { + ...uri.queryParameters, + "parentUrl": server == null + ? "http://localhost/widget" + : "http://localhost:${server.port}", + "widgetId": info.id, + }, + ); url = uri.toString(); - await createEmbeddedWidget(url, info, widget, room, context, - server: server); + await createEmbeddedWidget( + url, + info, + widget, + room, + context, + server: server, + ); return; case WidgetHostType.childProcess: await spawnChildProcess(url, room, widget); return; case WidgetHostType.remoteHttpClient: - await createRemoteHttpWidgetRunner(url, room, widget, - useInsecureHttp: false, allowRemoteConnection: true); + await createRemoteHttpWidgetRunner( + url, + room, + widget, + useInsecureHttp: false, + allowRemoteConnection: true, + ); return; case WidgetHostType.externalBrowser: - await createRemoteHttpWidgetRunner(url, room, widget, - launchBrowser: true, - useInsecureHttp: true, - allowRemoteConnection: false); + await createRemoteHttpWidgetRunner( + url, + room, + widget, + launchBrowser: true, + useInsecureHttp: true, + allowRemoteConnection: false, + ); return; case WidgetHostType.androidActivity: uri = Uri( - scheme: uri.scheme, - host: uri.host, - port: uri.port, - path: uri.path, - fragment: uri.fragment.isEmpty ? null : uri.fragment, - queryParameters: { - ...uri.queryParameters, - "parentUrl": "http://localhost/widget", - "widgetId": info.id, - }); + scheme: uri.scheme, + host: uri.host, + port: uri.port, + path: uri.path, + fragment: uri.fragment.isEmpty ? null : uri.fragment, + queryParameters: { + ...uri.queryParameters, + "parentUrl": "http://localhost/widget", + "widgetId": info.id, + }, + ); url = uri.toString(); createAndroidActivityWidget(url, widget, room, context); @@ -309,16 +336,19 @@ class MatrixWidgetComponent implements WidgetComponent { }); } - Future createAndroidActivityWidget(String url, - MatrixUserWidgetInfo info, Room room, BuildContext context) async { + Future createAndroidActivityWidget( + String url, + MatrixUserWidgetInfo info, + Room room, + BuildContext context, + ) async { var receiveSocketPath = await AppConfig.getWidgetSocketPath(); var file = File(receiveSocketPath); - var bytes = - (await rootBundle.load("assets/data/widget_runner_android.html")) - .buffer - .asUint8List(); + var bytes = (await rootBundle.load( + "assets/data/widget_runner_android.html", + )).buffer.asUint8List(); var text = Utf8Decoder().convert(bytes); @@ -327,8 +357,10 @@ class MatrixWidgetComponent implements WidgetComponent { .asUint8List(); var scriptText = Utf8Decoder().convert(scriptBytes); - text = - text.replaceAll("\$RUNNER_PAGE_TITLE", "Commet Widget | ${info.name}"); + text = text.replaceAll( + "\$RUNNER_PAGE_TITLE", + "Commet Widget | ${info.name}", + ); text = text.replaceAll("\$IFRAME_URL", url.toString()); text = text.replaceAll("\$WIDGET_ID", info.id); @@ -352,23 +384,28 @@ class MatrixWidgetComponent implements WidgetComponent { }); var runner = MatrixWidgetAndroidRunner( - room: room as MatrixRoom, - widgetId: info.id, - client: room.client as MatrixClient, - info: info, - socket: server, - context: context); + room: room as MatrixRoom, + widgetId: info.id, + client: room.client as MatrixClient, + info: info, + socket: server, + context: context, + ); registerRunner(runner); } - Future createEmbeddedWidget(String url, MatrixUserWidgetInfo info, - MatrixUserWidgetInfo widget, Room room, BuildContext context, - {HttpServer? server}) async { - var bytes = - (await rootBundle.load("assets/data/widget_runner_embedded.html")) - .buffer - .asUint8List(); + Future createEmbeddedWidget( + String url, + MatrixUserWidgetInfo info, + MatrixUserWidgetInfo widget, + Room room, + BuildContext context, { + HttpServer? server, + }) async { + var bytes = (await rootBundle.load( + "assets/data/widget_runner_embedded.html", + )).buffer.asUint8List(); var text = Utf8Decoder().convert(bytes); @@ -377,8 +414,10 @@ class MatrixWidgetComponent implements WidgetComponent { .asUint8List(); var scriptText = Utf8Decoder().convert(scriptBytes); - text = - text.replaceAll("\$RUNNER_PAGE_TITLE", "Commet Widget | ${info.name}"); + text = text.replaceAll( + "\$RUNNER_PAGE_TITLE", + "Commet Widget | ${info.name}", + ); text = text.replaceAll("\$IFRAME_URL", url.toString()); @@ -411,46 +450,56 @@ class MatrixWidgetComponent implements WidgetComponent { }); var builtWidget = MatrixWidgetInappwebviewRunnerWidget( - info: info, - widgetId: widget.id, - initialPageData: text, - onExitController: onExitController, - room: room as MatrixRoom, - server: server, - component: this); + info: info, + widgetId: widget.id, + initialPageData: text, + onExitController: onExitController, + room: room as MatrixRoom, + server: server, + component: this, + ); var window = OverlayWindow( - widget: builtWidget, - title: info.name, - onClose: onExitController.stream); + widget: builtWidget, + title: info.name, + onClose: onExitController.stream, + ); OverlayWindowsManager.of(context).addWindow(window); } Future spawnChildProcess( - String url, Room room, MatrixUserWidgetInfo widget) async { + String url, + Room room, + MatrixUserWidgetInfo widget, + ) async { var exe = Platform.resolvedExecutable; - var process = await Process.start( - exe, - ['--widget_runner', '--title="commet | Widget Runner"', '--url=${url}'], - ); + var process = await Process.start(exe, [ + '--widget_runner', + '--title="commet | Widget Runner"', + '--url=${url}', + ]); var runner = MatrixUserWidgetSubprocessRunner( - process: process, - room: room as MatrixRoom, - context: navigator.currentContext!, - widgetId: widget.id, - info: widget, - client: room.client as MatrixClient); + process: process, + room: room as MatrixRoom, + context: navigator.currentContext!, + widgetId: widget.id, + info: widget, + client: room.client as MatrixClient, + ); registerRunner(runner); } Future createRemoteHttpWidgetRunner( - String url, Room room, MatrixUserWidgetInfo widget, - {bool launchBrowser = false, - bool useInsecureHttp = false, - bool allowRemoteConnection = false}) async { + String url, + Room room, + MatrixUserWidgetInfo widget, { + bool launchBrowser = false, + bool useInsecureHttp = false, + bool allowRemoteConnection = false, + }) async { final info = NetworkInfo(); var ip = await info.getWifiIP(); @@ -482,28 +531,30 @@ class MatrixWidgetComponent implements WidgetComponent { Log.i("Hosted server: ${ip}"); var runner = MatrixUserWidgetRemoteHttpRunner( - room: room as MatrixRoom, - widgetId: widget.id, - client: client, - url: url, - info: widget, - server: server, - allowRemoteConnection: allowRemoteConnection, - launchBrowser: launchBrowser, - context: navigator.currentContext!, - useInsecureHttp: useInsecureHttp, - hostName: ip!); + room: room as MatrixRoom, + widgetId: widget.id, + client: client, + url: url, + info: widget, + server: server, + allowRemoteConnection: allowRemoteConnection, + launchBrowser: launchBrowser, + context: navigator.currentContext!, + useInsecureHttp: useInsecureHttp, + hostName: ip!, + ); registerRunner(runner); } @override - Future addWidget( - {required Uri url, - required Room room, - Uri? iconImageUrl, - String? widgetType, - String? widgetName}) async { + Future addWidget({ + required Uri url, + required Room room, + Uri? iconImageUrl, + String? widgetType, + String? widgetName, + }) async { var uuid = const Uuid(); var id = uuid.v4(); @@ -523,16 +574,24 @@ class MatrixWidgetComponent implements WidgetComponent { } await client.matrixClient.setRoomStateWithKey( - room.identifier, "im.vector.modular.widgets", id, content); + room.identifier, + "im.vector.modular.widgets", + id, + content, + ); } @override - Future removeWidget( - {required UserWidgetInfo widget, required Room room}) async { + Future removeWidget({ + required UserWidgetInfo widget, + required Room room, + }) async { await client.matrixClient.setRoomStateWithKey( - room.identifier, - "im.vector.modular.widgets", - (widget as MatrixUserWidgetInfo).stateKey, {}); + room.identifier, + "im.vector.modular.widgets", + (widget as MatrixUserWidgetInfo).stateKey, + {}, + ); } @override diff --git a/commet/lib/client/matrix/components/widgets/matrix_widget_message_handler.dart b/commet/lib/client/matrix/components/widgets/matrix_widget_message_handler.dart index ab7a4a80e..18026c8bb 100644 --- a/commet/lib/client/matrix/components/widgets/matrix_widget_message_handler.dart +++ b/commet/lib/client/matrix/components/widgets/matrix_widget_message_handler.dart @@ -32,9 +32,10 @@ class MatrixWidgetMessage { }; } - Map createResponse( - {Map data = const {}, - Map response = const {}}) { + Map createResponse({ + Map data = const {}, + Map response = const {}, + }) { return { "api": "fromWidget", "widgetId": widgetId, @@ -45,29 +46,34 @@ class MatrixWidgetMessage { }; } - MatrixWidgetMessage createResponseObject( - {Map data = const {}, - Map response = const {}}) { + MatrixWidgetMessage createResponseObject({ + Map data = const {}, + Map response = const {}, + }) { return MatrixWidgetMessage( - api: api, - widgetId: widgetId, - requestId: requestId, - action: action, - data: data.isEmpty ? this.data : data, - response: response); + api: api, + widgetId: widgetId, + requestId: requestId, + action: action, + data: data.isEmpty ? this.data : data, + response: response, + ); } - MatrixWidgetMessage createResponseError( - {Map data = const {}, required String message}) { + MatrixWidgetMessage createResponseError({ + Map data = const {}, + required String message, + }) { return MatrixWidgetMessage( - api: api, - widgetId: widgetId, - requestId: requestId, - action: action, - data: data.isEmpty ? this.data : data, - response: { - "error": {"message": message} - }); + api: api, + widgetId: widgetId, + requestId: requestId, + action: action, + data: data.isEmpty ? this.data : data, + response: { + "error": {"message": message}, + }, + ); } } @@ -96,11 +102,12 @@ class MatrixWidgetMessageHandler implements WidgetEventHandler { // This is a request initiated by the widget, to us if (api == "fromWidget") { var request = MatrixWidgetMessage( - api: api!, - requestId: requestId, - action: action, - data: messageData, - widgetId: runner.widgetId); + api: api!, + requestId: requestId, + action: action, + data: messageData, + widgetId: runner.widgetId, + ); final handler = defaultHandlers[action]; @@ -127,35 +134,35 @@ class MatrixWidgetMessageHandler implements WidgetEventHandler { if (capabilities != null) { var allowed = await runner.capabilities.requestCapabilities(capabilities); - var response = msg.createResponse(data: { - "capabilities": allowed, - }); + var response = msg.createResponse(data: {"capabilities": allowed}); runner.messageTransport.send(response); } } handleSupportedApiVersions(MatrixWidgetMessage msg) { - var response = msg.createResponse(response: { - "supported_versions": [ - "0.0.1", - "0.0.2", - "org.matrix.msc2762", // Read / Send Events - "org.matrix.msc2762_update_state", - "org.matrix.msc2871", // Capabilities Notifications - "org.matrix.msc2974", // Widgets: Capabilities re-exchange - "org.matrix.msc4039", // Access the Content repository with the Widget API - "town.robin.msc3846", // Allowing widgets to access TURN servers - "org.matrix.msc3819", // Allowing widgets to send/receive to-device messages - "org.matrix.msc3869", // Read event relations with the Widget API - if (BuildConfig.DEBUG) ...[ - "org.matrix.msc2873", // Identifying clients and user settings in widgets - "org.matrix.msc2931", // Allow widgets to navigate with matrix.to URIs - "org.matrix.msc2876", // Allowing widgets to read events in a room (Closed) - "org.matrix.msc3973", // Search users in the user directory with the Widget API - ] - ] - }); + var response = msg.createResponse( + response: { + "supported_versions": [ + "0.0.1", + "0.0.2", + "org.matrix.msc2762", // Read / Send Events + "org.matrix.msc2762_update_state", + "org.matrix.msc2871", // Capabilities Notifications + "org.matrix.msc2974", // Widgets: Capabilities re-exchange + "org.matrix.msc4039", // Access the Content repository with the Widget API + "town.robin.msc3846", // Allowing widgets to access TURN servers + "org.matrix.msc3819", // Allowing widgets to send/receive to-device messages + "org.matrix.msc3869", // Read event relations with the Widget API + if (BuildConfig.DEBUG) ...[ + "org.matrix.msc2873", // Identifying clients and user settings in widgets + "org.matrix.msc2931", // Allow widgets to navigate with matrix.to URIs + "org.matrix.msc2876", // Allowing widgets to read events in a room (Closed) + "org.matrix.msc3973", // Search users in the user directory with the Widget API + ], + ], + }, + ); runner.messageTransport.send(response); @@ -164,8 +171,12 @@ class MatrixWidgetMessageHandler implements WidgetEventHandler { Future sendInitialCapabilitiesRequest() async { Log.i("Sending initial capabilities request"); - var response = await runner.messageTransport.send(runner.eventHandler - .generateToWidgetEvent(action: "capabilities", data: {})); + var response = await runner.messageTransport.send( + runner.eventHandler.generateToWidgetEvent( + action: "capabilities", + data: {}, + ), + ); Log.i("Received response to initial capabilities!"); Log.i(response); @@ -185,14 +196,16 @@ class MatrixWidgetMessageHandler implements WidgetEventHandler { return "widgetapi-$requestNum"; } - Map generateToWidgetEvent( - {required String action, required Map data}) { + Map generateToWidgetEvent({ + required String action, + required Map data, + }) { return { "api": "toWidget", "widgetId": runner.widgetId, "requestId": generateRequestId(), "action": action, - "data": data + "data": data, }; } } diff --git a/commet/lib/client/matrix/components/widgets/matrix_widget_permission_groups.dart b/commet/lib/client/matrix/components/widgets/matrix_widget_permission_groups.dart index 3eb6d05f6..b4b14f36a 100644 --- a/commet/lib/client/matrix/components/widgets/matrix_widget_permission_groups.dart +++ b/commet/lib/client/matrix/components/widgets/matrix_widget_permission_groups.dart @@ -6,8 +6,12 @@ class MatrixWidgetCapabilityString { final String? eventType; final String? eventKey; - MatrixWidgetCapabilityString(this.capability, - {this.eventType, this.eventKey, required this.raw}); + MatrixWidgetCapabilityString( + this.capability, { + this.eventType, + this.eventKey, + required this.raw, + }); static MatrixWidgetCapabilityString parse(String name) { var split = name.split((":")); @@ -34,17 +38,16 @@ class MatrixWidgetCapabilityString { eventKey = eventTypeSplit.sublist(1).join("#"); } - return MatrixWidgetCapabilityString(parsedName, - eventType: eventType, eventKey: eventKey, raw: name); + return MatrixWidgetCapabilityString( + parsedName, + eventType: eventType, + eventKey: eventKey, + raw: name, + ); } } -enum WidgetPermissionSeverity { - low, - mild, - high, - critical, -} +enum WidgetPermissionSeverity { low, mild, high, critical } class MatrixWidgetPermissionGroup { List permissions; @@ -79,28 +82,30 @@ class MatrixWidgetPermissionGroup { } static (List, List) - groupPermissions(List capabilities) { + groupPermissions(List capabilities) { final templateGroups = permissionGroups(); Map groups = {}; for (var template in templateGroups) { groups[template.name] = MatrixWidgetPermissionGroup( - name: template.name, - defaultValue: template.defaultValue, - permissions: List.empty(growable: true), - severity: template.severity, - icon: template.icon, - description: template.description); + name: template.name, + defaultValue: template.defaultValue, + permissions: List.empty(growable: true), + severity: template.severity, + icon: template.icon, + description: template.description, + ); } groups["custom_events"] = MatrixWidgetPermissionGroup( - name: "Custom Events", - defaultValue: true, - permissions: List.empty(growable: true), - icon: Icons.code, - severity: WidgetPermissionSeverity.low, - description: "Send and receive custom event data"); + name: "Custom Events", + defaultValue: true, + permissions: List.empty(growable: true), + icon: Icons.code, + severity: WidgetPermissionSeverity.low, + description: "Send and receive custom event data", + ); List ungrouped = List.empty(growable: true); @@ -110,9 +115,11 @@ class MatrixWidgetPermissionGroup { bool grouped = false; for (var template in templateGroups) { - if (template.permissions.any((i) => - i.capability == parsed.capability && - (i.eventType == null || i.eventType == parsed.eventType))) { + if (template.permissions.any( + (i) => + i.capability == parsed.capability && + (i.eventType == null || i.eventType == parsed.eventType), + )) { groups[template.name]!.permissions.add(parsed); grouped = true; break; @@ -143,117 +150,120 @@ class MatrixWidgetPermissionGroup { return ( groups.values.where((i) => i.permissions.isNotEmpty).toList(), - ungrouped + ungrouped, ); } static MatrixWidgetPermissionGroup media() { return MatrixWidgetPermissionGroup( - name: "Media", - description: "Upload and download files from your homeserver", - severity: WidgetPermissionSeverity.low, - defaultValue: true, - icon: Icons.file_copy_rounded, - permissions: [ - "org.matrix.msc4039.upload_file", - "org.matrix.msc4039.download_file" - ].map((i) => MatrixWidgetCapabilityString.parse(i)).toList()); + name: "Media", + description: "Upload and download files from your homeserver", + severity: WidgetPermissionSeverity.low, + defaultValue: true, + icon: Icons.file_copy_rounded, + permissions: [ + "org.matrix.msc4039.upload_file", + "org.matrix.msc4039.download_file", + ].map((i) => MatrixWidgetCapabilityString.parse(i)).toList(), + ); } static MatrixWidgetPermissionGroup readRoomInformation() { return MatrixWidgetPermissionGroup( - name: "Read Room Information", - description: - "Read information about the current room state, such as name and members", - severity: WidgetPermissionSeverity.low, - defaultValue: true, - icon: Icons.tag, - permissions: [ - "org.matrix.msc2762.receive.state_event:m.room.create", - "org.matrix.msc2762.receive.state_event:m.room.name", - "org.matrix.msc2762.receive.state_event:m.room.member", - "org.matrix.msc2762.receive.state_event:m.room.encryption", - "org.matrix.msc2762.receive.state_event:m.room.power_levels", - ].map((i) => MatrixWidgetCapabilityString.parse(i)).toList()); + name: "Read Room Information", + description: "Read information about the current room state, such as name and members", + severity: WidgetPermissionSeverity.low, + defaultValue: true, + icon: Icons.tag, + permissions: [ + "org.matrix.msc2762.receive.state_event:m.room.create", + "org.matrix.msc2762.receive.state_event:m.room.name", + "org.matrix.msc2762.receive.state_event:m.room.member", + "org.matrix.msc2762.receive.state_event:m.room.encryption", + "org.matrix.msc2762.receive.state_event:m.room.power_levels", + ].map((i) => MatrixWidgetCapabilityString.parse(i)).toList(), + ); } static MatrixWidgetPermissionGroup modifyChats() { return MatrixWidgetPermissionGroup( - name: "Manage Chat", - description: "Read, send and delete messages in this room", - defaultValue: false, - icon: Icons.message_rounded, - severity: WidgetPermissionSeverity.high, - permissions: [ - "org.matrix.msc2762.send.event:m.room.redaction", - "org.matrix.msc2762.receive.event:m.room.redaction", - "org.matrix.msc2762.send.event:m.reaction", - "org.matrix.msc2762.receive.event:m.reaction", - "org.matrix.msc2762.send.event:m.room.message", - "org.matrix.msc2762.timeline", - ].map((i) => MatrixWidgetCapabilityString.parse(i)).toList()); + name: "Manage Chat", + description: "Read, send and delete messages in this room", + defaultValue: false, + icon: Icons.message_rounded, + severity: WidgetPermissionSeverity.high, + permissions: [ + "org.matrix.msc2762.send.event:m.room.redaction", + "org.matrix.msc2762.receive.event:m.room.redaction", + "org.matrix.msc2762.send.event:m.reaction", + "org.matrix.msc2762.receive.event:m.reaction", + "org.matrix.msc2762.send.event:m.room.message", + "org.matrix.msc2762.timeline", + ].map((i) => MatrixWidgetCapabilityString.parse(i)).toList(), + ); } static MatrixWidgetPermissionGroup adminPowers() { return MatrixWidgetPermissionGroup( - name: "Admin Powers", - description: - "Change permissions and user roles / power levels.\nAdditional confirmation will be asked later, when the widget attempts to make changes", - defaultValue: true, - icon: Icons.security, - severity: WidgetPermissionSeverity.mild, - permissions: [ - "org.matrix.msc2762.send.state_event:m.room.power_levels", - ].map((i) => MatrixWidgetCapabilityString.parse(i)).toList()); + name: "Admin Powers", + description: "Change permissions and user roles / power levels.\nAdditional confirmation will be asked later, when the widget attempts to make changes", + defaultValue: true, + icon: Icons.security, + severity: WidgetPermissionSeverity.mild, + permissions: ["org.matrix.msc2762.send.state_event:m.room.power_levels"] + .map((i) => MatrixWidgetCapabilityString.parse(i)) + .toList(), + ); } static MatrixWidgetPermissionGroup callPermissions() { return MatrixWidgetPermissionGroup( - name: "Call Permissions", - description: "Make, manage and join calls", - icon: Icons.call_rounded, - defaultValue: true, - severity: WidgetPermissionSeverity.mild, - permissions: [ - "org.matrix.msc2762.send.event:io.element.call.encryption_keys", - "org.matrix.msc3819.receive.to_device:io.element.call.encryption_keys", - "org.matrix.msc2762.send.event:io.element.call.reaction", - "org.matrix.msc2762.send.event:org.matrix.msc4310.rtc.decline", - "org.matrix.msc2762.send.event:org.matrix.msc4143.rtc.member", - "org.matrix.msc2762.receive.event:io.element.call.encryption_keys", - "org.matrix.msc2762.receive.event:io.element.call.reaction", - "org.matrix.msc2762.receive.event:org.matrix.msc4310.rtc.decline", - "org.matrix.msc2762.receive.event:org.matrix.msc4143.rtc.member", - "org.matrix.msc2762.send.state_event:org.matrix.msc3401.call.member", - "org.matrix.msc2762.receive.state_event:org.matrix.msc3401.call.member", - "org.matrix.msc3819.send.to_device:m.call.invite", - "org.matrix.msc3819.send.to_device:m.call.candidates", - "org.matrix.msc3819.send.to_device:m.call.answer", - "org.matrix.msc3819.send.to_device:m.call.hangup", - "org.matrix.msc3819.send.to_device:m.call.reject", - "org.matrix.msc3819.send.to_device:m.call.select_answer", - "org.matrix.msc3819.send.to_device:m.call.negotiate", - "org.matrix.msc3819.send.to_device:m.call.sdp_stream_metadata_changed", - "org.matrix.msc3819.send.to_device:org.matrix.call.sdp_stream_metadata_changed", - "org.matrix.msc3819.send.to_device:m.call.replaces", - "org.matrix.msc3819.send.to_device:io.element.call.encryption_keys", - "org.matrix.msc3819.receive.to_device:m.call.invite", - "org.matrix.msc3819.receive.to_device:m.call.candidates", - "org.matrix.msc3819.receive.to_device:m.call.answer", - "org.matrix.msc3819.receive.to_device:m.call.hangup", - "org.matrix.msc3819.receive.to_device:m.call.reject", - "org.matrix.msc3819.receive.to_device:m.call.select_answer", - "org.matrix.msc3819.receive.to_device:m.call.negotiate", - "org.matrix.msc3819.receive.to_device:m.call.sdp_stream_metadata_changed", - "org.matrix.msc3819.receive.to_device:org.matrix.call.sdp_stream_metadata_changed", - "org.matrix.msc3819.receive.to_device:m.call.replaces", - "org.matrix.msc2762.send.event:org.matrix.msc4075.call.notify", - "org.matrix.msc2762.send.event:org.matrix.msc4075.rtc.notification", - // Maybe these dont need to be in this category? - "org.matrix.msc4157.send.delayed_event", - "org.matrix.msc4157.update_delayed_event", - "org.matrix.msc4407.send.sticky_event", - "org.matrix.msc4407.receive.sticky_event", - ].map((i) => MatrixWidgetCapabilityString.parse(i)).toList()); + name: "Call Permissions", + description: "Make, manage and join calls", + icon: Icons.call_rounded, + defaultValue: true, + severity: WidgetPermissionSeverity.mild, + permissions: [ + "org.matrix.msc2762.send.event:io.element.call.encryption_keys", + "org.matrix.msc3819.receive.to_device:io.element.call.encryption_keys", + "org.matrix.msc2762.send.event:io.element.call.reaction", + "org.matrix.msc2762.send.event:org.matrix.msc4310.rtc.decline", + "org.matrix.msc2762.send.event:org.matrix.msc4143.rtc.member", + "org.matrix.msc2762.receive.event:io.element.call.encryption_keys", + "org.matrix.msc2762.receive.event:io.element.call.reaction", + "org.matrix.msc2762.receive.event:org.matrix.msc4310.rtc.decline", + "org.matrix.msc2762.receive.event:org.matrix.msc4143.rtc.member", + "org.matrix.msc2762.send.state_event:org.matrix.msc3401.call.member", + "org.matrix.msc2762.receive.state_event:org.matrix.msc3401.call.member", + "org.matrix.msc3819.send.to_device:m.call.invite", + "org.matrix.msc3819.send.to_device:m.call.candidates", + "org.matrix.msc3819.send.to_device:m.call.answer", + "org.matrix.msc3819.send.to_device:m.call.hangup", + "org.matrix.msc3819.send.to_device:m.call.reject", + "org.matrix.msc3819.send.to_device:m.call.select_answer", + "org.matrix.msc3819.send.to_device:m.call.negotiate", + "org.matrix.msc3819.send.to_device:m.call.sdp_stream_metadata_changed", + "org.matrix.msc3819.send.to_device:org.matrix.call.sdp_stream_metadata_changed", + "org.matrix.msc3819.send.to_device:m.call.replaces", + "org.matrix.msc3819.send.to_device:io.element.call.encryption_keys", + "org.matrix.msc3819.receive.to_device:m.call.invite", + "org.matrix.msc3819.receive.to_device:m.call.candidates", + "org.matrix.msc3819.receive.to_device:m.call.answer", + "org.matrix.msc3819.receive.to_device:m.call.hangup", + "org.matrix.msc3819.receive.to_device:m.call.reject", + "org.matrix.msc3819.receive.to_device:m.call.select_answer", + "org.matrix.msc3819.receive.to_device:m.call.negotiate", + "org.matrix.msc3819.receive.to_device:m.call.sdp_stream_metadata_changed", + "org.matrix.msc3819.receive.to_device:org.matrix.call.sdp_stream_metadata_changed", + "org.matrix.msc3819.receive.to_device:m.call.replaces", + "org.matrix.msc2762.send.event:org.matrix.msc4075.call.notify", + "org.matrix.msc2762.send.event:org.matrix.msc4075.rtc.notification", + // Maybe these dont need to be in this category? + "org.matrix.msc4157.send.delayed_event", + "org.matrix.msc4157.update_delayed_event", + "org.matrix.msc4407.send.sticky_event", + "org.matrix.msc4407.receive.sticky_event", + ].map((i) => MatrixWidgetCapabilityString.parse(i)).toList(), + ); } } diff --git a/commet/lib/client/matrix/components/widgets/matrix_widget_permissions_view.dart b/commet/lib/client/matrix/components/widgets/matrix_widget_permissions_view.dart index 62d6c9012..15f59e828 100644 --- a/commet/lib/client/matrix/components/widgets/matrix_widget_permissions_view.dart +++ b/commet/lib/client/matrix/components/widgets/matrix_widget_permissions_view.dart @@ -6,11 +6,12 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class MatrixWidgetPermissionsView extends StatefulWidget { - const MatrixWidgetPermissionsView( - {required this.runner, - required this.groupedPermissions, - required this.ungrouped, - super.key}); + const MatrixWidgetPermissionsView({ + required this.runner, + required this.groupedPermissions, + required this.ungrouped, + super.key, + }); final List groupedPermissions; final List ungrouped; @@ -54,7 +55,8 @@ class _MatrixWidgetPermissionsViewState Padding( padding: const EdgeInsets.all(8.0), child: tiamat.Text.label( - "'${widget.runner.info.name}' would like permission to do the following actions on your behalf:"), + "'${widget.runner.info.name}' would like permission to do the following actions on your behalf:", + ), ), buildGroups(), ListView.builder( @@ -66,9 +68,7 @@ class _MatrixWidgetPermissionsViewState return buildItem(item); }, ), - SizedBox( - height: 10, - ), + SizedBox(height: 10), Padding( padding: const EdgeInsets.all(8.0), child: Row( @@ -82,7 +82,7 @@ class _MatrixWidgetPermissionsViewState rememberChoice = value; }); }, - ) + ), ], ), ), @@ -90,17 +90,21 @@ class _MatrixWidgetPermissionsViewState Padding( padding: const EdgeInsets.all(8.0), child: tiamat.Text.labelLow( - "Some permissions will not be granted, the widget may not function as intended"), + "Some permissions will not be granted, the widget may not function as intended", + ), ), tiamat.Button( text: "Submit", onTap: () { - Navigator.of(context).pop(DialogResult( + Navigator.of(context).pop( + DialogResult( enabledPermissions.entries .where((i) => i.value == true) .map((i) => i.key) .toList(), - remember: rememberChoice)); + remember: rememberChoice, + ), + ); }, ), ], @@ -133,74 +137,72 @@ class _MatrixWidgetPermissionsViewState : Theme.of(context).colorScheme.surface; return ExpansionTile( - title: Row( - children: [ - Flexible( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Checkbox( - value: group.permissions - .any((i) => enabledPermissions[i.raw] == true), - onChanged: (value) { - setState(() { - for (var entry in group.permissions) { - enabledPermissions[entry.raw] = value == true; - } - }); - }, - ), - SizedBox( - width: 8, + title: Row( + children: [ + Flexible( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Checkbox( + value: group.permissions.any( + (i) => enabledPermissions[i.raw] == true, ), - Flexible( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 8, 0), - child: Icon( - group.icon, - size: 20, - ), + onChanged: (value) { + setState(() { + for (var entry in group.permissions) { + enabledPermissions[entry.raw] = value == true; + } + }); + }, + ), + SizedBox(width: 8), + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 8, 0), + child: Icon(group.icon, size: 20), + ), + tiamat.Text.labelEmphasised(group.name), + Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 0, 0), + child: tiamat.Text.labelLow( + "(${group.permissions.length})", ), - tiamat.Text.labelEmphasised(group.name), - Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 0, 0), - child: tiamat.Text.labelLow( - "(${group.permissions.length})"), - ) - ], - ), - Padding( - padding: const EdgeInsets.fromLTRB(0, 8, 0, 0), - child: tiamat.Text.labelLow(group.description), - ), - ], - ), + ), + ], + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 8, 0, 0), + child: tiamat.Text.labelLow(group.description), + ), + ], ), - Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 0, 0), - child: buildSeverityIcon(group), - ), - ], - ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 0, 0), + child: buildSeverityIcon(group), + ), + ], ), - ], + ), + ], + ), + backgroundColor: bg, + collapsedBackgroundColor: bg, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(10, 0, 0, 0), + child: Column( + children: group.permissions.map((i) => buildItem(i)).toList(), + ), ), - backgroundColor: bg, - collapsedBackgroundColor: bg, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(10, 0, 0, 0), - child: Column( - children: group.permissions.map((i) => buildItem(i)).toList(), - ), - ) - ]); + ], + ); } Widget buildSeverityIcon(MatrixWidgetPermissionGroup group) { @@ -215,10 +217,7 @@ class _MatrixWidgetPermissionsViewState WidgetPermissionSeverity.critical => Icons.warning_rounded, }; - return Icon( - icon, - color: color, - ); + return Icon(icon, color: color); } Color severityColor(MatrixWidgetPermissionGroup group) { diff --git a/commet/lib/client/matrix/components/widgets/matrix_widget_transport.dart b/commet/lib/client/matrix/components/widgets/matrix_widget_transport.dart index 8d5c8e88a..c43c60fe7 100644 --- a/commet/lib/client/matrix/components/widgets/matrix_widget_transport.dart +++ b/commet/lib/client/matrix/components/widgets/matrix_widget_transport.dart @@ -42,17 +42,11 @@ class MatrixWidgetTransport implements WidgetMessageTransport { dynamic encodeArrayBuffers(dynamic input) { if (input is Uint8List) { - return { - '__type': 'ArrayBuffer', - 'data': base64Encode(input), - }; + return {'__type': 'ArrayBuffer', 'data': base64Encode(input)}; } if (input is MatrixWidgetBlob) { - return { - '__type': 'Blob', - 'data': base64Encode(input.bytes), - }; + return {'__type': 'Blob', 'data': base64Encode(input.bytes)}; } if (input is List) { @@ -110,7 +104,7 @@ class MatrixWidgetTransport implements WidgetMessageTransport { if (preferences.widgetDeveloperMode.value) { messageLogs.add(( WidgetMessageDirection.outgoing, - Map.from(encoded) + Map.from(encoded), )); } diff --git a/commet/lib/client/matrix/components/widgets/runners/android_activity/matrix_widget_android_runner.dart b/commet/lib/client/matrix/components/widgets/runners/android_activity/matrix_widget_android_runner.dart index 30b286c93..3ad6c5374 100644 --- a/commet/lib/client/matrix/components/widgets/runners/android_activity/matrix_widget_android_runner.dart +++ b/commet/lib/client/matrix/components/widgets/runners/android_activity/matrix_widget_android_runner.dart @@ -56,8 +56,10 @@ class MatrixWidgetAndroidRunner implements MatrixWidgetRunner { tx = MatrixAndroidIpcTransceiver(socket); messageTransport = MatrixWidgetTransport(tx); eventHandler = MatrixWidgetMessageHandler(runner: this); - capabilities = - MatrixWidgetCapabilitiesManager(runner: this, context: context); + capabilities = MatrixWidgetCapabilitiesManager( + runner: this, + context: context, + ); } @override diff --git a/commet/lib/client/matrix/components/widgets/runners/in_app_web_view/matrix_inappwebview_widget_transceiver.dart b/commet/lib/client/matrix/components/widgets/runners/in_app_web_view/matrix_inappwebview_widget_transceiver.dart index 222ae54ad..62818d69e 100644 --- a/commet/lib/client/matrix/components/widgets/runners/in_app_web_view/matrix_inappwebview_widget_transceiver.dart +++ b/commet/lib/client/matrix/components/widgets/runners/in_app_web_view/matrix_inappwebview_widget_transceiver.dart @@ -18,7 +18,9 @@ class MatrixInAppWebViewWidgetTransceiver implements WidgetTransceiver { InAppWebViewController controller; MatrixInAppWebViewWidgetTransceiver(this.controller) { controller.addJavaScriptHandler( - handlerName: "widget_handler", callback: onJsCallback); + handlerName: "widget_handler", + callback: onJsCallback, + ); } onJsCallback(List arguments) async { @@ -59,7 +61,8 @@ class MatrixInAppWebViewWidgetTransceiver implements WidgetTransceiver { Log.i("Sending message id: $id"); - var script = """ + var script = + """ var data = sessionStorage.getItem('${id}'); window.onMessagePolyfill(data); sessionStorage.removeItem('${id}'); diff --git a/commet/lib/client/matrix/components/widgets/runners/in_app_web_view/matrix_widget_inappwebview_runner.dart b/commet/lib/client/matrix/components/widgets/runners/in_app_web_view/matrix_widget_inappwebview_runner.dart index 4e28bd682..8e991b878 100644 --- a/commet/lib/client/matrix/components/widgets/runners/in_app_web_view/matrix_widget_inappwebview_runner.dart +++ b/commet/lib/client/matrix/components/widgets/runners/in_app_web_view/matrix_widget_inappwebview_runner.dart @@ -48,22 +48,25 @@ class MatrixUserWidgetInAppWebviewRunner implements MatrixWidgetRunner { @override Stream get onClosed => _onClosed.stream; - MatrixUserWidgetInAppWebviewRunner( - {required InAppWebViewController webViewController, - required this.room, - required this.widgetId, - required this.info, - required this.onExitController, - required BuildContext context, - required this.client}) { + MatrixUserWidgetInAppWebviewRunner({ + required InAppWebViewController webViewController, + required this.room, + required this.widgetId, + required this.info, + required this.onExitController, + required BuildContext context, + required this.client, + }) { var tx = MatrixInAppWebViewWidgetTransceiver(webViewController); this.controller = webViewController; messageTransport = MatrixWidgetTransport(tx); eventHandler = MatrixWidgetMessageHandler(runner: this); - capabilities = - MatrixWidgetCapabilitiesManager(runner: this, context: context); + capabilities = MatrixWidgetCapabilitiesManager( + runner: this, + context: context, + ); } @override @@ -78,15 +81,16 @@ class MatrixUserWidgetInAppWebviewRunner implements MatrixWidgetRunner { } class MatrixWidgetInappwebviewRunnerWidget extends StatefulWidget { - const MatrixWidgetInappwebviewRunnerWidget( - {required this.widgetId, - required this.initialPageData, - required this.room, - required this.component, - required this.info, - required this.onExitController, - this.server, - super.key}); + const MatrixWidgetInappwebviewRunnerWidget({ + required this.widgetId, + required this.initialPageData, + required this.room, + required this.component, + required this.info, + required this.onExitController, + this.server, + super.key, + }); final String initialPageData; final String widgetId; final MatrixRoom room; @@ -112,12 +116,14 @@ class _MatrixWidgetInappwebviewRunnerWidgetState initialUrlRequest: widget.server == null ? null : URLRequest( - url: WebUri("http://localhost:${widget.server!.port}")), + url: WebUri("http://localhost:${widget.server!.port}"), + ), initialData: widget.server != null ? null : InAppWebViewInitialData( data: widget.initialPageData, - baseUrl: WebUri("http://localhost/widget")), + baseUrl: WebUri("http://localhost/widget"), + ), onConsoleMessage: (controller, consoleMessage) { Log.i("InAppWebView] $consoleMessage"); @@ -129,13 +135,14 @@ class _MatrixWidgetInappwebviewRunnerWidgetState Log.i("On web view created"); runner = MatrixUserWidgetInAppWebviewRunner( - webViewController: controller, - info: widget.info, - room: widget.room, - context: context, - widgetId: widget.widgetId, - onExitController: widget.onExitController, - client: widget.room.client as MatrixClient); + webViewController: controller, + info: widget.info, + room: widget.room, + context: context, + widgetId: widget.widgetId, + onExitController: widget.onExitController, + client: widget.room.client as MatrixClient, + ); widget.component!.registerRunner(runner!); }, diff --git a/commet/lib/client/matrix/components/widgets/runners/remote_http/matrix_remote_http_transceiver.dart b/commet/lib/client/matrix/components/widgets/runners/remote_http/matrix_remote_http_transceiver.dart index cdac7db08..421465ada 100644 --- a/commet/lib/client/matrix/components/widgets/runners/remote_http/matrix_remote_http_transceiver.dart +++ b/commet/lib/client/matrix/components/widgets/runners/remote_http/matrix_remote_http_transceiver.dart @@ -23,15 +23,16 @@ class MatrixRemoteHttpWidgetTransceiver implements WidgetTransceiver { Function()? onClientConnected; - MatrixRemoteHttpWidgetTransceiver( - {required this.server, - required this.hostIp, - required this.secret, - required this.widgetUrl, - required this.info, - this.onClientConnected, - required this.allowRemoteConnection, - required this.useHttps}) { + MatrixRemoteHttpWidgetTransceiver({ + required this.server, + required this.hostIp, + required this.secret, + required this.widgetUrl, + required this.info, + this.onClientConnected, + required this.allowRemoteConnection, + required this.useHttps, + }) { server.listen(onRequest); } @@ -76,11 +77,13 @@ class MatrixRemoteHttpWidgetTransceiver implements WidgetTransceiver { void handlePageRequest(HttpRequest request) async { var editedUrl = Uri.parse(widgetUrl); - editedUrl = editedUrl.replace(queryParameters: { - ...editedUrl.queryParameters, - "parentUrl": - (useHttps ? "https://" : "http://") + hostIp + ":${server.port}", - }); + editedUrl = editedUrl.replace( + queryParameters: { + ...editedUrl.queryParameters, + "parentUrl": + (useHttps ? "https://" : "http://") + hostIp + ":${server.port}", + }, + ); Log.i("Handling favicon"); var bytes = (await rootBundle.load("assets/data/widget_runner_remote.html")) @@ -93,8 +96,10 @@ class MatrixRemoteHttpWidgetTransceiver implements WidgetTransceiver { .asUint8List(); var scriptText = Utf8Decoder().convert(scriptBytes); - text = - text.replaceAll("\$RUNNER_PAGE_TITLE", "Commet Widget | ${info.name}"); + text = text.replaceAll( + "\$RUNNER_PAGE_TITLE", + "Commet Widget | ${info.name}", + ); text = text.replaceAll("\$IFRAME_URL", editedUrl.toString()); @@ -115,10 +120,9 @@ class MatrixRemoteHttpWidgetTransceiver implements WidgetTransceiver { } void handleIconRequest(HttpRequest request) async { - var bytes = - (await rootBundle.load("assets/images/app_icon/app_icon_rounded.png")) - .buffer - .asUint8List(); + var bytes = (await rootBundle.load( + "assets/images/app_icon/app_icon_rounded.png", + )).buffer.asUint8List(); request.response ..headers.contentType = new ContentType("image", "png") diff --git a/commet/lib/client/matrix/components/widgets/runners/remote_http/matrix_widget_remote_http_runner.dart b/commet/lib/client/matrix/components/widgets/runners/remote_http/matrix_widget_remote_http_runner.dart index 756a12119..12f1bb388 100644 --- a/commet/lib/client/matrix/components/widgets/runners/remote_http/matrix_widget_remote_http_runner.dart +++ b/commet/lib/client/matrix/components/widgets/runners/remote_http/matrix_widget_remote_http_runner.dart @@ -82,27 +82,31 @@ class MatrixUserWidgetRemoteHttpRunner implements MatrixWidgetRunner { final String secret = RandomUtils.getRandomString(50); // "secret_password"; tx = MatrixRemoteHttpWidgetTransceiver( - secret: secret, - widgetUrl: url, - hostIp: hostName, - info: info, - server: server, - allowRemoteConnection: allowRemoteConnection, - useHttps: useInsecureHttp == false, - onClientConnected: handleInitialConnection); + secret: secret, + widgetUrl: url, + hostIp: hostName, + info: info, + server: server, + allowRemoteConnection: allowRemoteConnection, + useHttps: useInsecureHttp == false, + onClientConnected: handleInitialConnection, + ); messageTransport = MatrixWidgetTransport(tx); eventHandler = MatrixWidgetMessageHandler(runner: this); - capabilities = - MatrixWidgetCapabilitiesManager(runner: this, context: context); + capabilities = MatrixWidgetCapabilitiesManager( + runner: this, + context: context, + ); if (launchBrowser) { var url = Uri( - scheme: "http", - host: hostName, - port: server.port, - queryParameters: {"token": secret}); + scheme: "http", + host: hostName, + port: server.port, + queryParameters: {"token": secret}, + ); Log.i("Launching browser with url: $url"); @@ -138,7 +142,8 @@ class MatrixUserWidgetRemoteHttpRunner implements MatrixWidgetRunner { if (selectedBrowser == null) { throw Exception( - "Could not find any installed chromium browser to run widget"); + "Could not find any installed chromium browser to run widget", + ); } var command = selectedBrowser; @@ -148,7 +153,7 @@ class MatrixUserWidgetRemoteHttpRunner implements MatrixWidgetRunner { '--no-default-browser-check', '--disable-background-networking', '--disable-component-update', - '--user-data-dir=${temp}' + '--user-data-dir=${temp}', ]; if (BuildConfig.IS_FLATPAK) { @@ -187,14 +192,18 @@ class MatrixUserWidgetRemoteHttpRunner implements MatrixWidgetRunner { } void showConnectionInfo( - String secret, String hostName, BuildContext context) async { + String secret, + String hostName, + BuildContext context, + ) async { Log.i("Current IP: $hostName"); var url = Uri( - scheme: useInsecureHttp ? "http" : "https", - host: hostName, - port: server.port, - queryParameters: {"token": secret}); + scheme: useInsecureHttp ? "http" : "https", + host: hostName, + port: server.port, + queryParameters: {"token": secret}, + ); Log.i("Url: ${url.toString()}"); @@ -206,23 +215,26 @@ class MatrixUserWidgetRemoteHttpRunner implements MatrixWidgetRunner { ClipRRect( borderRadius: BorderRadiusGeometry.circular(8), child: SizedBox( - height: 300, - width: 300, - child: PrettyQrView.data( - data: url.toString(), - errorCorrectLevel: QrErrorCorrectLevel.H, - decoration: const PrettyQrDecoration( - image: const PrettyQrDecorationImage( - scale: 0.20, - padding: EdgeInsetsGeometry.all(40), - filterQuality: FilterQuality.medium, - image: AssetImage( - 'assets/images/app_icon/app_icon_transparent_cropped.png'), - ), - quietZone: PrettyQrQuietZone.standard, - shape: PrettyQrSmoothSymbol(color: Colors.white), - background: Colors.black), - )), + height: 300, + width: 300, + child: PrettyQrView.data( + data: url.toString(), + errorCorrectLevel: QrErrorCorrectLevel.H, + decoration: const PrettyQrDecoration( + image: const PrettyQrDecorationImage( + scale: 0.20, + padding: EdgeInsetsGeometry.all(40), + filterQuality: FilterQuality.medium, + image: AssetImage( + 'assets/images/app_icon/app_icon_transparent_cropped.png', + ), + ), + quietZone: PrettyQrQuietZone.standard, + shape: PrettyQrSmoothSymbol(color: Colors.white), + background: Colors.black, + ), + ), + ), ), Padding( padding: const EdgeInsets.fromLTRB(0, 8, 0, 0), diff --git a/commet/lib/client/matrix/components/widgets/runners/remote_http/self_signed_https_server.dart b/commet/lib/client/matrix/components/widgets/runners/remote_http/self_signed_https_server.dart index a9da60726..718b3f514 100644 --- a/commet/lib/client/matrix/components/widgets/runners/remote_http/self_signed_https_server.dart +++ b/commet/lib/client/matrix/components/widgets/runners/remote_http/self_signed_https_server.dart @@ -10,10 +10,7 @@ class CertificateData { final Uint8List certBytes; final Uint8List privateKeyBytes; - CertificateData({ - required this.certBytes, - required this.privateKeyBytes, - }); + CertificateData({required this.certBytes, required this.privateKeyBytes}); } Future spawnSelfSignedHttpsServer(String hostname) async { @@ -41,8 +38,11 @@ Future spawnServerWithOpenPort({SecurityContext? context}) async { var server = await HttpServer.bind(InternetAddress.anyIPv4, port); return server; } else { - var server = - await HttpServer.bindSecure(InternetAddress.anyIPv4, port, context); + var server = await HttpServer.bindSecure( + InternetAddress.anyIPv4, + port, + context, + ); return server; } } catch (_) { @@ -59,13 +59,7 @@ Future generateSelfSignedCertificate(String host) async { final privateKey = pair.privateKey as RSAPrivateKey; final publicKey = pair.publicKey as RSAPublicKey; - final csr = X509Utils.generateRsaCsrPem( - { - 'CN': host, - }, - privateKey, - publicKey, - ); + final csr = X509Utils.generateRsaCsrPem({'CN': host}, privateKey, publicKey); final certPem = X509Utils.generateSelfSignedCertificate( privateKey, @@ -76,11 +70,7 @@ Future generateSelfSignedCertificate(String host) async { final privateKeyPem = CryptoUtils.encodeRSAPrivateKeyToPem(privateKey); return CertificateData( - certBytes: Uint8List.fromList( - utf8.encode(certPem), - ), - privateKeyBytes: Uint8List.fromList( - utf8.encode(privateKeyPem), - ), + certBytes: Uint8List.fromList(utf8.encode(certPem)), + privateKeyBytes: Uint8List.fromList(utf8.encode(privateKeyPem)), ); } diff --git a/commet/lib/client/matrix/components/widgets/runners/subprocess/matrix_widget_desktop_runner.dart b/commet/lib/client/matrix/components/widgets/runners/subprocess/matrix_widget_desktop_runner.dart index 34d42238b..6ff42ef1f 100644 --- a/commet/lib/client/matrix/components/widgets/runners/subprocess/matrix_widget_desktop_runner.dart +++ b/commet/lib/client/matrix/components/widgets/runners/subprocess/matrix_widget_desktop_runner.dart @@ -51,15 +51,16 @@ class MatrixUserWidgetSubprocessRunner implements MatrixWidgetRunner { @override UserWidgetInfo info; - MatrixUserWidgetSubprocessRunner( - {required Process process, - required this.room, - required this.widgetId, - required BuildContext context, - required this.info, - this.hidden = false, - this.privileged = false, - required this.client}) { + MatrixUserWidgetSubprocessRunner({ + required Process process, + required this.room, + required this.widgetId, + required BuildContext context, + required this.info, + this.hidden = false, + this.privileged = false, + required this.client, + }) { var tx = MatrixSubprocessWidgetTransceiver(process: process); this.process = process; @@ -67,11 +68,19 @@ class MatrixUserWidgetSubprocessRunner implements MatrixWidgetRunner { eventHandler = MatrixWidgetMessageHandler(runner: this); capabilities = MatrixWidgetCapabilitiesManager( - runner: this, context: context, privileged: privileged); + runner: this, + context: context, + privileged: privileged, + ); if (preferences.widgetDeveloperMode.value) { - process.stderr.map((i) => Utf8Decoder().convert(i)).listen((i) => - i.split("\n").forEach((i) => logs.add(LogEntry(LogType.info, i)))); + process.stderr + .map((i) => Utf8Decoder().convert(i)) + .listen( + (i) => i + .split("\n") + .forEach((i) => logs.add(LogEntry(LogType.info, i))), + ); } process.exitCode.then((i) { diff --git a/commet/lib/client/matrix/database/matrix_database.dart b/commet/lib/client/matrix/database/matrix_database.dart index a30b19bfd..355d33865 100644 --- a/commet/lib/client/matrix/database/matrix_database.dart +++ b/commet/lib/client/matrix/database/matrix_database.dart @@ -4,10 +4,16 @@ import 'matrix_database_stub.dart' import 'package:matrix/matrix.dart'; -Future getMatrixDatabase(String clientName, - {bool onDatabaseIsolate = true, bool readOnly = false}) { - return getMatrixDatabaseImplementation(clientName, - onDatabaseIsolate: onDatabaseIsolate, readOnly: readOnly); +Future getMatrixDatabase( + String clientName, { + bool onDatabaseIsolate = true, + bool readOnly = false, +}) { + return getMatrixDatabaseImplementation( + clientName, + onDatabaseIsolate: onDatabaseIsolate, + readOnly: readOnly, + ); } Future getLegacyMatrixDatabase(String clientName) { diff --git a/commet/lib/client/matrix/database/matrix_database_html.dart b/commet/lib/client/matrix/database/matrix_database_html.dart index 70f319e74..c0951a24a 100644 --- a/commet/lib/client/matrix/database/matrix_database_html.dart +++ b/commet/lib/client/matrix/database/matrix_database_html.dart @@ -2,8 +2,11 @@ import 'package:matrix/matrix.dart'; import 'package:universal_html/html.dart' as html; -Future getMatrixDatabaseImplementation(String clientName, - {bool onDatabaseIsolate = true, bool readOnly = false}) async { +Future getMatrixDatabaseImplementation( + String clientName, { + bool onDatabaseIsolate = true, + bool readOnly = false, +}) async { await html.window.navigator.storage?.persist(); var db = await MatrixSdkDatabase.init(clientName); await db.open(); @@ -11,6 +14,7 @@ Future getMatrixDatabaseImplementation(String clientName, } Future getLegacyMatrixDatabaseImplementation( - String clientName) async { + String clientName, +) async { return null; } diff --git a/commet/lib/client/matrix/database/matrix_database_io.dart b/commet/lib/client/matrix/database/matrix_database_io.dart index 3b626b301..61a926c52 100644 --- a/commet/lib/client/matrix/database/matrix_database_io.dart +++ b/commet/lib/client/matrix/database/matrix_database_io.dart @@ -10,8 +10,11 @@ import 'package:matrix_dart_sdk_drift_db/matrix_dart_sdk_drift_db.dart'; import 'package:path/path.dart' as p; import 'package:sqlite3/sqlite3.dart' as sqlite; -Future getMatrixDatabaseImplementation(String clientName, - {bool onDatabaseIsolate = true, bool readOnly = false}) async { +Future getMatrixDatabaseImplementation( + String clientName, { + bool onDatabaseIsolate = true, + bool readOnly = false, +}) async { var path = await AppConfig.getDriftDatabasePath(); path = p.join(path, clientName, "data.db"); var dir = p.dirname(path); @@ -23,23 +26,31 @@ Future getMatrixDatabaseImplementation(String clientName, final file = File(path); if (onDatabaseIsolate) { - var connection = - await DatabaseIsolate.connect(file.absolute.path, readOnly: readOnly); + var connection = await DatabaseIsolate.connect( + file.absolute.path, + readOnly: readOnly, + ); - return MatrixSdkDriftDatabase.init(connection, clientName, - benchmark: benchmarkFunc); + return MatrixSdkDriftDatabase.init( + connection, + clientName, + benchmark: benchmarkFunc, + ); } else { var connection = setupNativeDatabase(file, readOnly: readOnly); - return MatrixSdkDriftDatabase.init(connection, clientName, - benchmark: benchmarkFunc); + return MatrixSdkDriftDatabase.init( + connection, + clientName, + benchmark: benchmarkFunc, + ); } } NativeDatabase setupNativeDatabase(File file, {bool readOnly = false}) { - final db = sqlite.sqlite3.open(file.path, - mode: readOnly - ? sqlite.OpenMode.readOnly - : sqlite.OpenMode.readWriteCreate); + final db = sqlite.sqlite3.open( + file.path, + mode: readOnly ? sqlite.OpenMode.readOnly : sqlite.OpenMode.readWriteCreate, + ); Log.d("Opening database (readonly: $readOnly) ${file.path}"); @@ -53,12 +64,16 @@ NativeDatabase setupNativeDatabase(File file, {bool readOnly = false}) { ); } -Future benchmarkFunc(String name, Future Function() func, - [int? itemCount]) { +Future benchmarkFunc( + String name, + Future Function() func, [ + int? itemCount, +]) { return Diagnostics.databaseDiagnostics.timeAsync(name, func); } Future getLegacyMatrixDatabaseImplementation( - String clientName) async { + String clientName, +) async { return null; } diff --git a/commet/lib/client/matrix/database/matrix_database_stub.dart b/commet/lib/client/matrix/database/matrix_database_stub.dart index b7fc0dafc..aa8e5fda2 100644 --- a/commet/lib/client/matrix/database/matrix_database_stub.dart +++ b/commet/lib/client/matrix/database/matrix_database_stub.dart @@ -1,11 +1,15 @@ import 'package:matrix/matrix.dart'; -Future getMatrixDatabaseImplementation(String clientName, - {bool onDatabaseIsolate = true, bool readOnly = false}) async { +Future getMatrixDatabaseImplementation( + String clientName, { + bool onDatabaseIsolate = true, + bool readOnly = false, +}) async { throw UnimplementedError(); } Future getLegacyMatrixDatabaseImplementation( - String clientName) async { + String clientName, +) async { throw UnimplementedError(); } diff --git a/commet/lib/client/matrix/extensions/matrix_client_extensions.dart b/commet/lib/client/matrix/extensions/matrix_client_extensions.dart index 2ce5a670f..9d59cb472 100644 --- a/commet/lib/client/matrix/extensions/matrix_client_extensions.dart +++ b/commet/lib/client/matrix/extensions/matrix_client_extensions.dart @@ -12,18 +12,27 @@ extension MatrixExtensions on Client { } Future getContentThumbnailFromUri( - Uri uri, int width, int height) { + Uri uri, + int width, + int height, + ) { return getContentThumbnail( - uri.authority, uri.pathSegments.first, width, height); + uri.authority, + uri.pathSegments.first, + width, + height, + ); } - Future getRoomPreview(String roomId, - {List? via}) async { - var result = await request(RequestType.GET, - "/client/unstable/im.nheko.summary/rooms/${Uri.encodeComponent(roomId)}/summary", - query: { - if (via != null) "via": via.join(","), - }); + Future getRoomPreview( + String roomId, { + List? via, + }) async { + var result = await request( + RequestType.GET, + "/client/unstable/im.nheko.summary/rooms/${Uri.encodeComponent(roomId)}/summary", + query: {if (via != null) "via": via.join(",")}, + ); var name = result["name"] as String?; var id = result["room_id"] as String?; @@ -37,7 +46,7 @@ extension MatrixExtensions on Client { "chat.commet.calendar" => commet.RoomType.calendar, "chat.commet.photo_album" => commet.RoomType.photoAlbum, "org.matrix.msc3417.call" => commet.RoomType.voipRoom, - _ => commet.RoomType.defaultRoom + _ => commet.RoomType.defaultRoom, }; var visibility = switch (joinRule) { @@ -56,13 +65,15 @@ extension MatrixExtensions on Client { image = MatrixMxcImage(mxc, autoLoadFullRes: false, this); } - return GenericRoomPreview(id, - displayName: name, - type: type, - avatar: image, - numMembers: numMembers, - visibility: visibility, - topic: topic); + return GenericRoomPreview( + id, + displayName: name, + type: type, + avatar: image, + numMembers: numMembers, + visibility: visibility, + topic: topic, + ); } return null; @@ -70,10 +81,13 @@ extension MatrixExtensions on Client { Future addEmoticonRoomPack(String roomId, String packKey) async { var state = BasicEvent( - type: MatrixEmoticonComponent.globalEmoteRoomsStateKey, content: {}); + type: MatrixEmoticonComponent.globalEmoteRoomsStateKey, + content: {}, + ); - if (accountData - .containsKey(MatrixEmoticonComponent.globalEmoteRoomsStateKey)) { + if (accountData.containsKey( + MatrixEmoticonComponent.globalEmoteRoomsStateKey, + )) { state = accountData[MatrixEmoticonComponent.globalEmoteRoomsStateKey]!; } @@ -89,16 +103,22 @@ extension MatrixExtensions on Client { var roomPacks = rooms[roomId] as Map; roomPacks[packKey] = {}; - await setAccountData(userID!, - MatrixEmoticonComponent.globalEmoteRoomsStateKey, state.content); + await setAccountData( + userID!, + MatrixEmoticonComponent.globalEmoteRoomsStateKey, + state.content, + ); } Future removeEmoticonRoomPack(String roomId, String packKey) async { var state = BasicEvent( - type: MatrixEmoticonComponent.globalEmoteRoomsStateKey, content: {}); + type: MatrixEmoticonComponent.globalEmoteRoomsStateKey, + content: {}, + ); - if (accountData - .containsKey(MatrixEmoticonComponent.globalEmoteRoomsStateKey)) { + if (accountData.containsKey( + MatrixEmoticonComponent.globalEmoteRoomsStateKey, + )) { state = accountData[MatrixEmoticonComponent.globalEmoteRoomsStateKey]!; } @@ -114,13 +134,17 @@ extension MatrixExtensions on Client { var roomPacks = rooms[roomId] as Map; roomPacks.remove(packKey); - await setAccountData(userID!, - MatrixEmoticonComponent.globalEmoteRoomsStateKey, state.content); + await setAccountData( + userID!, + MatrixEmoticonComponent.globalEmoteRoomsStateKey, + state.content, + ); } bool isEmoticonPackGloballyAvailable(String roomId, String packKey) { - if (!accountData - .containsKey(MatrixEmoticonComponent.globalEmoteRoomsStateKey)) { + if (!accountData.containsKey( + MatrixEmoticonComponent.globalEmoteRoomsStateKey, + )) { return false; } diff --git a/commet/lib/client/matrix/matrix_client.dart b/commet/lib/client/matrix/matrix_client.dart index 783c2bfca..e45b04f30 100644 --- a/commet/lib/client/matrix/matrix_client.dart +++ b/commet/lib/client/matrix/matrix_client.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:collection/collection.dart'; import 'package:commet/client/alert.dart'; import 'package:commet/client/auth.dart'; @@ -28,7 +29,9 @@ import 'package:commet/utils/notifying_list_filter.dart'; import 'package:commet/utils/stored_stream_controller.dart'; import 'package:flutter/foundation.dart'; import 'package:crypto/crypto.dart'; + import 'dart:convert'; + import 'package:commet/client/client.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; @@ -39,6 +42,7 @@ import 'package:flutter_vodozemac/flutter_vodozemac.dart' as vodozemac; import '../../ui/atoms/code_block.dart'; import 'matrix_room.dart'; import 'matrix_space.dart'; + import 'package:vodozemac/vodozemac.dart' as vod; class MatrixClient extends Client { @@ -97,10 +101,11 @@ class MatrixClient extends Client { }, onFilterParamsChanged: [ _matrixClient.onSync.stream.where((sync) { - return sync.rooms?.join?.values.any((i) => - i.accountData?.any((i) => i.type == "m.tag") == true) == + return sync.rooms?.join?.values.any( + (i) => i.accountData?.any((i) => i.type == "m.tag") == true, + ) == true; - }) + }), ], ); @@ -166,24 +171,23 @@ class MatrixClient extends Client { StoredStreamController(); static String get matrixClientOlmMissingMessage => Intl.message( - "libolm is not installed or was not found. End to End Encryption will not be available until this is resolved", - name: "matrixClientOlmMissingMessage", - desc: - "Text that explains to the user that libolm dependency is not found", - ); + "libolm is not installed or was not found. End to End Encryption will not be available until this is resolved", + name: "matrixClientOlmMissingMessage", + desc: "Text that explains to the user that libolm dependency is not found", + ); static String get matrixClientVodozemacMissingMessage => Intl.message( - "vodozemac is not installed or was not found. End to End Encryption will not be available until this is resolved", - name: "matrixClientVodozemacMissingMessage", - desc: - "Text that explains to the user that vodozemac dependency is not found", - ); + "vodozemac is not installed or was not found. End to End Encryption will not be available until this is resolved", + name: "matrixClientVodozemacMissingMessage", + desc: + "Text that explains to the user that vodozemac dependency is not found", + ); static String get matrixClientEncryptionWarningTitle => Intl.message( - "Encryption Warning", - name: "matrixClientEncryptionWarningTitle", - desc: "Title of a warning about encryption", - ); + "Encryption Warning", + name: "matrixClientEncryptionWarningTitle", + desc: "Title of a warning about encryption", + ); static Future loadFromDB( ClientManager manager, { @@ -201,33 +205,30 @@ class MatrixClient extends Client { var client = await MatrixClient.create(clientName); manager.addClient(client); futures.add( - Diagnostics.general.timeAsync( - "Initializing client $clientName", - () async { - try { - await client.init( - true, - isBackgroundService: isBackgroundService, - ); - } catch (error, trace) { - Log.onError( - error, - trace, - content: "Unable to load client $clientName from database", - ); - - client.self = ErrorProfile(); - manager.alertManager.addAlert( - Alert( - AlertType.warning, - messageGetter: () => - "One of the registered accounts (${clientName.substring(0, 8)}...) was unable to load correctly, please check the logs for more details", - titleGetter: () => "Unable to load account", - ), - ); - } - }, - ), + Diagnostics.general.timeAsync("Initializing client $clientName", () async { + try { + await client.init( + true, + isBackgroundService: isBackgroundService, + ); + } catch (error, trace) { + Log.onError( + error, + trace, + content: "Unable to load client $clientName from database", + ); + + client.self = ErrorProfile(); + manager.alertManager.addAlert( + Alert( + AlertType.warning, + messageGetter: () => + "One of the registered accounts (${clientName.substring(0, 8)}...) was unable to load correctly, please check the logs for more details", + titleGetter: () => "Unable to load account", + ), + ); + } + }), ); } } @@ -256,11 +257,11 @@ class MatrixClient extends Client { static matrix.NativeImplementations get nativeImplementations => BuildConfig.WEB - ? const matrix.NativeImplementationsDummy() - : matrix.NativeImplementationsIsolate( - compute, - vodozemacInit: vodozemac.init, - ); + ? const matrix.NativeImplementationsDummy() + : matrix.NativeImplementationsIsolate( + compute, + vodozemacInit: vodozemac.init, + ); @override Future init( bool loadingFromCache, { @@ -393,20 +394,23 @@ class MatrixClient extends Client { var data = await _matrixClient.database.getUserProfile(id); if (data != null) { self = MatrixProfile( - this, - matrix.Profile( - userId: id, - displayName: data.displayname, - avatarUrl: data.avatarUrl, - )); + this, + matrix.Profile( + userId: id, + displayName: data.displayname, + avatarUrl: data.avatarUrl, + ), + ); // Update own profile, but lets not wait for it before continuing _matrixClient.getProfileFromUserId(id).then((profile) { self = MatrixProfile(this, profile); }); } else { - self = MatrixProfile(this, - await _matrixClient.getProfileFromUserId(_matrixClient.userID!)); + self = MatrixProfile( + this, + await _matrixClient.getProfileFromUserId(_matrixClient.userID!), + ); } } } @@ -459,8 +463,8 @@ class MatrixClient extends Client { powerLevelAdditions = { "events": { "org.matrix.msc3401.call": 0, - "org.matrix.msc3401.call.member": 0 - } + "org.matrix.msc3401.call.member": 0, + }, }; } @@ -510,21 +514,25 @@ class MatrixClient extends Client { ...initialState, for (var i in restricted.spaces) matrix.StateEvent( - stateKey: i, - type: matrix.EventTypes.SpaceParent, - content: { - "canonical": true, - "via": [ - if (self?.identifier.domain != null) self?.identifier.domain - ] - }), - matrix.StateEvent(content: { - "join_rule": "restricted", - "allow": [ - for (var i in restricted.spaces) - {"room_id": i, "type": "m.room_membership"}, - ] - }, type: matrix.EventTypes.RoomJoinRules) + stateKey: i, + type: matrix.EventTypes.SpaceParent, + content: { + "canonical": true, + "via": [ + if (self?.identifier.domain != null) self?.identifier.domain, + ], + }, + ), + matrix.StateEvent( + content: { + "join_rule": "restricted", + "allow": [ + for (var i in restricted.spaces) + {"room_id": i, "type": "m.room_membership"}, + ], + }, + type: matrix.EventTypes.RoomJoinRules, + ), ]; } @@ -556,10 +564,14 @@ class MatrixClient extends Client { "events": { ...?currentPerms["events"] as Map?, ...?powerLevelAdditions["events"] as Map?, - } + }, }; _matrixClient.setRoomStateWithKey( - id, matrix.EventTypes.RoomPowerLevels, "", newPerms); + id, + matrix.EventTypes.RoomPowerLevels, + "", + newPerms, + ); } } @@ -631,8 +643,9 @@ class MatrixClient extends Client { @override Future setAvatar(Uint8List bytes, String mimeType) async { - await _matrixClient.setAvatar(matrix.MatrixImageFile( - bytes: bytes, name: "avatar", mimeType: mimeType)); + await _matrixClient.setAvatar( + matrix.MatrixImageFile(bytes: bytes, name: "avatar", mimeType: mimeType), + ); await _updateOwnProfile(); // TODO: Handle refresh avatar @@ -779,7 +792,8 @@ class MatrixClient extends Client { void onSyncStatusChanged(matrix.SyncStatusUpdate event) { ClientConnectionStatus value = ClientConnectionStatus.unknown; - var connected = _matrixClient.onSync.value != null && + var connected = + _matrixClient.onSync.value != null && event.status != matrix.SyncStatus.error && _matrixClient.prevBatch != null; @@ -911,8 +925,9 @@ class MatrixClient extends Client { var data = await matrixClient.getWellknown(); Log.i(data); - var prop = - data.additionalProperties.tryGetMap("io.element.e2ee"); + var prop = data.additionalProperties.tryGetMap( + "io.element.e2ee", + ); var value = prop?.tryGet("force_disable"); diff --git a/commet/lib/client/matrix/matrix_member.dart b/commet/lib/client/matrix/matrix_member.dart index 138839c7c..008333a1e 100644 --- a/commet/lib/client/matrix/matrix_member.dart +++ b/commet/lib/client/matrix/matrix_member.dart @@ -12,11 +12,14 @@ class MatrixMember implements Member { @override ImageProvider? get avatar => matrixUser.avatarUrl != null - ? MatrixMxcImage(matrixUser.avatarUrl!, client.matrixClient, + ? MatrixMxcImage( + matrixUser.avatarUrl!, + client.matrixClient, doThumbnail: true, autoLoadFullRes: false, doFullres: false, - thumbnailHeight: 86) + thumbnailHeight: 86, + ) : null; @override diff --git a/commet/lib/client/matrix/matrix_mxc_file_provider.dart b/commet/lib/client/matrix/matrix_mxc_file_provider.dart index 4081a6e78..02acf4de2 100644 --- a/commet/lib/client/matrix/matrix_mxc_file_provider.dart +++ b/commet/lib/client/matrix/matrix_mxc_file_provider.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:io'; import 'dart:typed_data'; + import 'package:commet/cache/file_provider.dart'; import 'package:commet/debug/log.dart'; import 'package:commet/main.dart'; @@ -57,8 +58,9 @@ class MxcFileProvider implements FileProvider { var file = await event!.downloadAndDecryptAttachment( downloadCallback: (url) async { var request = http.Request("GET", url); - request.headers - .addAll({'authorization': 'Bearer ${client.accessToken}'}); + request.headers.addAll({ + 'authorization': 'Bearer ${client.accessToken}', + }); final response = await http.Client().send(request); List downloadedBytes = response.contentLength != null @@ -72,25 +74,23 @@ class MxcFileProvider implements FileProvider { var lastUpdatedProgress = DateTime.now(); - var data = response.stream.listen( - (event) { - if (response.contentLength != null) { - downloadedBytes.setAll(downloaded, event); - } else { - downloadedBytes.addAll(event); - } - downloaded += event.length; - - var now = DateTime.now(); - if (now.difference(lastUpdatedProgress).inMilliseconds > 16) { - lastUpdatedProgress = now; - - fileDownloadProgress.add( - DownloadProgress(downloaded, response.contentLength ?? -1)); - } - }, - cancelOnError: true, - ).asFuture(); + var data = response.stream.listen((event) { + if (response.contentLength != null) { + downloadedBytes.setAll(downloaded, event); + } else { + downloadedBytes.addAll(event); + } + downloaded += event.length; + + var now = DateTime.now(); + if (now.difference(lastUpdatedProgress).inMilliseconds > 16) { + lastUpdatedProgress = now; + + fileDownloadProgress.add( + DownloadProgress(downloaded, response.contentLength ?? -1), + ); + } + }, cancelOnError: true).asFuture(); await data; diff --git a/commet/lib/client/matrix/matrix_mxc_image_provider.dart b/commet/lib/client/matrix/matrix_mxc_image_provider.dart index 770434d3d..361540e76 100644 --- a/commet/lib/client/matrix/matrix_mxc_image_provider.dart +++ b/commet/lib/client/matrix/matrix_mxc_image_provider.dart @@ -1,5 +1,6 @@ import 'dart:io'; import 'dart:typed_data'; + import 'package:commet/client/matrix/extensions/matrix_client_extensions.dart'; import 'package:commet/debug/log.dart'; import 'package:commet/main.dart'; @@ -23,28 +24,30 @@ class MatrixMxcImage extends LODImageProvider { super.fullResHeight, Event? matrixEvent, }) : super( - id: "$identifier-$doThumbnail-$doFullres-$thumbnailHeight-$fullResHeight", - loadThumbnail: (doThumbnail == null || doThumbnail == true) - ? () => retryUntilOnline( - client, - () => loadMatrixThumbnail( - client, - identifier, - matrixEvent, - cache: cache, - )) - : null, - loadFullRes: (doFullres == null || doFullres == true) - ? () => retryUntilOnline( - client, - () => loadMatrixFullRes( - client, - identifier, - matrixEvent, - cache: cache, - )) - : null, - ); + id: "$identifier-$doThumbnail-$doFullres-$thumbnailHeight-$fullResHeight", + loadThumbnail: (doThumbnail == null || doThumbnail == true) + ? () => retryUntilOnline( + client, + () => loadMatrixThumbnail( + client, + identifier, + matrixEvent, + cache: cache, + ), + ) + : null, + loadFullRes: (doFullres == null || doFullres == true) + ? () => retryUntilOnline( + client, + () => loadMatrixFullRes( + client, + identifier, + matrixEvent, + cache: cache, + ), + ) + : null, + ); static String getThumbnailIdentifier(Uri uri) { return "matrix_thumbnail-$uri"; @@ -55,7 +58,9 @@ class MatrixMxcImage extends LODImageProvider { } static Future retryUntilOnline( - Client client, Future callback()) async { + Client client, + Future callback(), + ) async { try { var value = await callback(); return value; diff --git a/commet/lib/client/matrix/matrix_native_implementations.dart b/commet/lib/client/matrix/matrix_native_implementations.dart index 87b5da4eb..28fd2dfce 100644 --- a/commet/lib/client/matrix/matrix_native_implementations.dart +++ b/commet/lib/client/matrix/matrix_native_implementations.dart @@ -11,8 +11,10 @@ class NativeImplementationsCustom extends NativeImplementationsIsolate { NativeImplementationsCustom(super.compute); @override - FutureOr calcImageMetadata(Uint8List bytes, - {bool retryInDummy = false}) async { + FutureOr calcImageMetadata( + Uint8List bytes, { + bool retryInDummy = false, + }) async { return await runInBackground(_calcImageMetadata, bytes); } @@ -35,8 +37,12 @@ class NativeImplementationsCustom extends NativeImplementationsIsolate { width = 128; } - blurhashImage = - copyResize(image, width: width, height: height, maintainAspect: true); + blurhashImage = copyResize( + image, + width: width, + height: height, + maintainAspect: true, + ); } String blurhash = BlurHash.encode( diff --git a/commet/lib/client/matrix/matrix_room.dart b/commet/lib/client/matrix/matrix_room.dart index dbe8c11db..d178816f0 100644 --- a/commet/lib/client/matrix/matrix_room.dart +++ b/commet/lib/client/matrix/matrix_room.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; import 'dart:ui'; + import 'package:commet/client/components/component_registry.dart'; import 'package:commet/client/components/direct_messages/direct_message_component.dart'; import 'package:commet/client/components/emoticon/emoticon.dart'; @@ -62,6 +63,7 @@ import 'package:matrix/src/utils/markdown.dart' as mx_markdown; import '../attachment.dart'; import '../client.dart'; + import 'package:matrix/matrix.dart' as matrix; class MatrixRoom extends Room { @@ -217,7 +219,10 @@ class MatrixRoom extends Room { StreamSubscription? _onUpdateSubscription; MatrixRoom( - MatrixClient client, matrix.Room room, matrix.Client matrixClient) { + MatrixClient client, + matrix.Room room, + matrix.Client matrixClient, + ) { _matrixRoom = room; _client = client; @@ -260,15 +265,26 @@ class MatrixRoom extends Room { Future updateAvatar({bool fromCache = true}) async { if (_matrixRoom.avatar != null) { - _avatar = MatrixMxcImage(_matrixRoom.avatar!, _matrixRoom.client, - thumbnailHeight: 64, fullResHeight: 128, autoLoadFullRes: false); + _avatar = MatrixMxcImage( + _matrixRoom.avatar!, + _matrixRoom.client, + thumbnailHeight: 64, + fullResHeight: 128, + autoLoadFullRes: false, + ); } else if (_matrixRoom.isDirectChat) { - var user = _matrixRoom - .unsafeGetUserFromMemoryOrFallback(_matrixRoom.directChatMatrixID!); + var user = _matrixRoom.unsafeGetUserFromMemoryOrFallback( + _matrixRoom.directChatMatrixID!, + ); var url = user.avatarUrl; if (url != null) { - _avatar = MatrixMxcImage(url, _matrixRoom.client, - thumbnailHeight: 64, fullResHeight: 128, autoLoadFullRes: false); + _avatar = MatrixMxcImage( + url, + _matrixRoom.client, + thumbnailHeight: 64, + fullResHeight: 128, + autoLoadFullRes: false, + ); } } @@ -281,8 +297,9 @@ class MatrixRoom extends Room { } if (eventUpdate.content["type"] == matrix.EventTypes.Message) { - var roomEvent = - await matrixRoom.getEventById(eventUpdate.content['event_id']); + var roomEvent = await matrixRoom.getEventById( + eventUpdate.content['event_id'], + ); if (roomEvent == null) { return; @@ -320,8 +337,10 @@ class MatrixRoom extends Room { handleNotification(event); } - Future handleNotification(TimelineEvent event, - {Function(String reason)? onNotificationRejected}) async { + Future handleNotification( + TimelineEvent event, { + Function(String reason)? onNotificationRejected, + }) async { if (!shouldNotify(event, onNotificationRejected: onNotificationRejected)) { onNotificationRejected?.call("shouldNotify returned false"); return; @@ -337,15 +356,20 @@ class MatrixRoom extends Room { // let push notifications handle it if (BuildConfig.ANDROID) { onNotificationRejected?.call( - "Notifications should be handled by a push service on Android, but we are in the desktop notifications handler"); + "Notifications should be handled by a push service on Android, but we are in the desktop notifications handler", + ); return; } - var notification = - await MessageNotificationContent.fromEvent(event, this); + var notification = await MessageNotificationContent.fromEvent( + event, + this, + ); if (notification != null) { - NotificationManager.notify(notification, - onNotificationRejected: onNotificationRejected); + NotificationManager.notify( + notification, + onNotificationRejected: onNotificationRejected, + ); } else { onNotificationRejected?.call("Notification content was null"); } @@ -353,18 +377,22 @@ class MatrixRoom extends Room { } @override - bool shouldNotify(TimelineEvent event, - {Function(String reason)? onNotificationRejected}) { + bool shouldNotify( + TimelineEvent event, { + Function(String reason)? onNotificationRejected, + }) { if ((client as MatrixClient).firstSyncComplete == false) { return false; } // never notify for a message that came from an account we are logged in to! - if (clientManager?.clients - .any((element) => element.self?.identifier == event.senderId) == + if (clientManager?.clients.any( + (element) => element.self?.identifier == event.senderId, + ) == true) { - onNotificationRejected - ?.call("Message came from a user logged in to this client"); + onNotificationRejected?.call( + "Message came from a user logged in to this client", + ); return false; } @@ -388,14 +416,18 @@ class MatrixRoom extends Room { @override Future> processAttachments( - List attachments) async { - return await Future.wait(attachments.map((e) async { - return (await processAttachment(e))!; - })); + List attachments, + ) async { + return await Future.wait( + attachments.map((e) async { + return (await processAttachment(e))!; + }), + ); } Future processAttachment( - PendingFileAttachment attachment) async { + PendingFileAttachment attachment, + ) async { await attachment.resolve(); if (attachment.data == null) return null; @@ -422,12 +454,14 @@ class MatrixRoom extends Room { final name = attachment.name ?? "unknown${fileExtension}"; - return MatrixProcessedAttachment(await matrix.MatrixImageFile.create( + return MatrixProcessedAttachment( + await matrix.MatrixImageFile.create( bytes: attachment.data!, name: name, mimeType: attachment.mimeType, - nativeImplementations: - (client as MatrixClient).nativeImplentations)); + nativeImplementations: (client as MatrixClient).nativeImplentations, + ), + ); } } catch (error, stack) { // This image is probably corrupt, since it has a mime type we should be able to display, @@ -441,11 +475,12 @@ class MatrixRoom extends Room { var decodedImage = await decodeImageFromList(attachment.thumbnailFile!); thumbnailImageFile = matrix.MatrixImageFile( - bytes: attachment.thumbnailFile!, - width: decodedImage.width, - height: decodedImage.height, - mimeType: attachment.thumbnailMime, - name: "thumbnail"); + bytes: attachment.thumbnailFile!, + width: decodedImage.width, + height: decodedImage.height, + mimeType: attachment.thumbnailMime, + name: "thumbnail", + ); } final name = attachment.name ?? "Unknown${fileExtension}"; @@ -465,20 +500,25 @@ class MatrixRoom extends Room { } return MatrixProcessedAttachment( - matrix.MatrixFile( - bytes: attachment.data!, name: name, mimeType: attachment.mimeType), - thumbnailFile: thumbnailImageFile); + matrix.MatrixFile( + bytes: attachment.data!, + name: name, + mimeType: attachment.mimeType, + ), + thumbnailFile: thumbnailImageFile, + ); } @override - Future sendMessage( - {String? message, - TimelineEvent? inReplyTo, - TimelineEvent? replaceEvent, - String? threadRootEventId, - String? threadLastEventId, - Map? fileExtraContent, - List? processedAttachments}) async { + Future sendMessage({ + String? message, + TimelineEvent? inReplyTo, + TimelineEvent? replaceEvent, + String? threadRootEventId, + String? threadLastEventId, + Map? fileExtraContent, + List? processedAttachments, + }) async { matrix.Event? replyingTo; if (inReplyTo != null) { @@ -487,28 +527,32 @@ class MatrixRoom extends Room { if (processedAttachments != null) { Future.wait( - processedAttachments.whereType().map((e) { - return _matrixRoom.sendFileEvent(e.file, + processedAttachments.whereType().map((e) { + return _matrixRoom.sendFileEvent( + e.file, threadLastEventId: threadLastEventId, threadRootEventId: threadRootEventId, extraContent: fileExtraContent, - thumbnail: e.thumbnailFile); - })); + thumbnail: e.thumbnailFile, + ); + }), + ); } if (message != null && message.trim().isNotEmpty) { final event = { 'msgtype': matrix.MessageTypes.Text, - 'body': message + 'body': message, }; var emoticons = getComponent(); - final html = mx_markdown.markdown(message, - getEmotePacks: emoticons != null - ? () => - emoticons.getEmotePacksFlat(matrix.ImagePackUsage.emoticon) - : null, - getMention: _matrixRoom.getMention); + final html = mx_markdown.markdown( + message, + getEmotePacks: emoticons != null + ? () => emoticons.getEmotePacksFlat(matrix.ImagePackUsage.emoticon) + : null, + getMention: _matrixRoom.getMention, + ); if (HtmlUnescape().convert(html.replaceAll(RegExp(r'
\n?'), '\n')) != event['body']) { @@ -533,11 +577,13 @@ class MatrixRoom extends Room { event["m.mentions"] = mentions; - var id = await _matrixRoom.sendEvent(event, - inReplyTo: replyingTo, - editEventId: replaceEvent?.eventId, - threadLastEventId: threadLastEventId, - threadRootEventId: threadRootEventId); + var id = await _matrixRoom.sendEvent( + event, + inReplyTo: replyingTo, + editEventId: replaceEvent?.eventId, + threadLastEventId: threadLastEventId, + threadRootEventId: threadRootEventId, + ); if (id != null) { var event = await _matrixRoom.getEventById(id); @@ -573,31 +619,55 @@ class MatrixRoom extends Room { event.content['url'] is String || event.content.containsKey('file') ? MatrixTimelineEventSticker(event, client: c) : null, - matrix.EventTypes.Encrypted => - MatrixTimelineEventEncrypted(event, client: c), - matrix.EventTypes.RoomCreate => - MatrixTimelineEventCreateRoom(event, client: c), - matrix.EventTypes.RoomPowerLevels => - MatrixTimelineEventPowerLevels(event, client: c), - matrix.EventTypes.Reaction => - MatrixTimelineEventAddReaction(event, client: c), - matrix.EventTypes.RoomMember => - MatrixTimelineEventMembership(event, client: c), - matrix.EventTypes.Redaction => - MatrixTimelineEventRedaction(event, client: c), - matrix.EventTypes.CallInvite => - MatrixTimelineEventCall(event, client: c), - matrix.EventTypes.CallAnswer => - MatrixTimelineEventCall(event, client: c), - matrix.EventTypes.CallHangup => - MatrixTimelineEventCall(event, client: c), - matrix.EventTypes.CallReject => - MatrixTimelineEventCall(event, client: c), - matrix.EventTypes.RoomPinnedEvents => - MatrixTimelineEventPinnedMessages(event, client: c), - "chat.commet.calendar_events" => - MatrixTimelineEventEditCalendar(event, client: c), - _ => null + matrix.EventTypes.Encrypted => MatrixTimelineEventEncrypted( + event, + client: c, + ), + matrix.EventTypes.RoomCreate => MatrixTimelineEventCreateRoom( + event, + client: c, + ), + matrix.EventTypes.RoomPowerLevels => MatrixTimelineEventPowerLevels( + event, + client: c, + ), + matrix.EventTypes.Reaction => MatrixTimelineEventAddReaction( + event, + client: c, + ), + matrix.EventTypes.RoomMember => MatrixTimelineEventMembership( + event, + client: c, + ), + matrix.EventTypes.Redaction => MatrixTimelineEventRedaction( + event, + client: c, + ), + matrix.EventTypes.CallInvite => MatrixTimelineEventCall( + event, + client: c, + ), + matrix.EventTypes.CallAnswer => MatrixTimelineEventCall( + event, + client: c, + ), + matrix.EventTypes.CallHangup => MatrixTimelineEventCall( + event, + client: c, + ), + matrix.EventTypes.CallReject => MatrixTimelineEventCall( + event, + client: c, + ), + matrix.EventTypes.RoomPinnedEvents => MatrixTimelineEventPinnedMessages( + event, + client: c, + ), + "chat.commet.calendar_events" => MatrixTimelineEventEditCalendar( + event, + client: c, + ), + _ => null, }; if (result != null) { @@ -632,7 +702,9 @@ class MatrixRoom extends Room { @override Future addReaction( - TimelineEvent reactingTo, Emoticon reaction) async { + TimelineEvent reactingTo, + Emoticon reaction, + ) async { var recent = client.getComponent(); recent?.reactedEmoticon(this, reaction); @@ -647,7 +719,9 @@ class MatrixRoom extends Room { @override Future removeReaction( - TimelineEvent reactingTo, Emoticon reaction) async { + TimelineEvent reactingTo, + Emoticon reaction, + ) async { return (timeline! as MatrixTimeline).removeReaction(reactingTo, reaction); } @@ -687,9 +761,9 @@ class MatrixRoom extends Room { final comp = client.getComponent(); if (comp?.isRoomDirectMessage(this) == true) { - var user = await client - .getComponent()! - .getProfile(comp!.getDirectMessagePartnerId(this)!); + var user = await client.getComponent()!.getProfile( + comp!.getDirectMessagePartnerId(this)!, + ); if (user.avatar != null) { return user.avatar; @@ -728,8 +802,11 @@ class MatrixRoom extends Room { @override Future> fetchMembersList({bool cache = false}) async { - var results = await _matrixRoom - .requestParticipants([matrix.Membership.join], true, cache); + var results = await _matrixRoom.requestParticipants( + [matrix.Membership.join], + true, + cache, + ); return results.map((e) => MatrixMember(_client, e)).toList(); } @@ -740,7 +817,9 @@ class MatrixRoom extends Room { @override Member getMemberOrFallback(String id) { return MatrixMember( - _client, _matrixRoom.unsafeGetUserFromMemoryOrFallback(id)); + _client, + _matrixRoom.unsafeGetUserFromMemoryOrFallback(id), + ); } @override @@ -771,21 +850,24 @@ class MatrixRoom extends Room { if (roomVersion != null && roomVersion >= 12) { if (_matrixRoom.roomVersion != null && creator != null) { - var additionalCreators = - creationEvent?.content.tryGetList("additional_creators"); + var additionalCreators = creationEvent?.content.tryGetList( + "additional_creators", + ); for (var id in [ creator, - if (additionalCreators != null) ...additionalCreators + if (additionalCreators != null) ...additionalCreators, ]) { result.add((getMemberOrFallback(id), MatrixRole(150))); } } } - result.addAll(ids - .map((e) => (getMemberOrFallback(e), MatrixRole(roles[e]))) - .where((element) => element.$2.rank != 0)); + result.addAll( + ids + .map((e) => (getMemberOrFallback(e), MatrixRole(roles[e]))) + .where((element) => element.$2.rank != 0), + ); result; @@ -817,8 +899,9 @@ class MatrixRoom extends Room { } } - var name = - matrixRoom.unsafeGetUserFromMemoryOrFallback(partner).displayName; + var name = matrixRoom + .unsafeGetUserFromMemoryOrFallback(partner) + .displayName; if (name != null) { _displayName = name; } @@ -859,9 +942,11 @@ class MatrixRoom extends Room { return preferences.previewMediaInPrivateRooms.value; case matrix.JoinRules.restricted: - if (_client.spaces.any((e) => - e.visibility is RoomVisibilityPublic && - e.containsRoom(_matrixRoom.id))) { + if (_client.spaces.any( + (e) => + e.visibility is RoomVisibilityPublic && + e.containsRoom(_matrixRoom.id), + )) { // if any public space contains this room, consider the room public // this is kind of flawed, because there could be public spaces we are not a member of return preferences.previewMediaInPublicRooms.value; @@ -912,14 +997,16 @@ class MatrixRoom extends Room { @override List get availableRoles => [ - MatrixRole(100), - MatrixRole(50), - if (getComponent()?.hasCalendar == true) - MatrixRole(25, - nameOverride: "Calendar Moderator", - iconOverride: Icons.calendar_month), - MatrixRole(0), - ]; + MatrixRole(100), + MatrixRole(50), + if (getComponent()?.hasCalendar == true) + MatrixRole( + 25, + nameOverride: "Calendar Moderator", + iconOverride: Icons.calendar_month, + ), + MatrixRole(0), + ]; @override Future setMemberRole(String id, Role role) async { @@ -988,14 +1075,16 @@ class MatrixRoom extends Room { case matrix.JoinRules.private: return RoomVisibilityPrivate(); case matrix.JoinRules.restricted: - return RoomVisibilityRestricted(matrixRoom - .getState(matrix.EventTypes.RoomJoinRules) - ?.content - .tryGetList>("allow") - ?.map((i) => i.tryGet("room_id")) - .nonNulls - .toList() ?? - []); + return RoomVisibilityRestricted( + matrixRoom + .getState(matrix.EventTypes.RoomJoinRules) + ?.content + .tryGetList>("allow") + ?.map((i) => i.tryGet("room_id")) + .nonNulls + .toList() ?? + [], + ); case matrix.JoinRules.knockRestricted: return RoomVisibilityPrivate(); case null: @@ -1006,24 +1095,33 @@ class MatrixRoom extends Room { @override Future setVisibility(RoomVisibility visibility) async { var state = switch (visibility) { - final RoomVisibilityPrivate _ => matrix.StateEvent(content: { - "join_rule": "invite", - }, type: matrix.EventTypes.RoomJoinRules), + final RoomVisibilityPrivate _ => matrix.StateEvent( + content: {"join_rule": "invite"}, + type: matrix.EventTypes.RoomJoinRules, + ), final RoomVisibilityPublic _ => matrix.StateEvent( - content: {"join_rule": "public"}, - type: matrix.EventTypes.RoomJoinRules), - final RoomVisibilityRestricted restricted => matrix.StateEvent(content: { + content: {"join_rule": "public"}, + type: matrix.EventTypes.RoomJoinRules, + ), + final RoomVisibilityRestricted restricted => matrix.StateEvent( + content: { "join_rule": "restricted", "allow": [ for (var i in restricted.spaces) {"room_id": i, "type": "m.room_membership"}, - ] - }, type: matrix.EventTypes.RoomJoinRules), + ], + }, + type: matrix.EventTypes.RoomJoinRules, + ), RoomVisibility() => throw UnimplementedError(), }; - await _matrixRoom.client - .setRoomStateWithKey(_matrixRoom.id, state.type, "", state.content); + await _matrixRoom.client.setRoomStateWithKey( + _matrixRoom.id, + state.type, + "", + state.content, + ); } Set _findEventMentions(html_dom.Document document) { diff --git a/commet/lib/client/matrix/matrix_room_preview.dart b/commet/lib/client/matrix/matrix_room_preview.dart index 74e783542..3abb878a3 100644 --- a/commet/lib/client/matrix/matrix_room_preview.dart +++ b/commet/lib/client/matrix/matrix_room_preview.dart @@ -24,11 +24,18 @@ class MatrixSpaceRoomChunkPreview implements RoomPreview { @override late c.RoomType type; - MatrixSpaceRoomChunkPreview(this.chunk, this.matrixClient, - {this.via = const []}) { + MatrixSpaceRoomChunkPreview( + this.chunk, + this.matrixClient, { + this.via = const [], + }) { avatar = chunk.avatarUrl != null - ? MatrixMxcImage(chunk.avatarUrl!, matrixClient, - doFullres: false, doThumbnail: true) + ? MatrixMxcImage( + chunk.avatarUrl!, + matrixClient, + doFullres: false, + doThumbnail: true, + ) : null; if (chunk.roomType == "m.space") { diff --git a/commet/lib/client/matrix/matrix_space.dart b/commet/lib/client/matrix/matrix_space.dart index fa2573714..7598957ef 100644 --- a/commet/lib/client/matrix/matrix_space.dart +++ b/commet/lib/client/matrix/matrix_space.dart @@ -30,8 +30,9 @@ class MatrixSpace extends Space { final StreamController _onUpdate = StreamController.broadcast(); final NotifyingList _rooms = NotifyingList.empty(growable: true); - final NotifyingList _previews = - NotifyingList.empty(growable: true); + final NotifyingList _previews = NotifyingList.empty( + growable: true, + ); NotifyingList _subspaces = NotifyingList.empty(growable: true); @@ -194,7 +195,10 @@ class MatrixSpace extends Space { } MatrixSpace( - MatrixClient client, matrix.Room room, matrix.Client matrixClient) { + MatrixClient client, + matrix.Room room, + matrix.Client matrixClient, + ) { _matrixRoom = room; _matrixClient = matrixClient; _client = client; @@ -230,7 +234,8 @@ class MatrixSpace extends Space { } void onStateChanged( - ({String roomId, matrix.StrippedStateEvent state}) event) { + ({String roomId, matrix.StrippedStateEvent state}) event, + ) { refresh(); } @@ -257,11 +262,14 @@ class MatrixSpace extends Space { } void updateAvatar() { - var avatar = MatrixMxcImage(_matrixRoom.avatar!, _matrixClient, - doThumbnail: true, - thumbnailHeight: 128, - fullResHeight: 384, - autoLoadFullRes: false); + var avatar = MatrixMxcImage( + _matrixRoom.avatar!, + _matrixClient, + doThumbnail: true, + thumbnailHeight: 128, + fullResHeight: 384, + autoLoadFullRes: false, + ); _avatar = avatar; } @@ -274,9 +282,11 @@ class MatrixSpace extends Space { _matrixClient.getSpaceHierarchy(identifier, maxDepth: 1).then((value) { var chunk = value.rooms .where((element) => element.roomId == leftRoom.identifier) - .where((element) => - _matrixClient.getRoomById(element.roomId)?.membership != - matrix.Membership.join) + .where( + (element) => + _matrixClient.getRoomById(element.roomId)?.membership != + matrix.Membership.join, + ) .firstOrNull; if (chunk == null) return; @@ -289,8 +299,9 @@ class MatrixSpace extends Space { if (viaContent is List) { via = List.from(viaContent); } - _previews - .add(MatrixSpaceRoomChunkPreview(chunk, _matrixClient, via: via)); + _previews.add( + MatrixSpaceRoomChunkPreview(chunk, _matrixClient, via: via), + ); }); _fullyLoaded = true; } @@ -321,8 +332,9 @@ class MatrixSpace extends Space { if (!containsRoom(room.identifier) && !client.hasSpace(room.identifier)) { _rooms.add(room); - _previews - .removeWhere((element) => element.roomId == room.identifier); + _previews.removeWhere( + (element) => element.roomId == room.identifier, + ); } } } @@ -344,9 +356,11 @@ class MatrixSpace extends Space { } void _onRoomAdded(Room room) { - _subscriptions.add(room.onUpdate.listen((event) { - _onChildUpdated.add(room); - })); + _subscriptions.add( + room.onUpdate.listen((event) { + _onChildUpdated.add(room); + }), + ); } @override @@ -358,8 +372,10 @@ class MatrixSpace extends Space { @override Future> fetchChildren() async { - var response = - await _matrixClient.getSpaceHierarchy(identifier, maxDepth: 5); + var response = await _matrixClient.getSpaceHierarchy( + identifier, + maxDepth: 5, + ); return response.rooms .where((element) => element.roomId != identifier) @@ -374,40 +390,48 @@ class MatrixSpace extends Space { ignoreNextAvatarUpdate = true; _avatar = avatar; - await _matrixRoom.setAvatar(matrix.MatrixImageFile( + await _matrixRoom.setAvatar( + matrix.MatrixImageFile( bytes: bytes, name: "avatar", - mimeType: mimeType == "" ? null : mimeType)); + mimeType: mimeType == "" ? null : mimeType, + ), + ); _onUpdate.add(null); } @override Future loadExtra() async { - var response = - await _matrixClient.getSpaceHierarchy(identifier, maxDepth: 1); + var response = await _matrixClient.getSpaceHierarchy( + identifier, + maxDepth: 1, + ); // read child rooms response.rooms .where((element) => element.roomId != identifier) - .where((element) => - _matrixClient.getRoomById(element.roomId)?.membership != - matrix.Membership.join) + .where( + (element) => + _matrixClient.getRoomById(element.roomId)?.membership != + matrix.Membership.join, + ) .forEach((element) { - _previews.removeWhere((i) => i.roomId == element.roomId); + _previews.removeWhere((i) => i.roomId == element.roomId); - var viaContent = _matrixRoom - .getState(matrix.EventTypes.SpaceChild, element.roomId) - ?.content["via"]; + var viaContent = _matrixRoom + .getState(matrix.EventTypes.SpaceChild, element.roomId) + ?.content["via"]; - List via = const []; + List via = const []; - if (viaContent is List) { - via = List.from(viaContent); - } + if (viaContent is List) { + via = List.from(viaContent); + } - _previews - .add(MatrixSpaceRoomChunkPreview(element, _matrixClient, via: via)); - }); + _previews.add( + MatrixSpaceRoomChunkPreview(element, _matrixClient, via: via), + ); + }); _fullyLoaded = true; } @@ -453,8 +477,9 @@ class MatrixSpace extends Space { var thisRoom = update[_matrixRoom.id]; if (thisRoom != null) { - if (thisRoom.timeline?.events - ?.any((i) => i.type == matrix.EventTypes.SpaceChild) == + if (thisRoom.timeline?.events?.any( + (i) => i.type == matrix.EventTypes.SpaceChild, + ) == true) { print("A child of this space has been modified!"); loadExtra(); @@ -495,17 +520,22 @@ class MatrixSpace extends Space { } @override - Future setChildrenOrder(List ordered, - {Function(double?)? onProgressChanged}) async { - var orderKeys = - List.generate(ordered.length, (i) => RandomUtils.getRandomString(10)); + Future setChildrenOrder( + List ordered, { + Function(double?)? onProgressChanged, + }) async { + var orderKeys = List.generate( + ordered.length, + (i) => RandomUtils.getRandomString(10), + ); orderKeys.sort(); for (int i = 0; i < ordered.length; i++) { var item = ordered[i]; - var existing = _matrixRoom.spaceChildren - .firstWhereOrNull((e) => e.roomId == item.id); + var existing = _matrixRoom.spaceChildren.firstWhereOrNull( + (e) => e.roomId == item.id, + ); var order = orderKeys[i]; var suggested = existing?.suggested; @@ -515,11 +545,15 @@ class MatrixSpace extends Space { await exponentialBackoff(() async { await _matrixRoom.client.setRoomStateWithKey( - _matrixRoom.id, matrix.EventTypes.SpaceChild, item.id, { - 'via': via, - 'order': order, - if (suggested != null) 'suggested': suggested, - }); + _matrixRoom.id, + matrix.EventTypes.SpaceChild, + item.id, + { + 'via': via, + 'order': order, + if (suggested != null) 'suggested': suggested, + }, + ); }); } diff --git a/commet/lib/client/matrix/matrix_timeline.dart b/commet/lib/client/matrix/matrix_timeline.dart index adbef125a..1ac83ce83 100644 --- a/commet/lib/client/matrix/matrix_timeline.dart +++ b/commet/lib/client/matrix/matrix_timeline.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:commet/client/components/emoticon/emoticon.dart'; import 'package:commet/client/matrix/components/read_receipts/matrix_read_receipt_component.dart'; import 'package:commet/client/matrix/matrix_client.dart'; @@ -10,6 +11,7 @@ import 'package:commet/client/timeline_events/timeline_event_sticker.dart'; import 'package:commet/debug/log.dart'; import '../client.dart'; + import 'package:matrix/matrix.dart' as matrix; class MatrixTimeline extends Timeline { @@ -51,10 +53,11 @@ class MatrixTimeline extends Timeline { } _matrixTimeline = await _matrixRoom.getTimeline( - onInsert: onEventInserted, - onChange: onEventChanged, - onRemove: onEventRemoved, - eventContextId: contextEventId); + onInsert: onEventInserted, + onChange: onEventChanged, + onRemove: onEventRemoved, + eventContextId: contextEventId, + ); if (_matrixTimeline?.events.isEmpty == true) { await _matrixTimeline?.requestHistory(); @@ -84,8 +87,9 @@ class MatrixTimeline extends Timeline { if (index < _matrixTimeline!.events.length) { events[index] = (room as MatrixRoom).convertEvent( - _matrixTimeline!.events[index], - timeline: _matrixTimeline); + _matrixTimeline!.events[index], + timeline: _matrixTimeline, + ); notifyChanged(index); } @@ -155,7 +159,8 @@ class MatrixTimeline extends Timeline { if (event.status == TimelineEventStatus.synced || event.status == TimelineEventStatus.sent) { await _matrixTimeline?.setReadMarker( - public: receipts?.usePublicReadReceiptsForRoom); + public: receipts?.usePublicReadReceiptsForRoom, + ); receipts?.handleEvent(event.eventId, room.client.self!.identifier); } @@ -169,12 +174,17 @@ class MatrixTimeline extends Timeline { } Future removeReaction( - TimelineEvent reactingTo, Emoticon reaction) async { + TimelineEvent reactingTo, + Emoticon reaction, + ) async { var event = await _matrixRoom.getEventById(reactingTo.eventId); if (event == null) return; if (!event.hasAggregatedEvents( - _matrixTimeline!, matrix.RelationshipTypes.reaction)) return; + _matrixTimeline!, + matrix.RelationshipTypes.reaction, + )) + return; var events = event .aggregatedEvents(_matrixTimeline!, matrix.RelationshipTypes.reaction) @@ -204,7 +214,8 @@ class MatrixTimeline extends Timeline { @override bool canDeleteEvent(TimelineEvent event) { if (event.senderId != room.client.self!.identifier && - room.permissions.canDeleteOtherUserMessages != true) return false; + room.permissions.canDeleteOtherUserMessages != true) + return false; if (event is TimelineEventMessage) { return true; diff --git a/commet/lib/client/matrix/timeline_events/matrix_per_message_profile.dart b/commet/lib/client/matrix/timeline_events/matrix_per_message_profile.dart index 5111e9b22..366f5189c 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_per_message_profile.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_per_message_profile.dart @@ -11,16 +11,18 @@ class MatrixPerMessageProfileData { final bool hasFallback; final List pronouns; - const MatrixPerMessageProfileData( - {required this.id, - this.displayName, - this.avatarUrl, - this.clearAvatar = false, - this.hasFallback = false, - this.pronouns = const []}); + const MatrixPerMessageProfileData({ + required this.id, + this.displayName, + this.avatarUrl, + this.clearAvatar = false, + this.hasFallback = false, + this.pronouns = const [], + }); static MatrixPerMessageProfileData? fromEventContent( - Map content) { + Map content, + ) { var profile = content[stableKey] ?? content[unstableKey]; if (profile is! Map) { @@ -55,12 +57,13 @@ class MatrixPerMessageProfileData { } return MatrixPerMessageProfileData( - id: id is String ? id : "", - displayName: displayName as String?, - avatarUrl: avatarUrl, - clearAvatar: clearAvatar, - hasFallback: profile["has_fallback"] == true, - pronouns: parsePronounsField(profile[pronounsFieldKey])); + id: id is String ? id : "", + displayName: displayName as String?, + avatarUrl: avatarUrl, + clearAvatar: clearAvatar, + hasFallback: profile["has_fallback"] == true, + pronouns: parsePronounsField(profile[pronounsFieldKey]), + ); } } @@ -70,9 +73,10 @@ String stripPerMessageProfileFallback(String body, String displayName) { } final RegExp _htmlFallback = RegExp( - r'^(\s*.*?)?\s*]*data-mx-profile-fallback[^>]*>.*?', - caseSensitive: false, - dotAll: true); + r'^(\s*.*?)?\s*]*data-mx-profile-fallback[^>]*>.*?', + caseSensitive: false, + dotAll: true, +); String stripPerMessageProfileFallbackHtml(String html) => html.replaceFirstMapped(_htmlFallback, (match) => match.group(1) ?? ""); diff --git a/commet/lib/client/matrix/timeline_events/matrix_timeline_event.dart b/commet/lib/client/matrix/timeline_events/matrix_timeline_event.dart index c4a7d7c8f..09bcfc79f 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_timeline_event.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_timeline_event.dart @@ -36,11 +36,11 @@ abstract class MatrixTimelineEvent implements TimelineEvent { @override TimelineEventStatus get status => switch (event.status) { - matrix.EventStatus.error => TimelineEventStatus.error, - matrix.EventStatus.sending => TimelineEventStatus.sending, - matrix.EventStatus.sent => TimelineEventStatus.sent, - matrix.EventStatus.synced => TimelineEventStatus.synced, - }; + matrix.EventStatus.error => TimelineEventStatus.error, + matrix.EventStatus.sending => TimelineEventStatus.sending, + matrix.EventStatus.sent => TimelineEventStatus.sent, + matrix.EventStatus.synced => TimelineEventStatus.synced, + }; @override String get plainTextBody => event.plaintextBody; diff --git a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_call.dart b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_call.dart index 31527fae4..51d1d2fab 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_call.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_call.dart @@ -9,29 +9,33 @@ class MatrixTimelineEventCall extends MatrixTimelineEvent implements TimelineEventGeneric { MatrixTimelineEventCall(super.event, {required super.client}); - String messageUserAnsweredCall(String user) => - Intl.message("$user answered the call", - desc: "Message body for when a user answers a call", - args: [user], - name: "messageUserAnsweredCall"); + String messageUserAnsweredCall(String user) => Intl.message( + "$user answered the call", + desc: "Message body for when a user answers a call", + args: [user], + name: "messageUserAnsweredCall", + ); - String messageUserHangupCall(String user) => - Intl.message("$user ended the call", - desc: "Message body for when a user hangs up a call", - args: [user], - name: "messageUserHangupCall"); + String messageUserHangupCall(String user) => Intl.message( + "$user ended the call", + desc: "Message body for when a user hangs up a call", + args: [user], + name: "messageUserHangupCall", + ); - String messageUserRejectCall(String user) => - Intl.message("$user rejected the call", - desc: "Message body for when a user rejects a call", - args: [user], - name: "messageUserRejectCall"); + String messageUserRejectCall(String user) => Intl.message( + "$user rejected the call", + desc: "Message body for when a user rejects a call", + args: [user], + name: "messageUserRejectCall", + ); - String messageUserInviteCall(String user) => - Intl.message("$user started a call", - desc: "Message body for when a user starts a call", - args: [user], - name: "messageUserInviteCall"); + String messageUserInviteCall(String user) => Intl.message( + "$user started a call", + desc: "Message body for when a user starts a call", + args: [user], + name: "messageUserInviteCall", + ); @override IconData get icon { diff --git a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_create_room.dart b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_create_room.dart index 67bd5d9e6..256051e44 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_create_room.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_create_room.dart @@ -8,11 +8,12 @@ class MatrixTimelineEventCreateRoom extends MatrixTimelineEvent implements TimelineEventGeneric { MatrixTimelineEventCreateRoom(super.event, {required super.client}); - String messagePlaceholderUserCreatedRoom(String user) => - Intl.message("$user created the room!", - desc: "Message body for when a user creates the room", - args: [user], - name: "messagePlaceholderUserCreatedRoom"); + String messagePlaceholderUserCreatedRoom(String user) => Intl.message( + "$user created the room!", + desc: "Message body for when a user creates the room", + args: [user], + name: "messagePlaceholderUserCreatedRoom", + ); @override IconData get icon { diff --git a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_edit_calendar.dart b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_edit_calendar.dart index 2fba487af..fccd5f443 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_edit_calendar.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_edit_calendar.dart @@ -8,11 +8,12 @@ class MatrixTimelineEventEditCalendar extends MatrixTimelineEvent implements TimelineEventGeneric { MatrixTimelineEventEditCalendar(super.event, {required super.client}); - String messagePlaceholderUserEditedCalendar(String user) => - Intl.message("$user edited the calendar", - desc: "Message body for when a user edits the room calendar", - args: [user], - name: "messagePlaceholderUserEditedCalendar"); + String messagePlaceholderUserEditedCalendar(String user) => Intl.message( + "$user edited the calendar", + desc: "Message body for when a user edits the room calendar", + args: [user], + name: "messagePlaceholderUserEditedCalendar", + ); @override IconData get icon { diff --git a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_emote.dart b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_emote.dart index 73df6fc14..cf2398811 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_emote.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_emote.dart @@ -12,18 +12,20 @@ class MatrixTimelineEventEmote extends MatrixTimelineEvent implements TimelineEventEmote, TimelineEventGeneric { MatrixTimelineEventEmote(super.event, {required super.client}); - String messageUserEmote(String user, String emote) => - Intl.message("*$user $emote", - desc: "Message to display when a user does a custom emote (/me)", - args: [user, emote], - name: "messageUserEmote"); + String messageUserEmote(String user, String emote) => Intl.message( + "*$user $emote", + desc: "Message to display when a user does a custom emote (/me)", + args: [user, emote], + name: "messageUserEmote", + ); String messageUserEmoteViaProfile(String user, String emote, String sender) => - Intl.message("*$user $emote (via $sender)", - desc: - "Message to display when a user does a custom emote (/me) with a per message profile", - args: [user, emote, sender], - name: "messageUserEmoteViaProfile"); + Intl.message( + "*$user $emote (via $sender)", + desc: "Message to display when a user does a custom emote (/me) with a per message profile", + args: [user, emote, sender], + name: "messageUserEmoteViaProfile", + ); @override String getBody({Timeline? timeline}) { diff --git a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_membership.dart b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_membership.dart index 7adf59035..6ff930e56 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_membership.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_membership.dart @@ -19,97 +19,108 @@ enum _MembershipType { unknown, } -enum _SenderType { - self, - other, -} +enum _SenderType { self, other } class MatrixTimelineEventMembership extends MatrixTimelineEvent implements TimelineEventGeneric { MatrixTimelineEventMembership(super.event, {required super.client}); - String messagePlaceholderUserJoinedRoom(String user) => - Intl.message("$user joined the room!", - desc: "Message body for when a user joins the room", - args: [user], - name: "messagePlaceholderUserJoinedRoom"); - - String messagePlaceholderUserLeftRoom(String user) => - Intl.message("$user left the room", - desc: "Message body for when a user leaves the room", - args: [user], - name: "messagePlaceholderUserLeftRoom"); - - String messagePlaceholderUserUpdatedAvatar(String user) => - Intl.message("$user updated their avatar", - desc: "Message body for when a user updates their avatar", - args: [user], - name: "messagePlaceholderUserUpdatedAvatar"); - - String messagePlaceholderUserUpdatedName(String user) => - Intl.message("$user updated their display name", - desc: "Message body for when a user updates their display name", - args: [user], - name: "messagePlaceholderUserUpdatedName"); + String messagePlaceholderUserJoinedRoom(String user) => Intl.message( + "$user joined the room!", + desc: "Message body for when a user joins the room", + args: [user], + name: "messagePlaceholderUserJoinedRoom", + ); + + String messagePlaceholderUserLeftRoom(String user) => Intl.message( + "$user left the room", + desc: "Message body for when a user leaves the room", + args: [user], + name: "messagePlaceholderUserLeftRoom", + ); + + String messagePlaceholderUserUpdatedAvatar(String user) => Intl.message( + "$user updated their avatar", + desc: "Message body for when a user updates their avatar", + args: [user], + name: "messagePlaceholderUserUpdatedAvatar", + ); + + String messagePlaceholderUserUpdatedName(String user) => Intl.message( + "$user updated their display name", + desc: "Message body for when a user updates their display name", + args: [user], + name: "messagePlaceholderUserUpdatedName", + ); String messagePlaceholderUserUpdatedNameDetailed( - String user, String newName) => - Intl.message("$user changed their display name to \"$newName\"", - desc: "Message body for when a user updates their display name", - args: [user, newName], - name: "messagePlaceholderUserUpdatedNameDetailed"); + String user, + String newName, + ) => Intl.message( + "$user changed their display name to \"$newName\"", + desc: "Message body for when a user updates their display name", + args: [user, newName], + name: "messagePlaceholderUserUpdatedNameDetailed", + ); String messagePlaceholderUserInvited(String sender, String invitedUser) => - Intl.message("$sender invited $invitedUser", - desc: "Message body for when a user invites another user to the room", - args: [sender, invitedUser], - name: "messagePlaceholderUserInvited"); - - String messagePlaceholderUserRejectedInvite(String user) => - Intl.message("$user rejected the invitation", - desc: "Message body for when a user rejected an invitation to a room", - args: [user], - name: "messagePlaceholderUserRejectedInvite"); + Intl.message( + "$sender invited $invitedUser", + desc: "Message body for when a user invites another user to the room", + args: [sender, invitedUser], + name: "messagePlaceholderUserInvited", + ); + + String messagePlaceholderUserRejectedInvite(String user) => Intl.message( + "$user rejected the invitation", + desc: "Message body for when a user rejected an invitation to a room", + args: [user], + name: "messagePlaceholderUserRejectedInvite", + ); String messageUserRetractedInvite(String sender, String user) => Intl.message( - "$sender uninvited $user", - desc: "Message body for when a user's invitation to a room was withdrawn", - args: [sender, user], - name: "messageUserRetractedInvite"); - - String messageUserAcceptedInvite(String user) => - Intl.message("$user accepted the invitiation", - desc: "Message body for when a user accepted an invitation to a room", - args: [user], - name: "messageUserAcceptedInvite"); - - String messageUserBanned(String sender, String user) => - Intl.message("$sender banned $user", - desc: "Message body for when a user bans another user from the room", - args: [sender, user], - name: "messageUserBanned"); - - String messageUserUnbanned(String sender, String user) => - Intl.message("$sender unbanned $user", - desc: "Message body for when a user reverts a ban of another user", - args: [sender, user], - name: "messageUserUnbanned"); + "$sender uninvited $user", + desc: "Message body for when a user's invitation to a room was withdrawn", + args: [sender, user], + name: "messageUserRetractedInvite", + ); + + String messageUserAcceptedInvite(String user) => Intl.message( + "$user accepted the invitiation", + desc: "Message body for when a user accepted an invitation to a room", + args: [user], + name: "messageUserAcceptedInvite", + ); + + String messageUserBanned(String sender, String user) => Intl.message( + "$sender banned $user", + desc: "Message body for when a user bans another user from the room", + args: [sender, user], + name: "messageUserBanned", + ); + + String messageUserUnbanned(String sender, String user) => Intl.message( + "$sender unbanned $user", + desc: "Message body for when a user reverts a ban of another user", + args: [sender, user], + name: "messageUserUnbanned", + ); @override IconData get icon => switch (_getType()) { - _MembershipType.join => Icons.waving_hand_rounded, - _MembershipType.leave => Icons.subdirectory_arrow_left_rounded, - _MembershipType.kick => Icons.subdirectory_arrow_left_rounded, - _MembershipType.invite => Icons.person_add, - _MembershipType.updateDisplayName => Icons.person, - _MembershipType.updateAvatar => Icons.person, - _MembershipType.unknown => Icons.person, - _MembershipType.inviteRejected => Icons.person_remove, - _MembershipType.uninvited => Icons.person_remove, - _MembershipType.acceptedInvite => Icons.waving_hand_rounded, - _MembershipType.ban => Icons.person_remove, - _MembershipType.unban => Icons.shield_outlined, - }; + _MembershipType.join => Icons.waving_hand_rounded, + _MembershipType.leave => Icons.subdirectory_arrow_left_rounded, + _MembershipType.kick => Icons.subdirectory_arrow_left_rounded, + _MembershipType.invite => Icons.person_add, + _MembershipType.updateDisplayName => Icons.person, + _MembershipType.updateAvatar => Icons.person, + _MembershipType.unknown => Icons.person, + _MembershipType.inviteRejected => Icons.person_remove, + _MembershipType.uninvited => Icons.person_remove, + _MembershipType.acceptedInvite => Icons.waving_hand_rounded, + _MembershipType.ban => Icons.person_remove, + _MembershipType.unban => Icons.shield_outlined, + }; @override String get plainTextBody => getBody(); @@ -183,7 +194,9 @@ class MatrixTimelineEventMembership extends MatrixTimelineEvent case _MembershipType.updateDisplayName: if (newDisplayName != null) return messagePlaceholderUserUpdatedNameDetailed( - event.stateKey!, newDisplayName); + event.stateKey!, + newDisplayName, + ); return messagePlaceholderUserUpdatedName(memberName); case _MembershipType.updateAvatar: return messagePlaceholderUserUpdatedAvatar(memberName); diff --git a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_message.dart b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_message.dart index 81a0423cf..3eb97730e 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_message.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_message.dart @@ -56,13 +56,15 @@ class MatrixTimelineEventMessage extends MatrixTimelineEvent @override String get plainTextBody => stripFallback(event.plaintextBody); - String _getPlaintextBody({Timeline? timeline}) => - stripFallback(_getRawPlaintextBody(timeline: timeline), - timeline: timeline); + String _getPlaintextBody({Timeline? timeline}) => stripFallback( + _getRawPlaintextBody(timeline: timeline), + timeline: timeline, + ); - String _getFormattedBody({Timeline? timeline}) => - stripFallbackHtml(_getRawFormattedBody(timeline: timeline), - timeline: timeline); + String _getFormattedBody({Timeline? timeline}) => stripFallbackHtml( + _getRawFormattedBody(timeline: timeline), + timeline: timeline, + ); String _getRawPlaintextBody({Timeline? timeline}) { var e = getDisplayEvent(timeline); @@ -125,13 +127,19 @@ class MatrixTimelineEventMessage extends MatrixTimelineEvent } if (isFormatted) { - bool mentionsRoom = mentions?["room"] == true && + bool mentionsRoom = + mentions?["room"] == true && MatrixRoomPermissions.canUserMentionRoom( - displayEvent.senderId, (room as MatrixRoom).matrixRoom); + displayEvent.senderId, + (room as MatrixRoom).matrixRoom, + ); return MatrixHtmlParser.parse( - _getFormattedBody(timeline: timeline), client, room, - mentionsRoom: mentionsRoom); + _getFormattedBody(timeline: timeline), + client, + room, + mentionsRoom: mentionsRoom, + ); } else { var plain = _getPlaintextBody(timeline: timeline); if (plain != "") { @@ -164,54 +172,63 @@ class MatrixTimelineEventMessage extends MatrixTimelineEvent if (Mime.imageTypes.contains(event.attachmentMimetype)) { attachment = ImageAttachment( - MatrixMxcImage(event.attachmentMxcUrl!, mx, - blurhash: event.attachmentBlurhash, - doThumbnail: event.hasThumbnail, - doFullres: true, - thumbnailHeight: event.thumbnailHeight != null - ? min(700, event.thumbnailHeight!.toInt()) - : 700, - // I noticed on linux, decoding really high res images would cause a flicker, so we will limit it to 1440p - fullResHeight: PlatformUtils.isLinux - ? (event.attachmentHeight != null - ? min(1440, event.attachmentHeight!.toInt()) - : 1440) - : null, - autoLoadFullRes: !event.hasThumbnail, - matrixEvent: event), - MxcFileProvider(mx, event.attachmentMxcUrl!, event: event), - mimeType: event.attachmentMimetype, - width: width, - fileSize: event.infoMap['size'] as int?, - name: filename, - height: height); + MatrixMxcImage( + event.attachmentMxcUrl!, + mx, + blurhash: event.attachmentBlurhash, + doThumbnail: event.hasThumbnail, + doFullres: true, + thumbnailHeight: event.thumbnailHeight != null + ? min(700, event.thumbnailHeight!.toInt()) + : 700, + // I noticed on linux, decoding really high res images would cause a flicker, so we will limit it to 1440p + fullResHeight: PlatformUtils.isLinux + ? (event.attachmentHeight != null + ? min(1440, event.attachmentHeight!.toInt()) + : 1440) + : null, + autoLoadFullRes: !event.hasThumbnail, + matrixEvent: event, + ), + MxcFileProvider(mx, event.attachmentMxcUrl!, event: event), + mimeType: event.attachmentMimetype, + width: width, + fileSize: event.infoMap['size'] as int?, + name: filename, + height: height, + ); } else if (Mime.videoTypes.contains(event.attachmentMimetype)) { // Only load videos if the event has finished sending, otherwise // matrix dart sdk gives us the video file when we ask for thumbnail if (event.status.isSending == false) { attachment = VideoAttachment( - MxcFileProvider(mx, event.attachmentMxcUrl!, event: event), - thumbnail: event.videoThumbnailUrl != null - ? MatrixMxcImage(event.videoThumbnailUrl!, mx, - blurhash: event.attachmentBlurhash, - doFullres: false, - autoLoadFullRes: false, - doThumbnail: true, - matrixEvent: event) - : null, - name: filename, - mimeType: event.attachmentMimetype, - duration: event.attachmentDuration, - width: width, - fileSize: event.infoMap['size'] as int?, - height: height); - } - } else { - attachment = FileAttachment( MxcFileProvider(mx, event.attachmentMxcUrl!, event: event), + thumbnail: event.videoThumbnailUrl != null + ? MatrixMxcImage( + event.videoThumbnailUrl!, + mx, + blurhash: event.attachmentBlurhash, + doFullres: false, + autoLoadFullRes: false, + doThumbnail: true, + matrixEvent: event, + ) + : null, name: filename, mimeType: event.attachmentMimetype, - fileSize: event.infoMap['size'] as int?); + duration: event.attachmentDuration, + width: width, + fileSize: event.infoMap['size'] as int?, + height: height, + ); + } + } else { + attachment = FileAttachment( + MxcFileProvider(mx, event.attachmentMxcUrl!, event: event), + name: filename, + mimeType: event.attachmentMimetype, + fileSize: event.infoMap['size'] as int?, + ); } return List.from([attachment]); @@ -264,8 +281,11 @@ class MatrixTimelineEventMessage extends MatrixTimelineEvent } class PlaintextMessageBody extends StatelessWidget { - const PlaintextMessageBody( - {required this.content, required this.clientIdentifier, super.key}); + const PlaintextMessageBody({ + required this.content, + required this.clientIdentifier, + super.key, + }); final String content; final String clientIdentifier; @@ -274,9 +294,15 @@ class PlaintextMessageBody extends StatelessWidget { var document = html_parser.parse(content); bool big = shouldDoBigEmoji(document); - return Text.rich(TextSpan( + return Text.rich( + TextSpan( style: TextStyle(fontSize: big ? 34 : null), - children: TextUtils.linkifyString(content, - context: context, clientId: clientIdentifier))); + children: TextUtils.linkifyString( + content, + context: context, + clientId: clientIdentifier, + ), + ), + ); } } diff --git a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_mixin_per_message_profile.dart b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_mixin_per_message_profile.dart index c41030f97..62aa97de4 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_mixin_per_message_profile.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_mixin_per_message_profile.dart @@ -38,23 +38,28 @@ mixin MatrixTimelineEventPerMessageProfile on MatrixTimelineEvent } PerMessageProfile _buildProfile(MatrixPerMessageProfileData data) { - var avatarUrl = - data.avatarUrl != null ? Uri.tryParse(data.avatarUrl!) : null; + var avatarUrl = data.avatarUrl != null + ? Uri.tryParse(data.avatarUrl!) + : null; return PerMessageProfile( - id: data.id, - displayName: data.displayName, - avatar: avatarUrl != null - ? MatrixMxcImage(avatarUrl, client.getMatrixClient(), - doThumbnail: true, - autoLoadFullRes: false, - doFullres: false, - thumbnailHeight: 86) - : null, - clearAvatar: data.clearAvatar, - hasFallback: data.hasFallback, - pronouns: data.pronouns, - color: MatrixMember.hashColor("$senderId${data.id}")); + id: data.id, + displayName: data.displayName, + avatar: avatarUrl != null + ? MatrixMxcImage( + avatarUrl, + client.getMatrixClient(), + doThumbnail: true, + autoLoadFullRes: false, + doFullres: false, + thumbnailHeight: 86, + ) + : null, + clearAvatar: data.clearAvatar, + hasFallback: data.hasFallback, + pronouns: data.pronouns, + color: MatrixMember.hashColor("$senderId${data.id}"), + ); } String stripFallback(String body, {Timeline? timeline}) { diff --git a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_mixin_reactions.dart b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_mixin_reactions.dart index 74a03f83a..01a8ae85b 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_mixin_reactions.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_mixin_reactions.dart @@ -25,7 +25,9 @@ mixin MatrixTimelineEventReactions on MatrixTimelineEvent var mxTimeline = tl.matrixTimeline!; return matrixEvent.hasAggregatedEvents( - mxTimeline, matrix.RelationshipTypes.reaction); + mxTimeline, + matrix.RelationshipTypes.reaction, + ); } @override @@ -40,7 +42,10 @@ mixin MatrixTimelineEventReactions on MatrixTimelineEvent } var mxTimeline = tl.matrixTimeline!; if (!matrixEvent.hasAggregatedEvents( - mxTimeline, matrix.RelationshipTypes.reaction)) return {}; + mxTimeline, + matrix.RelationshipTypes.reaction, + )) + return {}; var reactions = >{}; @@ -48,8 +53,10 @@ mixin MatrixTimelineEventReactions on MatrixTimelineEvent .aggregatedEvents(mxTimeline, matrix.RelationshipTypes.reaction) .toList(); - events.sort((eventA, eventB) => - eventA.originServerTs.compareTo(eventB.originServerTs)); + events.sort( + (eventA, eventB) => + eventA.originServerTs.compareTo(eventB.originServerTs), + ); for (var event in events) { var emoji = getEmoticonFromReactionEvent(event, mxTimeline); @@ -64,15 +71,20 @@ mixin MatrixTimelineEventReactions on MatrixTimelineEvent } Emoticon getEmoticonFromReactionEvent( - matrix.Event event, matrix.Timeline timeline) { + matrix.Event event, + matrix.Timeline timeline, + ) { var content = event.content["m.relates_to"] as Map; var key = content['key'] as String; if (key.startsWith("mxc://")) { - return MatrixEmoticon(Uri.parse(key), timeline.room.client, - shortcode: event.content.tryGet("shortcode") ?? "", - packUsage: EmoticonUsage.all, - usage: EmoticonUsage.all); + return MatrixEmoticon( + Uri.parse(key), + timeline.room.client, + shortcode: event.content.tryGet("shortcode") ?? "", + packUsage: EmoticonUsage.all, + usage: EmoticonUsage.all, + ); } return UnicodeEmoticon(key, shortcode: content['shortcode'] as String?); diff --git a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_pinned_messages.dart b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_pinned_messages.dart index 80f75a951..d9aabd9b1 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_pinned_messages.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_pinned_messages.dart @@ -9,18 +9,18 @@ class MatrixTimelineEventPinnedMessages extends MatrixTimelineEvent MatrixTimelineEventPinnedMessages(super.event, {required super.client}); String messageUserPinnedEvent(String user) => Intl.message( - "$user pinned a message!", - desc: - "Message body for when a user adds an event to the room's pinned messages", - args: [user], - name: "messageUserPinnedEvent"); + "$user pinned a message!", + desc: "Message body for when a user adds an event to the room's pinned messages", + args: [user], + name: "messageUserPinnedEvent", + ); String messageUserUnpinnedEvent(String user) => Intl.message( - "$user unpinned a message", - desc: - "Message body for when a user removes an event from the room's pinned messages", - args: [user], - name: "messageUserUnpinnedEvent"); + "$user unpinned a message", + desc: "Message body for when a user removes an event from the room's pinned messages", + args: [user], + name: "messageUserUnpinnedEvent", + ); bool isNewEventPinned() { if (event.prevContent?.containsKey('pinned') == true) { diff --git a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_power_levels.dart b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_power_levels.dart index aec7b9c9a..a68a0abdd 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_power_levels.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_power_levels.dart @@ -9,11 +9,12 @@ class MatrixTimelineEventPowerLevels extends MatrixTimelineEvent implements TimelineEventGeneric { MatrixTimelineEventPowerLevels(super.event, {required super.client}); - String messagePowerLevelsChanged(String user) => - Intl.message("$user changed the room power levels", - desc: "Message to display when a user changes the room power levels", - args: [user], - name: "messagePowerLevelsChanged"); + String messagePowerLevelsChanged(String user) => Intl.message( + "$user changed the room power levels", + desc: "Message to display when a user changes the room power levels", + args: [user], + name: "messagePowerLevelsChanged", + ); @override String getBody({Timeline? timeline}) { diff --git a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_sticker.dart b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_sticker.dart index d48d4f134..4eb2ef880 100644 --- a/commet/lib/client/matrix/timeline_events/matrix_timeline_event_sticker.dart +++ b/commet/lib/client/matrix/timeline_events/matrix_timeline_event_sticker.dart @@ -20,8 +20,12 @@ class MatrixTimelineEventSticker extends MatrixTimelineEvent var file = event.content['file'] as Map; uri = file['url']; } - stickerImage = MatrixMxcImage(Uri.parse(uri!), client.getMatrixClient(), - matrixEvent: event, doThumbnail: false); + stickerImage = MatrixMxcImage( + Uri.parse(uri!), + client.getMatrixClient(), + matrixEvent: event, + doThumbnail: false, + ); stickerName = event.body; } diff --git a/commet/lib/client/matrix/widget/privelidged_matrix_widget_runner.dart b/commet/lib/client/matrix/widget/privelidged_matrix_widget_runner.dart index 7cf1fe45e..62a621277 100644 --- a/commet/lib/client/matrix/widget/privelidged_matrix_widget_runner.dart +++ b/commet/lib/client/matrix/widget/privelidged_matrix_widget_runner.dart @@ -144,8 +144,8 @@ class PrivelidgedMatrixWidgetRunner implements MatrixWidgetApi { "sender": client.userID!, "state_key": state_key, "event_id": eventId, - } - ] + }, + ], }, }; @@ -205,8 +205,10 @@ class PrivelidgedMatrixWidgetRunner implements MatrixWidgetApi { .toList(); var readableEvents = events - .where((i) => - i.eventId.startsWith("\$") && canWidgetReceiveEventType(i.type)) + .where( + (i) => + i.eventId.startsWith("\$") && canWidgetReceiveEventType(i.type), + ) .toList(); if (readableStateEvents.isNotEmpty) { @@ -262,8 +264,9 @@ class PrivelidgedMatrixWidgetRunner implements MatrixWidgetApi { }, }; - if (grantedCapabilities - .contains(MatrixCapability.receiveEvent(event.type))) { + if (grantedCapabilities.contains( + MatrixCapability.receiveEvent(event.type), + )) { Function(Map)? callback = actionListeners[ToWidgetAction.sendEvent]; @@ -287,7 +290,8 @@ class PrivelidgedMatrixWidgetRunner implements MatrixWidgetApi { Stream get onReady => _onReady.stream; Future> handleReadRelations( - Map data) async { + Map data, + ) async { print("Handling read relations"); var eventId = data["event_id"]; @@ -301,25 +305,35 @@ class PrivelidgedMatrixWidgetRunner implements MatrixWidgetApi { if (room.encrypted) { var related = await client.getRelatingEventsWithRelType( - room.id, eventId, relType, - from: from, limit: limit); + room.id, + eventId, + relType, + from: from, + limit: limit, + ); nextBatch = related.nextBatch; - var decrypted = await Future.wait( - [for (var event in related.chunk) tryDecryptEvent(event)]); + var decrypted = await Future.wait([ + for (var event in related.chunk) tryDecryptEvent(event), + ]); if (eventType != null) decrypted.removeWhere((i) => i?.type != eventType); return { "chunk": decrypted.nonNulls.map((i) => i.toJson()).toList(), - if (nextBatch != null) "next_batch": nextBatch + if (nextBatch != null) "next_batch": nextBatch, }; } if (relType != null && eventType != null) { var relatedEvents = await client.getRelatingEventsWithRelTypeAndEventType( - room.id, eventId, relType, eventType, - from: from, limit: limit); + room.id, + eventId, + relType, + eventType, + from: from, + limit: limit, + ); chunk = relatedEvents.chunk; nextBatch = relatedEvents.nextBatch; @@ -329,14 +343,15 @@ class PrivelidgedMatrixWidgetRunner implements MatrixWidgetApi { return { "chunk": chunk.map((i) => i.toJson()).toList(), - if (nextBatch != null) "next_batch": nextBatch + if (nextBatch != null) "next_batch": nextBatch, }; } Future tryDecryptEvent(matrix.MatrixEvent event) async { try { - return await client.encryption! - .decryptRoomEvent(matrix.Event.fromMatrixEvent(event, room)); + return await client.encryption!.decryptRoomEvent( + matrix.Event.fromMatrixEvent(event, room), + ); } catch (e) { return null; } diff --git a/commet/lib/client/matrix_background/matrix_background_client.dart b/commet/lib/client/matrix_background/matrix_background_client.dart index a148e7e28..f9416506b 100644 --- a/commet/lib/client/matrix_background/matrix_background_client.dart +++ b/commet/lib/client/matrix_background/matrix_background_client.dart @@ -40,9 +40,7 @@ class MatrixBackgroundClient implements Client { late final List> componentsInternal; MatrixBackgroundClient({required this.databaseId}) { - componentsInternal = [ - MatrixBackgroundClientDirectMessagesComponent(this), - ]; + componentsInternal = [MatrixBackgroundClientDirectMessagesComponent(this)]; } @override @@ -82,18 +80,23 @@ class MatrixBackgroundClient implements Client { @override StoredStreamController - get connectionStatusChanged => - StoredStreamController.new(); + get connectionStatusChanged => + StoredStreamController.new(); @override - Future init(bool loadingFromCache, - {bool isBackgroundService = false}) async { + Future init( + bool loadingFromCache, { + bool isBackgroundService = false, + }) async { Log.i( - "Using shared database isolate: ${preferences.useSharedIsolateInBackgroundTasks.value}"); + "Using shared database isolate: ${preferences.useSharedIsolateInBackgroundTasks.value}", + ); - final db = await getMatrixDatabase(databaseId, - onDatabaseIsolate: preferences.useSharedIsolateInBackgroundTasks.value, - readOnly: true); + final db = await getMatrixDatabase( + databaseId, + onDatabaseIsolate: preferences.useSharedIsolateInBackgroundTasks.value, + readOnly: true, + ); if (db is MatrixSdkDriftDatabase) { database = db; @@ -116,11 +119,13 @@ class MatrixBackgroundClient implements Client { allRooms = await database.db.select(database.db.roomData).get(); - preloadRoomStates = - await database.db.select(database.db.preloadRoomState).get(); + preloadRoomStates = await database.db + .select(database.db.preloadRoomState) + .get(); - nonPreloadRoomStates = - await database.db.select(database.db.nonPreloadRoomState).get(); + nonPreloadRoomStates = await database.db + .select(database.db.nonPreloadRoomState) + .get(); } @override @@ -170,10 +175,12 @@ class MatrixBackgroundClient implements Client { @override Room? getRoom(String identifier) { var data = allRooms.firstWhere((e) => e.roomId == identifier); - var preload = - preloadRoomStates.where((e) => e.roomId == identifier).toList(); - var nonPreload = - nonPreloadRoomStates.where((e) => e.roomId == identifier).toList(); + var preload = preloadRoomStates + .where((e) => e.roomId == identifier) + .toList(); + var nonPreload = nonPreloadRoomStates + .where((e) => e.roomId == identifier) + .toList(); return MatrixBackgroundRoom( this, roomId: identifier, diff --git a/commet/lib/client/matrix_background/matrix_background_room.dart b/commet/lib/client/matrix_background/matrix_background_room.dart index 8e12ae2f5..90c062295 100644 --- a/commet/lib/client/matrix_background/matrix_background_room.dart +++ b/commet/lib/client/matrix_background/matrix_background_room.dart @@ -50,14 +50,16 @@ class MatrixBackgroundRoom implements Room { } for (var postLoad in nonPreloadState) { - _stateEvents - .add(matrix.BasicEvent.fromJson(jsonDecode(postLoad.content))); + _stateEvents.add( + matrix.BasicEvent.fromJson(jsonDecode(postLoad.content)), + ); } } Future init() async { - var event = _stateEvents - .firstWhereOrNull((e) => e.type == matrix.EventTypes.RoomName); + var event = _stateEvents.firstWhereOrNull( + (e) => e.type == matrix.EventTypes.RoomName, + ); if (event != null) { displayName = event.content["name"] as String; @@ -78,17 +80,22 @@ class MatrixBackgroundRoom implements Room { if (avatarId != null) { avatar = await MatrixBackgroundMember.uriToCachedMxcImageProvider( - Uri.parse(avatarId!)); + Uri.parse(avatarId!), + ); } } - String? get avatarId => _stateEvents - .firstWhereOrNull((e) => e.type == matrix.EventTypes.RoomAvatar) - ?.content["url"] as String?; + String? get avatarId => + _stateEvents + .firstWhereOrNull((e) => e.type == matrix.EventTypes.RoomAvatar) + ?.content["url"] + as String?; @override Future?> addReaction( - TimelineEvent reactingTo, Emoticon reaction) { + TimelineEvent reactingTo, + Emoticon reaction, + ) { throw UnimplementedError(); } @@ -131,10 +138,11 @@ class MatrixBackgroundRoom implements Room { @override Future fetchMember(String id) async { var db = backgroundClient.database.db; - var data = await (db.select(db.roomMembers) - ..where( - (tbl) => tbl.roomId.equals(identifier) & tbl.userId.equals(id))) - .getSingleOrNull(); + var data = + await (db.select(db.roomMembers)..where( + (tbl) => tbl.roomId.equals(identifier) & tbl.userId.equals(id), + )) + .getSingleOrNull(); MatrixBackgroundMember result = MatrixBackgroundMember(id); if (data != null) { @@ -184,8 +192,11 @@ class MatrixBackgroundRoom implements Room { return null; } - Future attemptDecrypt(matrix.MatrixEvent result, - String cipherText, StoredInboundGroupSession session) async { + Future attemptDecrypt( + matrix.MatrixEvent result, + String cipherText, + StoredInboundGroupSession session, + ) async { var key = jsonDecode(session.content); var sessionKey = key["session_key"]; @@ -230,23 +241,26 @@ class MatrixBackgroundRoom implements Room { if (senderKey != null) { var database = backgroundClient.database; - var data = await (database.db.select(database.db.inboundGroupSession) - ..where((tbl) => - tbl.roomId.equals(roomId) & tbl.senderKey.equals(senderKey))) - .get(); + var data = + await (database.db.select(database.db.inboundGroupSession)..where( + (tbl) => + tbl.roomId.equals(roomId) & tbl.senderKey.equals(senderKey), + )) + .get(); Log.i("Found ${data.length} sessions with matching sender_key"); for (var entry in data) { Log.i("Got session via sender_key"); session = StoredInboundGroupSession( - roomId: entry.roomId, - sessionId: entry.sessionId, - pickle: entry.pickle, - content: entry.content, - indexes: entry.indexes, - allowedAtIndex: entry.allowedAtIndex, - senderKey: entry.senderKey, - senderClaimedKeys: entry.senderClaimedKey); + roomId: entry.roomId, + sessionId: entry.sessionId, + pickle: entry.pickle, + content: entry.content, + indexes: entry.indexes, + allowedAtIndex: entry.allowedAtIndex, + senderKey: entry.senderKey, + senderClaimedKeys: entry.senderClaimedKey, + ); var decrypted = await attemptDecrypt(result, ciphertext, session); if (decrypted != null) { @@ -254,8 +268,10 @@ class MatrixBackgroundRoom implements Room { } } } else { - session = await backgroundClient.database - .getInboundGroupSession(result.roomId!, sessionId as String); + session = await backgroundClient.database.getInboundGroupSession( + result.roomId!, + sessionId as String, + ); if (session != null) { var decrypted = await attemptDecrypt(result, ciphertext, session); @@ -270,8 +286,10 @@ class MatrixBackgroundRoom implements Room { @override Future?> getEvent(String eventId) async { - var result = - await backgroundClient.api.getOneRoomEvent(identifier, eventId); + var result = await backgroundClient.api.getOneRoomEvent( + identifier, + eventId, + ); Log.i("Received event: ${result}"); if (result.type == matrix.EventTypes.Encrypted) { @@ -363,7 +381,8 @@ class MatrixBackgroundRoom implements Room { @override Future> processAttachments( - List attachments) { + List attachments, + ) { throw UnimplementedError(); } @@ -371,7 +390,9 @@ class MatrixBackgroundRoom implements Room { @override Future removeReaction( - TimelineEvent reactingTo, Emoticon reaction) { + TimelineEvent reactingTo, + Emoticon reaction, + ) { throw UnimplementedError(); } @@ -381,11 +402,12 @@ class MatrixBackgroundRoom implements Room { } @override - Future?> sendMessage( - {String? message, - TimelineEvent? inReplyTo, - TimelineEvent? replaceEvent, - List? processedAttachments}) { + Future?> sendMessage({ + String? message, + TimelineEvent? inReplyTo, + TimelineEvent? replaceEvent, + List? processedAttachments, + }) { throw UnimplementedError(); } diff --git a/commet/lib/client/room.dart b/commet/lib/client/room.dart index 94613d8d2..7ece2d7c3 100644 --- a/commet/lib/client/room.dart +++ b/commet/lib/client/room.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:typed_data'; + import 'package:collection/collection.dart'; import 'package:commet/client/client.dart'; import 'package:commet/client/components/calendar_room/calendar_room_component.dart'; @@ -12,6 +13,7 @@ import 'package:commet/client/member.dart'; import 'package:commet/client/role.dart'; import 'package:commet/client/timeline_events/timeline_event.dart'; import 'package:flutter/material.dart'; + import 'attachment.dart'; import 'permissions.dart'; diff --git a/commet/lib/client/room_preview.dart b/commet/lib/client/room_preview.dart index 610ed2244..6a9bf3282 100644 --- a/commet/lib/client/room_preview.dart +++ b/commet/lib/client/room_preview.dart @@ -31,13 +31,15 @@ class GenericRoomPreview implements RoomPreview { RoomType? type; - GenericRoomPreview(this.roomId, - {this.avatar, - required this.displayName, - required this.type, - this.numMembers, - this.visibility, - this.topic}); + GenericRoomPreview( + this.roomId, { + this.avatar, + required this.displayName, + required this.type, + this.numMembers, + this.visibility, + this.topic, + }); @override Color get color => Colors.grey; diff --git a/commet/lib/client/space.dart b/commet/lib/client/space.dart index e6c1c3939..f01cce035 100644 --- a/commet/lib/client/space.dart +++ b/commet/lib/client/space.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:commet/client/client.dart'; import 'package:commet/client/components/space_component.dart'; import 'package:commet/client/permissions.dart'; @@ -35,7 +36,10 @@ abstract class Space { } void _addSubspaceRooms( - List rooms, Space space, List handledSpaces) { + List rooms, + Space space, + List handledSpaces, + ) { rooms.addAll(space.rooms); handledSpaces.add(space); for (var subspace in space.subspaces) { @@ -59,8 +63,10 @@ abstract class Space { List get children; - Future setChildrenOrder(List children, - {Function(double?)? onProgressChanged}); + Future setChildrenOrder( + List children, { + Function(double?)? onProgressChanged, + }); bool get isTopLevel; @@ -103,16 +109,17 @@ abstract class Space { int get notificationCount => roomsWithChildren .where((element) => element.pushRule == PushRule.notify) .fold( - 0, - (previousValue, element) => - previousValue + element.notificationCount); + 0, + (previousValue, element) => previousValue + element.notificationCount, + ); int get highlightedNotificationCount => roomsWithChildren .where((element) => element.pushRule != PushRule.dontNotify) .fold( - 0, - (previousValue, element) => - previousValue + element.highlightedNotificationCount); + 0, + (previousValue, element) => + previousValue + element.highlightedNotificationCount, + ); int get displayNotificationCount => pushRule == PushRule.notify ? notificationCount : 0; diff --git a/commet/lib/client/stale_info.dart b/commet/lib/client/stale_info.dart index a4f76d714..97d416908 100644 --- a/commet/lib/client/stale_info.dart +++ b/commet/lib/client/stale_info.dart @@ -5,8 +5,12 @@ class StalePeerInfo { String? displayName; String? identifier; ImageProvider? avatar; - StalePeerInfo( - {required this.index, this.displayName, this.identifier, this.avatar}); + StalePeerInfo({ + required this.index, + this.displayName, + this.identifier, + this.avatar, + }); } class StaleSpaceInfo { @@ -14,8 +18,12 @@ class StaleSpaceInfo { String? name; ImageProvider? avatar; ImageProvider? userAvatar; - StaleSpaceInfo( - {required this.index, this.name, this.avatar, this.userAvatar}); + StaleSpaceInfo({ + required this.index, + this.name, + this.avatar, + this.userAvatar, + }); } class StaleRoomInfo { diff --git a/commet/lib/client/tasks/client_connection_status_task.dart b/commet/lib/client/tasks/client_connection_status_task.dart index a9b94655d..de0c83c37 100644 --- a/commet/lib/client/tasks/client_connection_status_task.dart +++ b/commet/lib/client/tasks/client_connection_status_task.dart @@ -47,7 +47,9 @@ class ClientConnectionStatusTask extends BackgroundTaskWithOptionalProgress { } ClientConnectionStatusTask( - this.client, ClientConnectionStatusUpdate initialStatus) { + this.client, + ClientConnectionStatusUpdate initialStatus, + ) { sub = client.connectionStatusChanged.stream.listen(onStatusUpdate); onStatusUpdate(initialStatus); } diff --git a/commet/lib/client/timeline.dart b/commet/lib/client/timeline.dart index c9bbc3d84..a4b4d1f50 100644 --- a/commet/lib/client/timeline.dart +++ b/commet/lib/client/timeline.dart @@ -4,13 +4,7 @@ import 'package:commet/client/client.dart'; import 'package:commet/client/timeline_events/timeline_event.dart'; import 'package:flutter/material.dart'; -enum TimelineEventStatus { - error, - sending, - sent, - synced, - roomState, -} +enum TimelineEventStatus { error, sending, sent, synced, roomState } TimelineEventStatus eventStatusFromInt(int intValue) => TimelineEventStatus.values[intValue + 2]; @@ -18,8 +12,9 @@ TimelineEventStatus eventStatusFromInt(int intValue) => /// Takes two [EventStatus] values and returns the one with higher /// (better in terms of message sending) status. TimelineEventStatus latestEventStatus( - TimelineEventStatus status1, TimelineEventStatus status2) => - status1.intValue > status2.intValue ? status1 : status2; + TimelineEventStatus status1, + TimelineEventStatus status2, +) => status1.intValue > status2.intValue ? status1 : status2; extension EventStatusExtension on TimelineEventStatus { /// Returns int value of the event status. @@ -44,17 +39,17 @@ extension EventStatusExtension on TimelineEventStatus { /// Returns `true` if the status is sent or later: /// [EventStatus.sent], [EventStatus.synced] or [EventStatus.roomState]. bool get isSent => [ - TimelineEventStatus.sent, - TimelineEventStatus.synced, - TimelineEventStatus.roomState - ].contains(this); + TimelineEventStatus.sent, + TimelineEventStatus.synced, + TimelineEventStatus.roomState, + ].contains(this); /// Returns `true` if the status is `synced` or `roomState`: /// [EventStatus.synced] or [EventStatus.roomState]. bool get isSynced => [ - TimelineEventStatus.synced, - TimelineEventStatus.roomState, - ].contains(this); + TimelineEventStatus.synced, + TimelineEventStatus.roomState, + ].contains(this); } enum EventRelationshipType { reply } @@ -62,8 +57,9 @@ enum EventRelationshipType { reply } abstract class Timeline { late List events = List.empty(growable: true); final Map _eventsDict = {}; - late StreamController onEventAdded = - StreamController.broadcast(sync: true); + late StreamController onEventAdded = StreamController.broadcast( + sync: true, + ); late StreamController onChange = StreamController.broadcast(sync: false); late StreamController onRemove = StreamController.broadcast(sync: true); late Client client; diff --git a/commet/lib/client/timeline_events/timeline_event_feature_per_message_profile.dart b/commet/lib/client/timeline_events/timeline_event_feature_per_message_profile.dart index cd60026d0..88be229f9 100644 --- a/commet/lib/client/timeline_events/timeline_event_feature_per_message_profile.dart +++ b/commet/lib/client/timeline_events/timeline_event_feature_per_message_profile.dart @@ -10,14 +10,15 @@ class PerMessageProfile { final List pronouns; final Color color; - const PerMessageProfile( - {required this.id, - required this.color, - this.displayName, - this.avatar, - this.clearAvatar = false, - this.hasFallback = false, - this.pronouns = const []}); + const PerMessageProfile({ + required this.id, + required this.color, + this.displayName, + this.avatar, + this.clearAvatar = false, + this.hasFallback = false, + this.pronouns = const [], + }); bool get hasDisplayName => displayName != null; } diff --git a/commet/lib/config/build_config.dart b/commet/lib/config/build_config.dart index 8bb46f545..a55c80b79 100644 --- a/commet/lib/config/build_config.dart +++ b/commet/lib/config/build_config.dart @@ -3,37 +3,51 @@ import 'package:flutter/foundation.dart'; class BuildConfig { - static const String _buildMode = - String.fromEnvironment('BUILD_MODE', defaultValue: _Constants.release); - - static const String PLATFORM = - String.fromEnvironment('PLATFORM', defaultValue: _Constants._desktop); - - static const String GIT_HASH = - String.fromEnvironment('GIT_HASH', defaultValue: "unknown"); - - static const String VERSION_TAG = - String.fromEnvironment('VERSION_TAG', defaultValue: "development"); + static const String _buildMode = String.fromEnvironment( + 'BUILD_MODE', + defaultValue: _Constants.release, + ); + + static const String PLATFORM = String.fromEnvironment( + 'PLATFORM', + defaultValue: _Constants._desktop, + ); + + static const String GIT_HASH = String.fromEnvironment( + 'GIT_HASH', + defaultValue: "unknown", + ); + + static const String VERSION_TAG = String.fromEnvironment( + 'VERSION_TAG', + defaultValue: "development", + ); // Details about build, like "flatpak", "fdroid" - static const String BUILD_DETAIL = - String.fromEnvironment('BUILD_DETAIL', defaultValue: "default"); + static const String BUILD_DETAIL = String.fromEnvironment( + 'BUILD_DETAIL', + defaultValue: "default", + ); - static const bool ENABLE_GOOGLE_SERVICES = - bool.fromEnvironment("ENABLE_GOOGLE_SERVICES", defaultValue: false); + static const bool ENABLE_GOOGLE_SERVICES = bool.fromEnvironment( + "ENABLE_GOOGLE_SERVICES", + defaultValue: false, + ); static const bool DEBUG = _buildMode == _Constants._debug; static const bool RELEASE = _buildMode == _Constants.release; - static const bool DESKTOP = PLATFORM == _Constants._desktop || + static const bool DESKTOP = + PLATFORM == _Constants._desktop || PLATFORM == _Constants._linux || PLATFORM == _Constants._windows || PLATFORM == _Constants._macos; static const bool WEB = PLATFORM == _Constants._web || kIsWeb; - static const bool MOBILE = PLATFORM == _Constants._mobile || + static const bool MOBILE = + PLATFORM == _Constants._mobile || PLATFORM == _Constants._android || PLATFORM == _Constants._ios; @@ -57,8 +71,10 @@ class BuildConfig { static Uri donationRewardsApiHost = Uri.https("stripe-rewards.commet.chat"); - static const String _BUILD_DATE = - String.fromEnvironment('BUILD_DATE', defaultValue: "0"); + static const String _BUILD_DATE = String.fromEnvironment( + 'BUILD_DATE', + defaultValue: "0", + ); static DateTime get BUILD_DATE => DateTime.fromMillisecondsSinceEpoch(int.parse(_BUILD_DATE)); @@ -66,19 +82,19 @@ class BuildConfig { // IM SO SORRY static const String appName = MOBILE ? (ANDROID - ? "$app for Android" - : (IOS ? "$app for iOS" : "$app for Mobile")) + ? "$app for Android" + : (IOS ? "$app for iOS" : "$app for Mobile")) : (DESKTOP - ? (WINDOWS - ? "$app for Windows" - : LINUX + ? (WINDOWS + ? "$app for Windows" + : LINUX ? "$app for Linux" : MAC - ? "$app for MacOS" - : "$app for Desktop") - : WEB - ? "$app for Web" - : app); + ? "$app for MacOS" + : "$app for Desktop") + : WEB + ? "$app for Web" + : app); } class _Constants { diff --git a/commet/lib/config/layout_config.dart b/commet/lib/config/layout_config.dart index d674ed46d..44d17ebe6 100644 --- a/commet/lib/config/layout_config.dart +++ b/commet/lib/config/layout_config.dart @@ -48,10 +48,7 @@ class Layout { } } -enum LayoutType { - mobile, - desktop; -} +enum LayoutType { mobile, desktop } extension LayoutQueryData on MediaQueryData { LayoutType get layout { diff --git a/commet/lib/config/platform_utils.dart b/commet/lib/config/platform_utils.dart index c5cebc689..5ee7a548b 100644 --- a/commet/lib/config/platform_utils.dart +++ b/commet/lib/config/platform_utils.dart @@ -66,12 +66,6 @@ class PlatformUtils { } } -enum DisplayServer { - Wayland, - X11, -} +enum DisplayServer { Wayland, X11 } -enum DesktopEnvironment { - KDEPlasma, - GNOME, -} +enum DesktopEnvironment { KDEPlasma, GNOME } diff --git a/commet/lib/config/preferences.dart b/commet/lib/config/preferences.dart index 37c262bf8..d19c62e00 100644 --- a/commet/lib/config/preferences.dart +++ b/commet/lib/config/preferences.dart @@ -57,8 +57,10 @@ class Preferences { void addRegisteredMatrixClient(String name) { List names = List.empty(growable: true); if (_preferences!.containsKey(registeredMatrixClients)) { - names = List.from(_preferences!.getStringList(registeredMatrixClients)!, - growable: true); + names = List.from( + _preferences!.getStringList(registeredMatrixClients)!, + growable: true, + ); } names.add(name); @@ -144,7 +146,8 @@ class Preferences { : _preferences!.getString(_pushGateway) ?? "push.commet.chat"; Future setExperimentEnabled(String experiment, bool value) async { - var experiments = _preferences?.getStringList(_optedInExperiments) ?? + var experiments = + _preferences?.getStringList(_optedInExperiments) ?? List.empty(growable: true); if (value) { @@ -175,8 +178,10 @@ class Preferences { } Future setCalendarSources(String roomId, Map sources) { - return _preferences! - .setString(_syncedCalendarUrls + ".${roomId}", jsonEncode(sources)); + return _preferences!.setString( + _syncedCalendarUrls + ".${roomId}", + jsonEncode(sources), + ); } (String, DateTime)? get runningDonationCheckFlow { @@ -196,13 +201,13 @@ class Preferences { } Future setRunningDonationCheckFlow( - String value, DateTime timestamp) async { + String value, + DateTime timestamp, + ) async { _preferences!.setString( - _runningDonationCheckFlow, - jsonEncode({ - "user": value, - "time": timestamp.millisecondsSinceEpoch, - })); + _runningDonationCheckFlow, + jsonEncode({"user": value, "time": timestamp.millisecondsSinceEpoch}), + ); onSettingChangedController.add(null); } @@ -252,25 +257,38 @@ class Preferences { "allowed_widget:${clientId}:${widgetNamespace}"; Future setWidgetAllowed( - String clientId, String widgetNamespace, bool allowed) async { + String clientId, + String widgetNamespace, + bool allowed, + ) async { await _preferences?.setBool( - _widgetAllowedKey(clientId, widgetNamespace), allowed); + _widgetAllowedKey(clientId, widgetNamespace), + allowed, + ); } bool getWidgetAllowed(String clientId, String widgetNamespace) { - return _preferences - ?.getBool(_widgetAllowedKey(clientId, widgetNamespace)) ?? + return _preferences?.getBool( + _widgetAllowedKey(clientId, widgetNamespace), + ) ?? false; } - Future allowWidgetCapabilityPermissions(String clientId, - String widgetNamespace, List capabilities) async { - var currentAccepted = _preferences?.getStringList( - _acceptedCapabilitiesKey(clientId, widgetNamespace)) ?? + Future allowWidgetCapabilityPermissions( + String clientId, + String widgetNamespace, + List capabilities, + ) async { + var currentAccepted = + _preferences?.getStringList( + _acceptedCapabilitiesKey(clientId, widgetNamespace), + ) ?? []; - var currentRejected = _preferences?.getStringList( - _rejectedCapabilitiesKey(clientId, widgetNamespace)) ?? + var currentRejected = + _preferences?.getStringList( + _rejectedCapabilitiesKey(clientId, widgetNamespace), + ) ?? []; currentAccepted = List.from(currentAccepted, growable: true); @@ -286,19 +304,30 @@ class Preferences { } _preferences?.setStringList( - _acceptedCapabilitiesKey(clientId, widgetNamespace), currentAccepted); + _acceptedCapabilitiesKey(clientId, widgetNamespace), + currentAccepted, + ); _preferences?.setStringList( - _rejectedCapabilitiesKey(clientId, widgetNamespace), currentRejected); + _rejectedCapabilitiesKey(clientId, widgetNamespace), + currentRejected, + ); } - Future rejectWidgetCapabilityPermissions(String clientId, - String widgetNamespace, List capabilities) async { - var currentAccepted = _preferences?.getStringList( - _acceptedCapabilitiesKey(clientId, widgetNamespace)) ?? + Future rejectWidgetCapabilityPermissions( + String clientId, + String widgetNamespace, + List capabilities, + ) async { + var currentAccepted = + _preferences?.getStringList( + _acceptedCapabilitiesKey(clientId, widgetNamespace), + ) ?? []; - var currentRejected = _preferences?.getStringList( - _rejectedCapabilitiesKey(clientId, widgetNamespace)) ?? + var currentRejected = + _preferences?.getStringList( + _rejectedCapabilitiesKey(clientId, widgetNamespace), + ) ?? []; currentAccepted = List.from(currentAccepted, growable: true); @@ -314,32 +343,46 @@ class Preferences { } _preferences?.setStringList( - _acceptedCapabilitiesKey(clientId, widgetNamespace), currentAccepted); + _acceptedCapabilitiesKey(clientId, widgetNamespace), + currentAccepted, + ); _preferences?.setStringList( - _rejectedCapabilitiesKey(clientId, widgetNamespace), currentRejected); + _rejectedCapabilitiesKey(clientId, widgetNamespace), + currentRejected, + ); } Future> getAcceptedWidgetCapabilities( - String clientId, String widgetNamespace) async { + String clientId, + String widgetNamespace, + ) async { return _preferences?.getStringList( - _acceptedCapabilitiesKey(clientId, widgetNamespace)) ?? + _acceptedCapabilitiesKey(clientId, widgetNamespace), + ) ?? []; } Future> getRejectedWidgetCapabilities( - String clientId, String widgetNamespace) async { + String clientId, + String widgetNamespace, + ) async { return _preferences?.getStringList( - _rejectedCapabilitiesKey(clientId, widgetNamespace)) ?? + _rejectedCapabilitiesKey(clientId, widgetNamespace), + ) ?? []; } Future clearWidgetSettings( - String clientId, String widgetNamespace) async { - await _preferences - ?.remove(_acceptedCapabilitiesKey(clientId, widgetNamespace)); + String clientId, + String widgetNamespace, + ) async { + await _preferences?.remove( + _acceptedCapabilitiesKey(clientId, widgetNamespace), + ); - await _preferences - ?.remove(_rejectedCapabilitiesKey(clientId, widgetNamespace)); + await _preferences?.remove( + _rejectedCapabilitiesKey(clientId, widgetNamespace), + ); await _preferences?.remove(_widgetAllowedKey(clientId, widgetNamespace)); } @@ -362,219 +405,348 @@ class Preferences { await _preferences?.setString(_roomsListCache, jsonEncode(rooms)); } - BoolPreference shouldFollowSystemTheme = - BoolPreference("should_follow_system_theme", defaultValue: false); - - BoolPreference shouldFollowSystemColors = - BoolPreference("should_follow_system_colors", defaultValue: false); - - BoolPreference minimizeOnClose = - BoolPreference("minimize_on_close", defaultValue: false); - - BoolPreference developerMode = - BoolPreference("developer_mode", defaultValue: false); - - BoolPreference widgetDeveloperMode = - BoolPreference("widget_developer_mode", defaultValue: false); - - BoolPreference showStateEvents = - BoolPreference("show_state_events", defaultValue: true); - - BoolPreference collapseStateEvents = - BoolPreference("collapse_state_events", defaultValue: true); - - BoolPreference debugTranslations = - BoolPreference("enable_translations_debug", defaultValue: false); - - BoolPreference tenorGifSearchEnabled = - BoolPreference("enable_tenor_gif_search", defaultValue: false); + BoolPreference shouldFollowSystemTheme = BoolPreference( + "should_follow_system_theme", + defaultValue: false, + ); + + BoolPreference shouldFollowSystemColors = BoolPreference( + "should_follow_system_colors", + defaultValue: false, + ); + + BoolPreference minimizeOnClose = BoolPreference( + "minimize_on_close", + defaultValue: false, + ); + + BoolPreference developerMode = BoolPreference( + "developer_mode", + defaultValue: false, + ); + + BoolPreference widgetDeveloperMode = BoolPreference( + "widget_developer_mode", + defaultValue: false, + ); + + BoolPreference showStateEvents = BoolPreference( + "show_state_events", + defaultValue: true, + ); + + BoolPreference collapseStateEvents = BoolPreference( + "collapse_state_events", + defaultValue: true, + ); + + BoolPreference debugTranslations = BoolPreference( + "enable_translations_debug", + defaultValue: false, + ); + + BoolPreference tenorGifSearchEnabled = BoolPreference( + "enable_tenor_gif_search", + defaultValue: false, + ); //Workaround for: https://github.com/commetchat/commet/issues/202 - BoolPreference stickerCompatibilityMode = - BoolPreference("sticker_compatibility_mode", defaultValue: true); - - BoolPreference useFallbackTurnServer = - BoolPreference("use_fallback_turn_server", defaultValue: false); - - BoolPreference useVoipOverlay = - BoolPreference("use_voip_overlay", defaultValue: true); - - BoolPreference urlPreviewInE2EEChat = - BoolPreference("use_url_preview_in_e2ee_chat", defaultValue: false); - - BoolPreference messageEffectsEnabled = - BoolPreference("message_effects_enabled", defaultValue: true); - - BoolPreference showRoomAvatars = - BoolPreference("show_room_avatars", defaultValue: true); - - BoolPreference showRoomsInSidebar = - BoolPreference("show_rooms_in_sidebar", defaultValue: false); - - BoolPreference usePlaceholderRoomAvatars = - BoolPreference("use_placeholder_room_avatars", defaultValue: false); - - BoolPreference previewMediaInPublicRooms = - BoolPreference("preview_media_in_public_rooms", defaultValue: false); - - BoolPreference previewMediaInPrivateRooms = - BoolPreference("preview_media_in_private_rooms", defaultValue: true); - - BoolPreference showMediaInNotifications = - BoolPreference("show_media_in_notifications", defaultValue: true); - - BoolPreference formatNotificationBody = - BoolPreference("format_notification_body", defaultValue: true); - - BoolPreference previewUrlInNotifications = - BoolPreference("preview_urls_in_notification", defaultValue: true); - - BoolPreference useLegacyNotificationHandler = - BoolPreference("use_legacy_notification_handler", defaultValue: false); - - BoolPreference openRoomsAtLastReadMessage = - BoolPreference("open_rooms_at_last_read_message", defaultValue: false); - - BoolPreference askBeforeDeletingMessageEnabled = - BoolPreference("ask_before_deleting_message_enabled", defaultValue: true); + BoolPreference stickerCompatibilityMode = BoolPreference( + "sticker_compatibility_mode", + defaultValue: true, + ); + + BoolPreference useFallbackTurnServer = BoolPreference( + "use_fallback_turn_server", + defaultValue: false, + ); + + BoolPreference useVoipOverlay = BoolPreference( + "use_voip_overlay", + defaultValue: true, + ); + + BoolPreference urlPreviewInE2EEChat = BoolPreference( + "use_url_preview_in_e2ee_chat", + defaultValue: false, + ); + + BoolPreference messageEffectsEnabled = BoolPreference( + "message_effects_enabled", + defaultValue: true, + ); + + BoolPreference showRoomAvatars = BoolPreference( + "show_room_avatars", + defaultValue: true, + ); + + BoolPreference showRoomsInSidebar = BoolPreference( + "show_rooms_in_sidebar", + defaultValue: false, + ); + + BoolPreference usePlaceholderRoomAvatars = BoolPreference( + "use_placeholder_room_avatars", + defaultValue: false, + ); + + BoolPreference previewMediaInPublicRooms = BoolPreference( + "preview_media_in_public_rooms", + defaultValue: false, + ); + + BoolPreference previewMediaInPrivateRooms = BoolPreference( + "preview_media_in_private_rooms", + defaultValue: true, + ); + + BoolPreference showMediaInNotifications = BoolPreference( + "show_media_in_notifications", + defaultValue: true, + ); + + BoolPreference formatNotificationBody = BoolPreference( + "format_notification_body", + defaultValue: true, + ); + + BoolPreference previewUrlInNotifications = BoolPreference( + "preview_urls_in_notification", + defaultValue: true, + ); + + BoolPreference useLegacyNotificationHandler = BoolPreference( + "use_legacy_notification_handler", + defaultValue: false, + ); + + BoolPreference openRoomsAtLastReadMessage = BoolPreference( + "open_rooms_at_last_read_message", + defaultValue: false, + ); + + BoolPreference askBeforeDeletingMessageEnabled = BoolPreference( + "ask_before_deleting_message_enabled", + defaultValue: true, + ); BoolPreference silenceNotifications = BoolPreference( - "silence_notifications_when_other_device_active", - defaultValue: true); - - BoolPreference showNotificationBadgesInTaskbar = - BoolPreference("show_notification_badges_in_taskbar", defaultValue: true); - - BoolPreference disableTextCursorManagement = - BoolPreference("disable_text_cursor_management", defaultValue: false); - - BoolPreference hideRoomSidePanel = - BoolPreference("hide_room_side_panel", defaultValue: false); - - BoolPreference showRoomPreviewsInSpaceSidebar = - BoolPreference("show_room_previews_in_space_sidebar", defaultValue: true); + "silence_notifications_when_other_device_active", + defaultValue: true, + ); + + BoolPreference showNotificationBadgesInTaskbar = BoolPreference( + "show_notification_badges_in_taskbar", + defaultValue: true, + ); + + BoolPreference disableTextCursorManagement = BoolPreference( + "disable_text_cursor_management", + defaultValue: false, + ); + + BoolPreference hideRoomSidePanel = BoolPreference( + "hide_room_side_panel", + defaultValue: false, + ); + + BoolPreference showRoomPreviewsInSpaceSidebar = BoolPreference( + "show_room_previews_in_space_sidebar", + defaultValue: true, + ); BoolPreference autoFocusMessageTextBox = BoolPreference( - "auto_focus_message_textbox", - defaultGetter: () => PlatformUtils.isAndroid ? false : true, - defaultValue: false); - - BoolPreference selectAutoCompleteSuggestion = - BoolPreference("select_auto_complete_suggestion", defaultValue: false); - - BoolPreference automaticallyOpenSpace = - BoolPreference("open_space_on_room_navigation", defaultValue: true); - - BoolPreference pauseAnimationsWhenNotFocused = - BoolPreference("pause_animations_When_not_focused", defaultValue: true); - - BoolPreference autoRotateImages = - BoolPreference("lightbox_rotate_images", defaultValue: false); - - BoolPreference autoRotateVideos = - BoolPreference("lightbox_rotate_videos", defaultValue: false); - - DoublePreference textScale = - DoublePreference("text_scale", defaultValue: 1.0); - - BoolPreference doSimulcast = - BoolPreference("livekit_use_simulcast", defaultValue: false); - - BoolPreference enableNotifications = - BoolPreference("notifications_enabled", defaultValue: true); + "auto_focus_message_textbox", + defaultGetter: () => PlatformUtils.isAndroid ? false : true, + defaultValue: false, + ); + + BoolPreference selectAutoCompleteSuggestion = BoolPreference( + "select_auto_complete_suggestion", + defaultValue: false, + ); + + BoolPreference automaticallyOpenSpace = BoolPreference( + "open_space_on_room_navigation", + defaultValue: true, + ); + + BoolPreference pauseAnimationsWhenNotFocused = BoolPreference( + "pause_animations_When_not_focused", + defaultValue: true, + ); + + BoolPreference autoRotateImages = BoolPreference( + "lightbox_rotate_images", + defaultValue: false, + ); + + BoolPreference autoRotateVideos = BoolPreference( + "lightbox_rotate_videos", + defaultValue: false, + ); + + DoublePreference textScale = DoublePreference( + "text_scale", + defaultValue: 1.0, + ); + + BoolPreference doSimulcast = BoolPreference( + "livekit_use_simulcast", + defaultValue: false, + ); + + BoolPreference enableNotifications = BoolPreference( + "notifications_enabled", + defaultValue: true, + ); BoolPreference suppressNotificationWhenRoomFocused = BoolPreference( - "suppress_notification_when_room_focused", - defaultValue: true); + "suppress_notification_when_room_focused", + defaultValue: true, + ); BoolPreference experimentEnableE2eeElementCall = BoolPreference( - "experiment_enabled_e2ee_element_call", - defaultValue: false); + "experiment_enabled_e2ee_element_call", + defaultValue: false, + ); BoolPreference useSharedIsolateInBackgroundTasks = BoolPreference( - "use_shared_isolate_in_background_tasks", - defaultValue: false); - - BoolPreference showPerformanceOverlay = - BoolPreference("show_performance_overlay", defaultValue: false); - - DoublePreference notificationsVolume = - DoublePreference("notifications_volume", defaultValue: 90.0); - - DoublePreference streamBitrate = - DoublePreference("screenshare_bitrate_mbps", defaultValue: 8); - - DoublePreference streamAudioBitrate = - DoublePreference("stream_audio_kbps", defaultValue: 96); - - DoublePreference streamFramerate = - DoublePreference("screenshare_fps", defaultValue: 60); - - StringPreference streamCodec = - StringPreference("livekit_screenshare_codec", defaultValue: "av1"); + "use_shared_isolate_in_background_tasks", + defaultValue: false, + ); + + BoolPreference showPerformanceOverlay = BoolPreference( + "show_performance_overlay", + defaultValue: false, + ); + + DoublePreference notificationsVolume = DoublePreference( + "notifications_volume", + defaultValue: 90.0, + ); + + DoublePreference streamBitrate = DoublePreference( + "screenshare_bitrate_mbps", + defaultValue: 8, + ); + + DoublePreference streamAudioBitrate = DoublePreference( + "stream_audio_kbps", + defaultValue: 96, + ); + + DoublePreference streamFramerate = DoublePreference( + "screenshare_fps", + defaultValue: 60, + ); + + StringPreference streamCodec = StringPreference( + "livekit_screenshare_codec", + defaultValue: "av1", + ); StringPreference streamResolution = StringPreference( - "livekit_screenshare_resolution", - defaultValue: "1920x1080"); + "livekit_screenshare_resolution", + defaultValue: "1920x1080", + ); DoublePreference appScale = DoublePreference("app_scale", defaultValue: 1.0); - DoublePreference emojiPickerHeight = - DoublePreference("emoji_picker_height", defaultValue: 300); + DoublePreference emojiPickerHeight = DoublePreference( + "emoji_picker_height", + defaultValue: 300, + ); DoublePreference customOnscreenKeyboardViewOffset = DoublePreference( - "custom_onscreen_keyboard_view_offset", - defaultValue: 0.0); + "custom_onscreen_keyboard_view_offset", + defaultValue: 0.0, + ); - StringPreference proxyUrl = - StringPreference("proxy_url", defaultValue: "proxy.commet.chat"); + StringPreference proxyUrl = StringPreference( + "proxy_url", + defaultValue: "proxy.commet.chat", + ); - StringPreference fallbackTurnServer = StringPreference("fallback_turn_server", - defaultValue: "stun:turn.matrix.org"); + StringPreference fallbackTurnServer = StringPreference( + "fallback_turn_server", + defaultValue: "stun:turn.matrix.org", + ); StringPreference theme = StringPreference("app_theme", defaultValue: "dark"); - NullableStringPreference lastOpenedVersion = - NullableStringPreference("last_run_version", defaultValue: null); - - NullableBoolPreference unifiedPushEnabled = - NullableBoolPreference("unified_push_enabled", defaultValue: null); - - NullableBoolPreference checkForUpdates = - NullableBoolPreference("check_for_updates", defaultValue: null); - - NullableStringPreference layoutOverride = - NullableStringPreference("layout_override", defaultValue: null); - - NullableStringPreference voipDefaultAudioInput = - NullableStringPreference("voip_default_audio_input", defaultValue: null); - - NullableStringPreference voipDefaultAudioOutput = - NullableStringPreference("voip_default_audio_output", defaultValue: null); - - NullableStringPreference voipDefaultVideoInput = - NullableStringPreference("voip_default_video_input", defaultValue: null); - - NullableStringPreference filterClient = - NullableStringPreference("filter_client_id", defaultValue: null); - - NullableStringPreference fcmKey = - NullableStringPreference("fcm_key", defaultValue: null); - - NullableStringPreference unifiedPushEndpoint = - NullableStringPreference("unified_push_endpoint", defaultValue: null); - - NullableStringPreference lastDownloadLocation = - NullableStringPreference("last_download_location", defaultValue: null); - - StringListPreference allowedRemoteVideoHosts = - StringListPreference("allowed_remote_video_hosts", defaultValue: []); - - StringListPreference expandedSpaceGroups = - StringListPreference("expanded_space_groups", defaultValue: []); - - DoublePreference playerVolume = - DoublePreference("player_volume", defaultValue: 100); - BoolPreference isPlayerMuted = - BoolPreference("is_player_muted", defaultValue: false); + NullableStringPreference lastOpenedVersion = NullableStringPreference( + "last_run_version", + defaultValue: null, + ); + + NullableBoolPreference unifiedPushEnabled = NullableBoolPreference( + "unified_push_enabled", + defaultValue: null, + ); + + NullableBoolPreference checkForUpdates = NullableBoolPreference( + "check_for_updates", + defaultValue: null, + ); + + NullableStringPreference layoutOverride = NullableStringPreference( + "layout_override", + defaultValue: null, + ); + + NullableStringPreference voipDefaultAudioInput = NullableStringPreference( + "voip_default_audio_input", + defaultValue: null, + ); + + NullableStringPreference voipDefaultAudioOutput = NullableStringPreference( + "voip_default_audio_output", + defaultValue: null, + ); + + NullableStringPreference voipDefaultVideoInput = NullableStringPreference( + "voip_default_video_input", + defaultValue: null, + ); + + NullableStringPreference filterClient = NullableStringPreference( + "filter_client_id", + defaultValue: null, + ); + + NullableStringPreference fcmKey = NullableStringPreference( + "fcm_key", + defaultValue: null, + ); + + NullableStringPreference unifiedPushEndpoint = NullableStringPreference( + "unified_push_endpoint", + defaultValue: null, + ); + + NullableStringPreference lastDownloadLocation = NullableStringPreference( + "last_download_location", + defaultValue: null, + ); + + StringListPreference allowedRemoteVideoHosts = StringListPreference( + "allowed_remote_video_hosts", + defaultValue: [], + ); + + StringListPreference expandedSpaceGroups = StringListPreference( + "expanded_space_groups", + defaultValue: [], + ); + + DoublePreference playerVolume = DoublePreference( + "player_volume", + defaultValue: 100, + ); + BoolPreference isPlayerMuted = BoolPreference( + "is_player_muted", + defaultValue: false, + ); } diff --git a/commet/lib/config/preferences/bool_preference.dart b/commet/lib/config/preferences/bool_preference.dart index 659005185..af7ee8403 100644 --- a/commet/lib/config/preferences/bool_preference.dart +++ b/commet/lib/config/preferences/bool_preference.dart @@ -1,27 +1,29 @@ import 'package:commet/config/preferences/preference.dart'; class BoolPreference extends Preference { - BoolPreference(super.key, - {required super.defaultValue, bool Function()? defaultGetter}) - : super( - defaultGetter: defaultGetter, - getter: () => Preference.preferences?.getBool(key), - setter: (v) async { - await Preference.preferences?.setBool(key, v); - }, - ); + BoolPreference( + super.key, { + required super.defaultValue, + bool Function()? defaultGetter, + }) : super( + defaultGetter: defaultGetter, + getter: () => Preference.preferences?.getBool(key), + setter: (v) async { + await Preference.preferences?.setBool(key, v); + }, + ); } class NullableBoolPreference extends Preference { NullableBoolPreference(super.key, {required super.defaultValue}) - : super( - getter: () => Preference.preferences?.getBool(key), - setter: (v) async { - if (v == null) { - await Preference.preferences?.remove(key); - } else { - await Preference.preferences?.setBool(key, v); - } - }, - ); + : super( + getter: () => Preference.preferences?.getBool(key), + setter: (v) async { + if (v == null) { + await Preference.preferences?.remove(key); + } else { + await Preference.preferences?.setBool(key, v); + } + }, + ); } diff --git a/commet/lib/config/preferences/double_preference.dart b/commet/lib/config/preferences/double_preference.dart index e858657cd..c5c61e417 100644 --- a/commet/lib/config/preferences/double_preference.dart +++ b/commet/lib/config/preferences/double_preference.dart @@ -2,10 +2,10 @@ import 'package:commet/config/preferences/preference.dart'; class DoublePreference extends Preference { DoublePreference(super.key, {required super.defaultValue}) - : super( - getter: () => Preference.preferences?.getDouble(key), - setter: (v) async { - await Preference.preferences?.setDouble(key, v); - }, - ); + : super( + getter: () => Preference.preferences?.getDouble(key), + setter: (v) async { + await Preference.preferences?.setDouble(key, v); + }, + ); } diff --git a/commet/lib/config/preferences/preference.dart b/commet/lib/config/preferences/preference.dart index ac481e836..9e9a6d8ab 100644 --- a/commet/lib/config/preferences/preference.dart +++ b/commet/lib/config/preferences/preference.dart @@ -39,12 +39,14 @@ class Preference { @override bool operator ==(Object other) { throw Exception( - "Do not check for equality on a preference, check the preferences value"); + "Do not check for equality on a preference, check the preferences value", + ); } @override String toString() { throw Exception( - "Do not convert a preference to string, use the preferences value"); + "Do not convert a preference to string, use the preferences value", + ); } } diff --git a/commet/lib/config/preferences/string_list_preference.dart b/commet/lib/config/preferences/string_list_preference.dart index 755293f51..6324acc89 100644 --- a/commet/lib/config/preferences/string_list_preference.dart +++ b/commet/lib/config/preferences/string_list_preference.dart @@ -2,12 +2,13 @@ import 'package:commet/config/preferences/preference.dart'; class StringListPreference extends Preference> { StringListPreference(super.key, {required super.defaultValue}) - : super( - getter: () => - Preference.preferences?.getStringList(key) ?? List.empty(), - setter: (v) async { - await Preference.preferences?.setStringList(key, v); - }); + : super( + getter: () => + Preference.preferences?.getStringList(key) ?? List.empty(), + setter: (v) async { + await Preference.preferences?.setStringList(key, v); + }, + ); void add(String value) { var values = Preference.preferences?.getStringList(key); diff --git a/commet/lib/config/preferences/string_preference.dart b/commet/lib/config/preferences/string_preference.dart index d0784486a..46d494d1d 100644 --- a/commet/lib/config/preferences/string_preference.dart +++ b/commet/lib/config/preferences/string_preference.dart @@ -2,24 +2,24 @@ import 'package:commet/config/preferences/preference.dart'; class StringPreference extends Preference { StringPreference(super.key, {required super.defaultValue}) - : super( - getter: () => Preference.preferences?.getString(key), - setter: (v) async { - await Preference.preferences?.setString(key, v); - }, - ); + : super( + getter: () => Preference.preferences?.getString(key), + setter: (v) async { + await Preference.preferences?.setString(key, v); + }, + ); } class NullableStringPreference extends Preference { NullableStringPreference(super.key, {required super.defaultValue}) - : super( - getter: () => Preference.preferences?.getString(key), - setter: (v) async { - if (v == null) { - await Preference.preferences?.remove(key); - } else { - await Preference.preferences?.setString(key, v); - } - }, - ); + : super( + getter: () => Preference.preferences?.getString(key), + setter: (v) async { + if (v == null) { + await Preference.preferences?.remove(key); + } else { + await Preference.preferences?.setString(key, v); + } + }, + ); } diff --git a/commet/lib/config/subplatforms/steamdeck.dart b/commet/lib/config/subplatforms/steamdeck.dart index 063dfdad0..1f3dde37f 100644 --- a/commet/lib/config/subplatforms/steamdeck.dart +++ b/commet/lib/config/subplatforms/steamdeck.dart @@ -8,7 +8,8 @@ class SteamdeckSubplatform implements Subplatform { @override Future init() async { Log.i( - "Initializing steamdeck subplatform: ${_isSteamDeck} is gamemode: ${_isGameMode}"); + "Initializing steamdeck subplatform: ${_isSteamDeck} is gamemode: ${_isGameMode}", + ); if (_isGameMode) { await windowManager.setFullScreen(true); @@ -51,7 +52,8 @@ class SteamdeckSubplatform implements Subplatform { _isSteamDeck && steamProceses.any((i) => i.args.contains("-gamepadui")); Log.i( - "Is running on steamdeck: ${_isSteamDeck} is gamemode: ${_isGameMode}"); + "Is running on steamdeck: ${_isSteamDeck} is gamemode: ${_isGameMode}", + ); return _isSteamDeck; } diff --git a/commet/lib/config/theme_config.dart b/commet/lib/config/theme_config.dart index 3fd1c2e2e..da1fa0e7c 100644 --- a/commet/lib/config/theme_config.dart +++ b/commet/lib/config/theme_config.dart @@ -50,8 +50,10 @@ class ThemeConfig { final inputStream = InputFileStream(file.path); var dir = await getCustomThemesDir(); - var destination = - (path.join(dir.path, path.basenameWithoutExtension(file.path))); + var destination = (path.join( + dir.path, + path.basenameWithoutExtension(file.path), + )); final archive = ZipDecoder().decodeBuffer(inputStream); @@ -63,8 +65,9 @@ class ThemeConfig { for (var file in archive.files) { if (file.isFile) { - final outputStream = - OutputFileStream(path.join(destination, file.name)); + final outputStream = OutputFileStream( + path.join(destination, file.name), + ); file.writeContent(outputStream); outputStream.close(); diff --git a/commet/lib/debug/l10n_debug_lookup.dart b/commet/lib/debug/l10n_debug_lookup.dart index e33e91a1f..d11686c3a 100644 --- a/commet/lib/debug/l10n_debug_lookup.dart +++ b/commet/lib/debug/l10n_debug_lookup.dart @@ -12,9 +12,14 @@ class DebugLookup implements MessageLookup { void addLocale(String localeName, Function findLocale) {} @override - String? lookupMessage(String? messageText, String? locale, String? name, - List? args, String? meaning, - {MessageIfAbsent? ifAbsent}) { + String? lookupMessage( + String? messageText, + String? locale, + String? name, + List? args, + String? meaning, { + MessageIfAbsent? ifAbsent, + }) { return "$name"; } } diff --git a/commet/lib/debug/log.dart b/commet/lib/debug/log.dart index d626e0a39..82559a8d0 100644 --- a/commet/lib/debug/log.dart +++ b/commet/lib/debug/log.dart @@ -34,8 +34,9 @@ class LogEntryException extends LogEntry { } class Log { - static final NotifyingList log = - NotifyingList.empty(growable: true); + static final NotifyingList log = NotifyingList.empty( + growable: true, + ); static String prefix = ""; @@ -77,20 +78,30 @@ class Log { } } - String? info = - stackTrace != null ? getDetailFromStackTrace(stackTrace) : null; - add(LogEntryException( + String? info = stackTrace != null + ? getDetailFromStackTrace(stackTrace) + : null; + add( + LogEntryException( LogType.error, "${error.toString()}${info != null ? " ($info)" : ""}", error, - stackTrace)); + stackTrace, + ), + ); return null; }, handleUncaughtError: (self, parent, zone, error, stackTrace) { parent.print(zone, "HandleUncaughtError"); String? info = getDetailFromStackTrace(stackTrace); - add(LogEntryException( - LogType.error, "${error.toString()} ($info)", error, stackTrace)); + add( + LogEntryException( + LogType.error, + "${error.toString()} ($info)", + error, + stackTrace, + ), + ); }, ); @@ -144,8 +155,12 @@ class Log { static void onError(Object object, StackTrace trace, {String? content}) { String? info = getDetailFromStackTrace(trace); - var entry = LogEntryException(LogType.error, - content ?? "${object.toString()} ($info)", object, trace); + var entry = LogEntryException( + LogType.error, + content ?? "${object.toString()} ($info)", + object, + trace, + ); _print(entry); // ignore: avoid_print print(trace); @@ -153,19 +168,24 @@ class Log { static Function(FlutterErrorDetails)? _previousReporter; static Function(FlutterErrorDetails) getFlutterErrorReporter( - Function(FlutterErrorDetails)? current) { + Function(FlutterErrorDetails)? current, + ) { _previousReporter = current; return _onFlutterError; } static void _onFlutterError(FlutterErrorDetails details) { - String? info = - details.stack != null ? getDetailFromStackTrace(details.stack!) : null; - add(LogEntryException( + String? info = details.stack != null + ? getDetailFromStackTrace(details.stack!) + : null; + add( + LogEntryException( LogType.error, "${details.exception.toString()}${info != null ? " ($info)" : ""}", details.exception, - details.stack)); + details.stack, + ), + ); _previousReporter?.call(details); } diff --git a/commet/lib/diagnostic/mocks/matrix_client_component_mocks.dart b/commet/lib/diagnostic/mocks/matrix_client_component_mocks.dart index dd627b4b3..ed18e5ed4 100644 --- a/commet/lib/diagnostic/mocks/matrix_client_component_mocks.dart +++ b/commet/lib/diagnostic/mocks/matrix_client_component_mocks.dart @@ -22,27 +22,33 @@ class MockMatrixUrlPreviewComponent @override Future getPreview( - Timeline timeline, TimelineEvent? event) async { + Timeline timeline, + TimelineEvent? event, + ) async { await Future.delayed(const Duration(seconds: 1)); var image = [ "assets/images/app_icon/app_icon_filled.png", "assets/images/app_icon/app_icon_rounded.png", "assets/images/app_icon/app_icon_transparent_cropped.png", - "assets/images/app_icon/app_icon_transparent.png" + "assets/images/app_icon/app_icon_transparent.png", ][imageIndex % 4]; imageIndex += 1; - return UrlPreviewData(Uri.parse("https://example.com"), - siteName: "Example", - description: "Example description", - image: AssetImage(image)); + return UrlPreviewData( + Uri.parse("https://example.com"), + siteName: "Example", + description: "Example description", + image: AssetImage(image), + ); } @override bool shouldGetPreviewDataForTimelineEvent( - Timeline timeline, TimelineEvent event) { + Timeline timeline, + TimelineEvent event, + ) { return true; } diff --git a/commet/lib/generator/unicode_emoji_generator.dart b/commet/lib/generator/unicode_emoji_generator.dart index d3c80c070..2b3368b56 100644 --- a/commet/lib/generator/unicode_emoji_generator.dart +++ b/commet/lib/generator/unicode_emoji_generator.dart @@ -8,23 +8,25 @@ import '../utils/emoji/unicode_emoji_data.dart'; class UnicodeEmojiBuilder implements Builder { @override Map> get buildExtensions => const { - 'assets/emoji_data/data.json': [ - 'lib/utils/emoji/unicode_emoji_data_groups.g.dart' - ], - }; + 'assets/emoji_data/data.json': [ + 'lib/utils/emoji/unicode_emoji_data_groups.g.dart', + ], + }; @override Future build(BuildStep buildStep) async { final inputId = buildStep.inputId; final outputId = AssetId( - inputId.package, "lib/utils/emoji/unicode_emoji_data_groups.g.dart"); + inputId.package, + "lib/utils/emoji/unicode_emoji_data_groups.g.dart", + ); final data = (json.decode(await buildStep.readAsString(inputId)) as List); Map> packs = {}; - String shortcodesString = - await File("assets/emoji_data/shortcodes/en.json").readAsString(); + String shortcodesString = await File("assets/emoji_data/shortcodes/en.json") + .readAsString(); Map shortCodes = jsonDecode(shortcodesString); for (var e in data) { @@ -46,24 +48,28 @@ class UnicodeEmojiBuilder implements Builder { packs[group] = List.empty(growable: true); } - packs[group]! - .add(UnicodeEmojiData(unicode: unicode, shortcode: shortcode)); + packs[group]!.add( + UnicodeEmojiData(unicode: unicode, shortcode: shortcode), + ); } final outputBuffer = StringBuffer('// Generated, do not edit\n'); outputBuffer.write("// ignore_for_file: constant_identifier_names\n"); outputBuffer.write( - "import 'package:commet/utils/emoji/unicode_emoji_data.dart';\n"); + "import 'package:commet/utils/emoji/unicode_emoji_data.dart';\n", + ); outputBuffer.write("class UnicodeEmojiGroups {\n"); for (var key in packs.keys) { - outputBuffer - .write(" static const List GROUP_$key = [\n"); + outputBuffer.write( + " static const List GROUP_$key = [\n", + ); for (var emoji in packs[key]!) { outputBuffer.write( - " UnicodeEmojiData(unicode: \"${emoji.unicode}\", shortcode: \"${emoji.shortcode}\"),\n"); + " UnicodeEmojiData(unicode: \"${emoji.unicode}\", shortcode: \"${emoji.shortcode}\"),\n", + ); } outputBuffer.write(" ];\n"); diff --git a/commet/lib/main.dart b/commet/lib/main.dart index 786d05a1d..240d76e94 100644 --- a/commet/lib/main.dart +++ b/commet/lib/main.dart @@ -110,7 +110,8 @@ void bubble() async { var initialTheme = await preferences.resolveTheme(); - runApp(MaterialApp( + runApp( + MaterialApp( title: 'Commet', theme: initialTheme, navigatorKey: navigator, @@ -121,21 +122,23 @@ void bubble() async { GlobalCupertinoLocalizations.delegate, ], builder: (context, child) => Provider( - create: (context) => clientManager!, - child: child, - ), + create: (context) => clientManager!, + child: child, + ), home: BubblePage( clientManager!, initialClientId: initialClientId, initialRoom: initialRoomId, - ))); + ), + ), + ); } void main(List args) async { commandLineArgs = args; print(args); - if(args.contains("--unifiedpush-bg")) { + if (args.contains("--unifiedpush-bg")) { unifiedPushEntry(); return; } @@ -175,7 +178,8 @@ void appMain() async { FlutterError.onError = Log.getFlutterErrorReporter(FlutterError.onError); - isHeadless = PlatformUtils.isAndroid && + isHeadless = + PlatformUtils.isAndroid && AppLifecycleState.detached == WidgetsBinding.instance.lifecycleState; loading = initNecessary(); @@ -303,19 +307,22 @@ Future startGui() async { if (PlatformUtils.isAndroid) { var roomsListCache = Map>.new(); for (var client in clientManager!.clients) { - roomsListCache[client.identifier] = - client.rooms.map((i) => i.identifier).toList(); + roomsListCache[client.identifier] = client.rooms + .map((i) => i.identifier) + .toList(); } preferences.storeRoomsListCache(roomsListCache); } - runApp(App( - clientManager: clientManager!, - initialTheme: initialTheme, - initialClientId: initialClientId, - initialRoom: initialRoomId, - )); + runApp( + App( + clientManager: clientManager!, + initialTheme: initialTheme, + initialClientId: initialClientId, + initialRoom: initialRoomId, + ), + ); WindowManagement.init().then((_) { AppFocus.init(); @@ -326,23 +333,28 @@ Future startGui() async { void enableEdgeToEdge() async { var theme = await preferences.resolveTheme(); SystemChrome.setEnabledSystemUIMode( - SystemUiMode.edgeToEdge); // Enable Edge-to-Edge on Android 10+ - SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( + SystemUiMode.edgeToEdge, + ); // Enable Edge-to-Edge on Android 10+ + SystemChrome.setSystemUIOverlayStyle( + SystemUiOverlayStyle( systemNavigationBarColor: Colors.transparent, // Setting a transparent navigation bar color systemNavigationBarContrastEnforced: true, // Default systemNavigationBarIconBrightness: theme.brightness == Brightness.dark ? Brightness.light - : Brightness.dark)); + : Brightness.dark, + ), + ); } class App extends StatelessWidget { - const App( - {super.key, - required this.clientManager, - this.initialTheme, - this.initialRoom, - this.initialClientId}); + const App({ + super.key, + required this.clientManager, + this.initialTheme, + this.initialRoom, + this.initialClientId, + }); final ThemeData? initialTheme; final ClientManager clientManager; @@ -356,36 +368,39 @@ class App extends StatelessWidget { child: FocusNodeMonitor( child: TextScaleChanger( child: ThemeChanger( - shouldFollowSystemTheme: () => - preferences.shouldFollowSystemTheme.value, - getDarkTheme: () { - return preferences.resolveTheme( - overrideBrightness: Brightness.dark); - }, - getLightTheme: () { - return preferences.resolveTheme( - overrideBrightness: Brightness.light); - }, - initialTheme: initialTheme ?? ThemeDark.theme, - materialAppBuilder: (context, theme) { - return MaterialApp( - title: 'Commet', - theme: theme, - showPerformanceOverlay: - preferences.showPerformanceOverlay.value, - debugShowCheckedModeBanner: false, - navigatorKey: navigator, - builder: (context, child) => Provider( - create: (context) => clientManager, - child: child, - ), - home: AppView( - clientManager: clientManager, - initialClientId: initialClientId, - initialRoom: initialRoom, - ), - ); - }), + shouldFollowSystemTheme: () => + preferences.shouldFollowSystemTheme.value, + getDarkTheme: () { + return preferences.resolveTheme( + overrideBrightness: Brightness.dark, + ); + }, + getLightTheme: () { + return preferences.resolveTheme( + overrideBrightness: Brightness.light, + ); + }, + initialTheme: initialTheme ?? ThemeDark.theme, + materialAppBuilder: (context, theme) { + return MaterialApp( + title: 'Commet', + theme: theme, + showPerformanceOverlay: + preferences.showPerformanceOverlay.value, + debugShowCheckedModeBanner: false, + navigatorKey: navigator, + builder: (context, child) => Provider( + create: (context) => clientManager, + child: child, + ), + home: AppView( + clientManager: clientManager, + initialClientId: initialClientId, + initialRoom: initialRoom, + ), + ); + }, + ), ), ), ), @@ -394,11 +409,12 @@ class App extends StatelessWidget { } class AppView extends StatefulWidget { - const AppView( - {required this.clientManager, - super.key, - this.initialClientId, - this.initialRoom}); + const AppView({ + required this.clientManager, + super.key, + this.initialClientId, + this.initialRoom, + }); final ClientManager clientManager; final String? initialRoom; final String? initialClientId; @@ -415,17 +431,17 @@ class _AppViewState extends State { @override void initState() { super.initState(); - _onClientRemovedSubscription = - widget.clientManager.onClientRemoved.stream.listen((_) { - if (!widget.clientManager.isLoggedIn()) { - navigator.currentState?.popUntil((route) => route.isFirst); - setState(() {}); - } - }); - _onClientAddedSubscription = - widget.clientManager.onClientAdded.stream.listen((_) { - setState(() {}); - }); + _onClientRemovedSubscription = widget.clientManager.onClientRemoved.stream + .listen((_) { + if (!widget.clientManager.isLoggedIn()) { + navigator.currentState?.popUntil((route) => route.isFirst); + setState(() {}); + } + }); + _onClientAddedSubscription = widget.clientManager.onClientAdded.stream + .listen((_) { + setState(() {}); + }); isInitiallyLoggedIn = widget.clientManager.isLoggedIn(); } @@ -446,9 +462,11 @@ class _AppViewState extends State { initialRoom: widget.initialRoom, wasLoggedInAtStartup: isInitiallyLoggedIn, ) - : LoginPage(onSuccess: (_) { - setState(() {}); - }); + : LoginPage( + onSuccess: (_) { + setState(() {}); + }, + ); } } diff --git a/commet/lib/service/background_service.dart b/commet/lib/service/background_service.dart index 0663eb3e6..6e8520e1f 100644 --- a/commet/lib/service/background_service.dart +++ b/commet/lib/service/background_service.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:isolate'; + import 'package:commet/debug/log.dart'; import 'package:commet/main.dart'; import 'package:commet/service/background_service_notifications/background_service_task_notification.dart'; @@ -44,8 +45,10 @@ void handleTask(BackgroundServiceTask task, FlutterBackgroundService service) { if (task is BackgroundServiceTaskNotification) { Log.i("Handling task: ${task.eventId} ${task.hashCode}"); - FlutterBackgroundService().invoke("on_message_received", - {"event_id": task.eventId, "room_id": task.roomId}); + FlutterBackgroundService().invoke("on_message_received", { + "event_id": task.eventId, + "room_id": task.roomId, + }); } } @@ -60,21 +63,24 @@ Future initBackgroundService() async { await flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>() + AndroidFlutterLocalNotificationsPlugin + >() ?.createNotificationChannel(channel); try { _service!.configure( - iosConfiguration: IosConfiguration(), - androidConfiguration: AndroidConfiguration( - onStart: onServiceStarted, - isForegroundMode: true, - autoStart: false, - autoStartOnBoot: false, - initialNotificationTitle: "Updating Notifications", - initialNotificationContent: "Updating Notifications", - notificationChannelId: channel.id, - foregroundServiceNotificationId: id)); + iosConfiguration: IosConfiguration(), + androidConfiguration: AndroidConfiguration( + onStart: onServiceStarted, + isForegroundMode: true, + autoStart: false, + autoStartOnBoot: false, + initialNotificationTitle: "Updating Notifications", + initialNotificationContent: "Updating Notifications", + notificationChannelId: channel.id, + foregroundServiceNotificationId: id, + ), + ); await _service!.startService(); @@ -96,10 +102,12 @@ Future initBackgroundService() async { } catch (exception) { if (exception is MissingPluginException) { Log.w( - "Failed to start background service due to missing implementation. This wont show the banner, ${Isolate.current.debugName}"); + "Failed to start background service due to missing implementation. This wont show the banner, ${Isolate.current.debugName}", + ); } else { Log.w( - "Failed to start background service!, ${Isolate.current.debugName}"); + "Failed to start background service!, ${Isolate.current.debugName}", + ); } return false; } @@ -121,14 +129,17 @@ void onServiceInit(Map? data) async { "Updating Notifications", null, NotificationDetails( - android: AndroidNotificationDetails(channel.id, channel.name, - category: AndroidNotificationCategory.service, - icon: "ic_bg_service_small", - ongoing: true, - showProgress: true, - silent: true, - maxProgress: 100, - indeterminate: true), + android: AndroidNotificationDetails( + channel.id, + channel.name, + category: AndroidNotificationCategory.service, + icon: "ic_bg_service_small", + ongoing: true, + showProgress: true, + silent: true, + maxProgress: 100, + indeterminate: true, + ), ), ); } diff --git a/commet/lib/service/background_service_notifications/background_service_task_notification.dart b/commet/lib/service/background_service_notifications/background_service_task_notification.dart index 516a277d4..0dbc1cde4 100644 --- a/commet/lib/service/background_service_notifications/background_service_task_notification.dart +++ b/commet/lib/service/background_service_notifications/background_service_task_notification.dart @@ -93,8 +93,9 @@ class BackgroundNotificationsManager { var roomId = data["room_id"] as String; var eventId = data["event_id"] as String; - var client = - clientManager!.clients.firstWhere((element) => element.hasRoom(roomId)); + var client = clientManager!.clients.firstWhere( + (element) => element.hasRoom(roomId), + ); Log.i("Found client: ${client.identifier}"); var room = client.getRoom(roomId); @@ -105,9 +106,10 @@ class BackgroundNotificationsManager { Log.i("Got user: $user ($user)"); - bool isDirectMessage = client - .getComponent() - ?.isRoomDirectMessage(room) ?? + bool isDirectMessage = + client.getComponent()?.isRoomDirectMessage( + room, + ) ?? false; if (event is TimelineEventEncrypted) { @@ -119,16 +121,17 @@ class BackgroundNotificationsManager { event is TimelineEventSticker || event is TimelineEventEncrypted) { var content = MessageNotificationContent( - senderName: user.displayName, - senderId: user.identifier, - roomName: room.displayName, - content: event.plainTextBody, - eventId: eventId, - roomId: room.identifier, - clientId: client.identifier, - senderImage: user.avatar, - roomImage: room.avatar, - isDirectMessage: isDirectMessage); + senderName: user.displayName, + senderId: user.identifier, + roomName: room.displayName, + content: event.plainTextBody, + eventId: eventId, + roomId: room.identifier, + clientId: client.identifier, + senderImage: user.avatar, + roomImage: room.avatar, + isDirectMessage: isDirectMessage, + ); await NotificationManager.notify(content); } diff --git a/commet/lib/service/background_service_notifications/background_service_task_notification2.dart b/commet/lib/service/background_service_notifications/background_service_task_notification2.dart index cc2d3a2a4..edc5f3748 100644 --- a/commet/lib/service/background_service_notifications/background_service_task_notification2.dart +++ b/commet/lib/service/background_service_notifications/background_service_task_notification2.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:collection/collection.dart'; import 'package:commet/cache/file_cache.dart'; import 'package:commet/client/components/direct_messages/direct_message_component.dart'; @@ -86,9 +87,12 @@ class BackgroundNotificationsManager2 { Log.onError(e, s); try { - NotificationManager.notify(ErrorNotificationContent( + NotificationManager.notify( + ErrorNotificationContent( title: "An error occurred while processing notifications", - content: "${e} \n\n ${s}")); + content: "${e} \n\n ${s}", + ), + ); } catch (_) {} } @@ -127,9 +131,12 @@ class BackgroundNotificationsManager2 { final clients = preferences.getRegisteredMatrixClients(); if (clients?.contains(localClientId) != true) { - NotificationManager.notify(ErrorNotificationContent( + NotificationManager.notify( + ErrorNotificationContent( title: "An error occurred while processing notifications", - content: "Failed to find client: $localClientId")); + content: "Failed to find client: $localClientId", + ), + ); return; } @@ -149,9 +156,12 @@ class BackgroundNotificationsManager2 { } if (room == null) { - NotificationManager.notify(ErrorNotificationContent( + NotificationManager.notify( + ErrorNotificationContent( title: "An error occurred while processing notifications", - content: "Failed to find room: $roomId ${data}")); + content: "Failed to find room: $roomId ${data}", + ), + ); return; } @@ -176,7 +186,8 @@ class BackgroundNotificationsManager2 { if (event == null) { throw Exception( - "Unable to fetch room event for notification\n${exception}"); + "Unable to fetch room event for notification\n${exception}", + ); } Log.e("got event: ${event}"); @@ -184,19 +195,20 @@ class BackgroundNotificationsManager2 { var member = await room.fetchMember(event.senderId); var content = MessageNotificationContent( - senderName: member.displayName, - senderId: event.senderId, - roomName: room.displayName, - content: event.plainTextBody, - eventId: eventId, - roomId: roomId, - clientId: client.identifier, - senderImage: member.avatar, - roomImageId: room.avatarId, - senderImageId: member.avatarId, - roomImage: room.avatar, - room: room, - isDirectMessage: isDirectMessage); + senderName: member.displayName, + senderId: event.senderId, + roomName: room.displayName, + content: event.plainTextBody, + eventId: eventId, + roomId: roomId, + clientId: client.identifier, + senderImage: member.avatar, + roomImageId: room.avatarId, + senderImageId: member.avatarId, + roomImage: room.avatar, + room: room, + isDirectMessage: isDirectMessage, + ); Log.i("Sender image: ${member.avatar}"); @@ -205,9 +217,12 @@ class BackgroundNotificationsManager2 { Log.e("An error occured while processing the notification service loop"); Log.onError(e, s); - NotificationManager.notify(ErrorNotificationContent( + NotificationManager.notify( + ErrorNotificationContent( title: "An error occurred while processing notifications", - content: "${e} \n\n ${s}")); + content: "${e} \n\n ${s}", + ), + ); } } } diff --git a/commet/lib/single_instance.dart b/commet/lib/single_instance.dart index abf197a70..c3cad7104 100644 --- a/commet/lib/single_instance.dart +++ b/commet/lib/single_instance.dart @@ -1,10 +1,12 @@ import 'dart:io'; import 'dart:typed_data'; + import 'package:commet/config/app_config.dart'; import 'package:commet/config/platform_utils.dart'; import 'package:commet/debug/log.dart'; import 'package:dart_ipc/dart_ipc.dart'; + import 'dart:convert'; import 'package:window_manager/window_manager.dart'; @@ -34,7 +36,8 @@ class SingleInstance { if (PlatformUtils.isLinux) { if (e.osError?.errorCode == 111) { Log.i( - "Socket exists but did not respond, the main instance either closed or crashed, so it should be fine to remove the socket"); + "Socket exists but did not respond, the main instance either closed or crashed, so it should be fine to remove the socket", + ); await File(path).delete(); return false; } @@ -66,17 +69,21 @@ class SingleInstance { static void handleSocket(Socket socket, ServerSocket serverSocket) { socket.write(jsonEncode({"type": "hello"})); - socket.listen((data) { - try { - handleSocketMessageReceived(data); - } catch (e, s) { - Log.onError(e, s); - } - }, onDone: () { - print("Client Done"); - }, onError: (e) { - print("Client Error: $e"); - }); + socket.listen( + (data) { + try { + handleSocketMessageReceived(data); + } catch (e, s) { + Log.onError(e, s); + } + }, + onDone: () { + print("Client Done"); + }, + onError: (e) { + print("Client Error: $e"); + }, + ); } static void handleSocketMessageReceived(Uint8List data) { diff --git a/commet/lib/ui/atoms/adaptive_context_menu.dart b/commet/lib/ui/atoms/adaptive_context_menu.dart index 93a6c1fa2..dba5e3cd4 100644 --- a/commet/lib/ui/atoms/adaptive_context_menu.dart +++ b/commet/lib/ui/atoms/adaptive_context_menu.dart @@ -4,11 +4,12 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class AdaptiveContextMenu extends StatelessWidget { - const AdaptiveContextMenu( - {required this.items, - this.modal = false, - required this.child, - super.key}); + const AdaptiveContextMenu({ + required this.items, + this.modal = false, + required this.child, + super.key, + }); final List items; final Widget child; final bool modal; @@ -20,54 +21,51 @@ class AdaptiveContextMenu extends StatelessWidget { } if (MediaQuery.of(context).desktop) { - return tiamat.ContextMenu( - child: child, - items: items, - modal: modal, - ); + return tiamat.ContextMenu(child: child, items: items, modal: modal); } else { var callback = () => showModalBottomSheet( - isDismissible: true, - showDragHandle: true, - context: context, - builder: (modalContext) => SingleChildScrollView( - child: ScaledSafeArea( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - spacing: 4, - mainAxisSize: MainAxisSize.min, - children: items.map((item) { - if (item.customBuilder != null) { - return item.customBuilder!.call( - context, - () { - Navigator.of(modalContext).pop(); - item.onPressed?.call(); - }, - closeMenu: () { - Navigator.of(modalContext).pop(); - }, - ); - } + isDismissible: true, + showDragHandle: true, + context: context, + builder: (modalContext) => SingleChildScrollView( + child: ScaledSafeArea( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + spacing: 4, + mainAxisSize: MainAxisSize.min, + children: items.map((item) { + if (item.customBuilder != null) { + return item.customBuilder!.call( + context, + () { + Navigator.of(modalContext).pop(); + item.onPressed?.call(); + }, + closeMenu: () { + Navigator.of(modalContext).pop(); + }, + ); + } - return SizedBox( - height: 50, - child: tiamat.TextButton( - item.text, - textColor: Theme.of(context).colorScheme.onSurface, - icon: item.icon, - onTap: () { - Navigator.of(modalContext).pop(); - item.onPressed?.call(); - }, - ), - ); - }).toList(), + return SizedBox( + height: 50, + child: tiamat.TextButton( + item.text, + textColor: Theme.of(context).colorScheme.onSurface, + icon: item.icon, + onTap: () { + Navigator.of(modalContext).pop(); + item.onPressed?.call(); + }, ), - ), - ), - )); + ); + }).toList(), + ), + ), + ), + ), + ); return InkWell( child: child, diff --git a/commet/lib/ui/atoms/blurred_image_background.dart b/commet/lib/ui/atoms/blurred_image_background.dart index 94784cc4c..f2193179c 100644 --- a/commet/lib/ui/atoms/blurred_image_background.dart +++ b/commet/lib/ui/atoms/blurred_image_background.dart @@ -3,12 +3,14 @@ import 'dart:ui'; import 'package:flutter/material.dart'; class BlurredImageBackground extends StatelessWidget { - const BlurredImageBackground(this.image, - {super.key, - this.child, - this.sigma = 5, - this.height = 90, - this.backgroundColor = Colors.transparent}); + const BlurredImageBackground( + this.image, { + super.key, + this.child, + this.sigma = 5, + this.height = 90, + this.backgroundColor = Colors.transparent, + }); final ImageProvider image; final Color backgroundColor; final Widget? child; @@ -22,26 +24,37 @@ class BlurredImageBackground extends StatelessWidget { ClipRect( child: ImageFiltered( imageFilter: ImageFilter.blur( - sigmaX: sigma, sigmaY: sigma, tileMode: TileMode.clamp), + sigmaX: sigma, + sigmaY: sigma, + tileMode: TileMode.clamp, + ), child: DecoratedBox( decoration: BoxDecoration( - image: DecorationImage(image: image, fit: BoxFit.cover)), + image: DecorationImage(image: image, fit: BoxFit.cover), + ), child: Container(), ), ), ), ClipRect( - child: DecoratedBox( - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [Colors.transparent, backgroundColor], - begin: Alignment.topCenter, - stops: const [0, 0.8], - end: Alignment.bottomCenter)), - child: Container())), + child: DecoratedBox( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [Colors.transparent, backgroundColor], + begin: Alignment.topCenter, + stops: const [0, 0.8], + end: Alignment.bottomCenter, + ), + ), + child: Container(), + ), + ), SafeArea( - child: SizedBox( - height: height, child: child != null ? child! : Container())) + child: SizedBox( + height: height, + child: child != null ? child! : Container(), + ), + ), ], ); } diff --git a/commet/lib/ui/atoms/code_block.dart b/commet/lib/ui/atoms/code_block.dart index 68197a713..db7dc8009 100644 --- a/commet/lib/ui/atoms/code_block.dart +++ b/commet/lib/ui/atoms/code_block.dart @@ -4,8 +4,10 @@ import 'package:flutter_highlighter/flutter_highlighter.dart'; import 'package:tiamat/tiamat.dart' as tiamat; const _darkTheme = { - 'root': - TextStyle(color: Color(0xffabb2bf), backgroundColor: Colors.transparent), + 'root': TextStyle( + color: Color(0xffabb2bf), + backgroundColor: Colors.transparent, + ), 'comment': TextStyle(color: Color(0xff5c6370), fontStyle: FontStyle.italic), 'quote': TextStyle(color: Color(0xff5c6370), fontStyle: FontStyle.italic), 'doctag': TextStyle(color: Color(0xffc678dd)), @@ -42,8 +44,10 @@ const _darkTheme = { }; const _lightTheme = { - 'root': - TextStyle(color: Color(0xff383a42), backgroundColor: Colors.transparent), + 'root': TextStyle( + color: Color(0xff383a42), + backgroundColor: Colors.transparent, + ), 'comment': TextStyle(color: Color(0xffa0a1a7), fontStyle: FontStyle.italic), 'quote': TextStyle(color: Color(0xffa0a1a7), fontStyle: FontStyle.italic), 'doctag': TextStyle(color: Color(0xffa626a4)), @@ -80,8 +84,12 @@ const _lightTheme = { }; class Codeblock extends StatelessWidget { - const Codeblock( - {required this.text, this.clipboardText, this.language, super.key}); + const Codeblock({ + required this.text, + this.clipboardText, + this.language, + super.key, + }); final String? clipboardText; final String text; @@ -94,80 +102,77 @@ class Codeblock extends StatelessWidget { : _lightTheme; return Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: Theme.of(context).colorScheme.surfaceContainerLow, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(4, 4, 0, 0), - child: clipboardText == null - ? SizedBox( - height: 0, - width: 0, - ) - : SizedBox( - width: 20, - height: 20, - child: tiamat.IconButton( - icon: Icons.copy, - size: 12, - onPressed: () { - Clipboard.setData( - ClipboardData(text: clipboardText!), - ); - }, - ), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(0, 4, 0, 0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (language != null && language != "") - Padding( - padding: const EdgeInsets.fromLTRB(4, 2, 4, 4), - child: tiamat.Text.labelLow(language!), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).colorScheme.surfaceContainerLow, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(4, 4, 0, 0), + child: clipboardText == null + ? SizedBox(height: 0, width: 0) + : SizedBox( + width: 20, + height: 20, + child: tiamat.IconButton( + icon: Icons.copy, + size: 12, + onPressed: () { + Clipboard.setData(ClipboardData(text: clipboardText!)); + }, ), - Flexible( - child: Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 8, 4), - child: language != null - ? SizedBox( - child: HighlightView( - text.trim(), - language: language, - theme: theme, - textStyle: const TextStyle( - fontFamily: "Code", - fontFeatures: [ - FontFeature.disable("calt") - ]), - ), - ) - : Text( + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 4, 0, 0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (language != null && language != "") + Padding( + padding: const EdgeInsets.fromLTRB(4, 2, 4, 4), + child: tiamat.Text.labelLow(language!), + ), + Flexible( + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 8, 4), + child: language != null + ? SizedBox( + child: HighlightView( text.trim(), + language: language, + theme: theme, + textStyle: const TextStyle( + fontFamily: "Code", + fontFeatures: [FontFeature.disable("calt")], + ), ), - ), + ) + : Text(text.trim()), ), - ], - ), + ), + ], ), - ], - )); + ), + ], + ), + ); } } class ExpandableCodeBlock extends StatefulWidget { - const ExpandableCodeBlock( - {required this.text, this.expanded = false, this.language, super.key}); + const ExpandableCodeBlock({ + required this.text, + this.expanded = false, + this.language, + super.key, + }); final String text; final String? language; @@ -212,36 +217,32 @@ class _ExpandableCodeBlockState extends State { mainAxisSize: MainAxisSize.min, children: [ ShaderMask( - shaderCallback: (rect) { - return const LinearGradient( - end: Alignment.centerLeft, - begin: Alignment.bottomLeft, - colors: [ - Colors.purple, - Colors.transparent, - ], - stops: [ - 0.0, - 1.0, - ], - ).createShader(rect); - }, - blendMode: - (canExpand && !expanded) ? BlendMode.dstOut : BlendMode.dst, - child: Container( - child: Scrollbar( + shaderCallback: (rect) { + return const LinearGradient( + end: Alignment.centerLeft, + begin: Alignment.bottomLeft, + colors: [Colors.purple, Colors.transparent], + stops: [0.0, 1.0], + ).createShader(rect); + }, + blendMode: (canExpand && !expanded) + ? BlendMode.dstOut + : BlendMode.dst, + child: Container( + child: Scrollbar( + controller: controller, + child: SingleChildScrollView( controller: controller, - child: SingleChildScrollView( - controller: controller, - scrollDirection: Axis.horizontal, - child: Codeblock( - text: text, - clipboardText: widget.text, - language: widget.language, - ), + scrollDirection: Axis.horizontal, + child: Codeblock( + text: text, + clipboardText: widget.text, + language: widget.language, ), ), - )), + ), + ), + ), if (canExpand) Material( color: Theme.of(context).colorScheme.surfaceContainerLow, @@ -261,7 +262,8 @@ class _ExpandableCodeBlockState extends State { size: 20, ), tiamat.Text.labelLow( - expanded ? "Show Less" : "Show More") + expanded ? "Show Less" : "Show More", + ), ], ), ), diff --git a/commet/lib/ui/atoms/dot_indicator.dart b/commet/lib/ui/atoms/dot_indicator.dart index 2bc3b5411..21a498bb4 100644 --- a/commet/lib/ui/atoms/dot_indicator.dart +++ b/commet/lib/ui/atoms/dot_indicator.dart @@ -11,8 +11,9 @@ class DotIndicator extends StatelessWidget { height: 10, child: DecoratedBox( decoration: BoxDecoration( - color: color ?? Theme.of(context).colorScheme.secondary, - borderRadius: BorderRadius.circular(5)), + color: color ?? Theme.of(context).colorScheme.secondary, + borderRadius: BorderRadius.circular(5), + ), ), ); } diff --git a/commet/lib/ui/atoms/drag_drop_file_target.dart b/commet/lib/ui/atoms/drag_drop_file_target.dart index 8ce6ddf2a..7e6ff7a96 100644 --- a/commet/lib/ui/atoms/drag_drop_file_target.dart +++ b/commet/lib/ui/atoms/drag_drop_file_target.dart @@ -13,44 +13,48 @@ class DragDropFileTarget extends StatefulWidget { class _DragDropFileTargetState extends State { bool isFileHovered = false; - String get fileDragDropPrompt => Intl.message("Drop a file to upload...", - name: "fileDragDropPrompt", - desc: "Text that is shown when a user is dragging a file"); + String get fileDragDropPrompt => Intl.message( + "Drop a file to upload...", + name: "fileDragDropPrompt", + desc: "Text that is shown when a user is dragging a file", + ); @override Widget build(BuildContext context) { return IgnorePointer( child: DropTarget( - onDragEntered: (ev) { - print(ev); - setState(() { - isFileHovered = true; - }); - }, - onDragExited: (_) { - setState(() { - isFileHovered = false; - }); - }, - onDragDone: (detail) => widget.onDropComplete?.call(detail), - child: Stack( - children: [ - AnimatedOpacity( - duration: const Duration(milliseconds: 500), - curve: Curves.easeOutExpo, - opacity: isFileHovered ? 0.5 : 0, - child: Container(color: Colors.black), + onDragEntered: (ev) { + print(ev); + setState(() { + isFileHovered = true; + }); + }, + onDragExited: (_) { + setState(() { + isFileHovered = false; + }); + }, + onDragDone: (detail) => widget.onDropComplete?.call(detail), + child: Stack( + children: [ + AnimatedOpacity( + duration: const Duration(milliseconds: 500), + curve: Curves.easeOutExpo, + opacity: isFileHovered ? 0.5 : 0, + child: Container(color: Colors.black), + ), + AnimatedOpacity( + duration: const Duration(milliseconds: 500), + curve: Curves.easeOutExpo, + opacity: isFileHovered ? 1 : 0, + child: Align( + alignment: Alignment.center, + child: tiamat.Text.largeTitle(fileDragDropPrompt), ), - AnimatedOpacity( - duration: const Duration(milliseconds: 500), - curve: Curves.easeOutExpo, - opacity: isFileHovered ? 1 : 0, - child: Align( - alignment: Alignment.center, - child: tiamat.Text.largeTitle(fileDragDropPrompt)), - ), - ], - )), + ), + ], + ), + ), ); } } diff --git a/commet/lib/ui/atoms/emoji_reaction.dart b/commet/lib/ui/atoms/emoji_reaction.dart index 7ef430f1f..2891beab4 100644 --- a/commet/lib/ui/atoms/emoji_reaction.dart +++ b/commet/lib/ui/atoms/emoji_reaction.dart @@ -7,13 +7,14 @@ import 'package:flutter/material.dart' as material; import 'emoji_widget.dart'; class EmojiReaction extends StatelessWidget { - const EmojiReaction( - {required this.emoji, - required this.numReactions, - this.highlighted = false, - this.onTapped, - this.onLongPressed, - super.key}); + const EmojiReaction({ + required this.emoji, + required this.numReactions, + this.highlighted = false, + this.onTapped, + this.onLongPressed, + super.key, + }); final Function(Emoticon emote)? onTapped; final Function(Emoticon emote)? onLongPressed; @@ -37,25 +38,19 @@ class EmojiReaction extends StatelessWidget { borderRadius: borderRadius, child: DecoratedBox( decoration: BoxDecoration( - color: bgColor.withAlpha(70), - border: Border.all(color: bgColor, width: 1), - borderRadius: borderRadius), + color: bgColor.withAlpha(70), + border: Border.all(color: bgColor, width: 1), + borderRadius: borderRadius, + ), child: Padding( padding: const EdgeInsets.fromLTRB(5, 3, 5, 3), child: Row( mainAxisSize: MainAxisSize.min, children: [ - EmojiWidget( - emoji, - height: 17, - ), - const SizedBox( - width: 5, - ), + EmojiWidget(emoji, height: 17), + const SizedBox(width: 5), tiamat.Text.label(numReactions.toString()), - const SizedBox( - width: 3, - ), + const SizedBox(width: 3), ], ), ), diff --git a/commet/lib/ui/atoms/emoji_widget.dart b/commet/lib/ui/atoms/emoji_widget.dart index 9d924e452..4fd359371 100644 --- a/commet/lib/ui/atoms/emoji_widget.dart +++ b/commet/lib/ui/atoms/emoji_widget.dart @@ -8,40 +8,38 @@ class EmojiWidget extends StatelessWidget { double height; EdgeInsetsGeometry padding; - EmojiWidget(this.emoji, - {super.key, - this.height = 24, - this.padding = const EdgeInsetsGeometry.all(0)}); + EmojiWidget( + this.emoji, { + super.key, + this.height = 24, + this.padding = const EdgeInsetsGeometry.all(0), + }); @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.fromLTRB(2, 0, 2, 0), - child: emoji.image != null - ? SizedBox( + padding: const EdgeInsets.fromLTRB(2, 0, 2, 0), + child: emoji.image != null + ? SizedBox( + width: height, + height: height, + child: FadeInImage( + placeholder: tiamat.transparentImage.image, + fadeInDuration: Durations.medium1, + filterQuality: FilterQuality.medium, + fit: BoxFit.contain, width: height, height: height, - child: FadeInImage( - placeholder: tiamat.transparentImage.image, - fadeInDuration: Durations.medium1, - filterQuality: FilterQuality.medium, - fit: BoxFit.contain, - width: height, - height: height, - image: emoji.image!, - ), - ) - : SizedBox( - height: height, - child: FittedBox( - fit: BoxFit.cover, - child: Padding( - padding: padding, - child: Text( - emoji.slug, - ), - ), - ), - )); + image: emoji.image!, + ), + ) + : SizedBox( + height: height, + child: FittedBox( + fit: BoxFit.cover, + child: Padding(padding: padding, child: Text(emoji.slug)), + ), + ), + ); } } diff --git a/commet/lib/ui/atoms/floating_tile.dart b/commet/lib/ui/atoms/floating_tile.dart index 7920643da..542b30d5a 100644 --- a/commet/lib/ui/atoms/floating_tile.dart +++ b/commet/lib/ui/atoms/floating_tile.dart @@ -4,10 +4,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; class FloatingTile extends StatefulWidget { - const FloatingTile( - {super.key, - required this.child, - this.initialPosition = Alignment.topRight}); + const FloatingTile({ + super.key, + required this.child, + this.initialPosition = Alignment.topRight, + }); final Alignment initialPosition; final Widget child; @@ -56,12 +57,13 @@ class _FloatingTileState extends State { } class TileOverlay extends StatefulWidget { - const TileOverlay( - {super.key, - required this.child, - this.initialPosition = Alignment.topRight, - this.initialLayoutSize = Rect.zero, - this.safeAreaPadding = EdgeInsets.zero}); + const TileOverlay({ + super.key, + required this.child, + this.initialPosition = Alignment.topRight, + this.initialLayoutSize = Rect.zero, + this.safeAreaPadding = EdgeInsets.zero, + }); final Rect initialLayoutSize; final EdgeInsets safeAreaPadding; final Alignment initialPosition; @@ -89,7 +91,9 @@ class _TileOverlayState extends State { break; case Alignment.bottomRight: offset = Offset( - widget.initialLayoutSize.width, widget.initialLayoutSize.height); + widget.initialLayoutSize.width, + widget.initialLayoutSize.height, + ); break; case Alignment.topLeft: offset = Offset.zero; @@ -97,7 +101,11 @@ class _TileOverlayState extends State { } offset = getNearestPoint( - offset, Offset.zero, widget.initialLayoutSize, widget.safeAreaPadding); + offset, + Offset.zero, + widget.initialLayoutSize, + widget.safeAreaPadding, + ); SchedulerBinding.instance.addPostFrameCallback(postFrameCallback); } @@ -107,26 +115,32 @@ class _TileOverlayState extends State { } Offset getNearestPoint( - Offset currentPos, Offset size, Rect bounds, EdgeInsets safeAreaPadding) { + Offset currentPos, + Offset size, + Rect bounds, + EdgeInsets safeAreaPadding, + ) { var p = 10.0; var b = Rect.fromLTRB( - bounds.left / preferences.appScale.value, - bounds.top / preferences.appScale.value, - bounds.right / preferences.appScale.value, - bounds.bottom / preferences.appScale.value); + bounds.left / preferences.appScale.value, + bounds.top / preferences.appScale.value, + bounds.right / preferences.appScale.value, + bounds.bottom / preferences.appScale.value, + ); var rect = Rect.fromLTRB( - b.left + p + safeAreaPadding.left, - b.top + p + safeAreaPadding.top, - b.right - p - size.dx - safeAreaPadding.right, - b.bottom - p - size.dy - safeAreaPadding.bottom); + b.left + p + safeAreaPadding.left, + b.top + p + safeAreaPadding.top, + b.right - p - size.dx - safeAreaPadding.right, + b.bottom - p - size.dy - safeAreaPadding.bottom, + ); var points = [ Offset(rect.left, rect.top), Offset(rect.right, rect.top), Offset(rect.left, rect.bottom), - Offset(rect.right, rect.bottom) + Offset(rect.right, rect.bottom), ]; var minDistance = 9999999999.0; @@ -152,10 +166,11 @@ class _TileOverlayState extends State { } var point = getNearestPoint( - currentPoint, - Offset(childSize.width, childSize.height), - Rect.fromLTWH(0, 0, size.width, size.height), - widget.safeAreaPadding); + currentPoint, + Offset(childSize.width, childSize.height), + Rect.fromLTWH(0, 0, size.width, size.height), + widget.safeAreaPadding, + ); if ((point - offset).distance > 1) { setState(() { @@ -172,24 +187,26 @@ class _TileOverlayState extends State { return false; }, child: AnimatedPositioned( - left: offset.dx, - top: offset.dy, - duration: const Duration(milliseconds: 300), - curve: Curves.easeOutCubic, - child: GestureDetector( - onPanUpdate: (details) { - setState(() { - offset = details.globalPosition - startPosition; - }); - }, - onPanStart: (details) { - startPosition = details.localPosition; - }, - onPanEnd: (details) { - var pos = offset + details.velocity.pixelsPerSecond; - updatePoint(pos); - }, - child: Container(key: childKey, child: widget.child))), + left: offset.dx, + top: offset.dy, + duration: const Duration(milliseconds: 300), + curve: Curves.easeOutCubic, + child: GestureDetector( + onPanUpdate: (details) { + setState(() { + offset = details.globalPosition - startPosition; + }); + }, + onPanStart: (details) { + startPosition = details.localPosition; + }, + onPanEnd: (details) { + var pos = offset + details.velocity.pixelsPerSecond; + updatePoint(pos); + }, + child: Container(key: childKey, child: widget.child), + ), + ), ); } } diff --git a/commet/lib/ui/atoms/gradient_background.dart b/commet/lib/ui/atoms/gradient_background.dart index a27a672b9..25a2e43f0 100644 --- a/commet/lib/ui/atoms/gradient_background.dart +++ b/commet/lib/ui/atoms/gradient_background.dart @@ -1,12 +1,13 @@ import 'package:flutter/material.dart'; class GradientBackground extends StatelessWidget { - const GradientBackground( - {required this.begin, - required this.end, - super.key, - this.child, - required this.backgroundColor}); + const GradientBackground({ + required this.begin, + required this.end, + super.key, + this.child, + required this.backgroundColor, + }); final Color backgroundColor; final Widget? child; final Alignment begin; @@ -16,11 +17,13 @@ class GradientBackground extends StatelessWidget { Widget build(BuildContext context) { return DecoratedBox( decoration: BoxDecoration( - gradient: LinearGradient( - colors: [Colors.transparent, backgroundColor], - begin: begin, - stops: const [0, 1], - end: end)), + gradient: LinearGradient( + colors: [Colors.transparent, backgroundColor], + begin: begin, + stops: const [0, 1], + end: end, + ), + ), child: child, ); } diff --git a/commet/lib/ui/atoms/hover_menu.dart b/commet/lib/ui/atoms/hover_menu.dart index 7405faa97..c5e2f8f8e 100644 --- a/commet/lib/ui/atoms/hover_menu.dart +++ b/commet/lib/ui/atoms/hover_menu.dart @@ -2,13 +2,14 @@ import 'package:commet/utils/debounce.dart'; import 'package:flutter/material.dart'; class HoverMenu extends StatefulWidget { - const HoverMenu( - {super.key, - this.menuAlignment = Alignment.topLeft, - this.parentAlignment = Alignment.topLeft, - this.onHoverStateChanged, - required this.builder, - required this.child}); + const HoverMenu({ + super.key, + this.menuAlignment = Alignment.topLeft, + this.parentAlignment = Alignment.topLeft, + this.onHoverStateChanged, + required this.builder, + required this.child, + }); final Widget child; final Widget Function(BuildContext context) builder; final Function(bool hovered)? onHoverStateChanged; @@ -25,8 +26,9 @@ class HoverMenuState extends State { bool overlayHovered = false; - Debouncer overlayRemoveDebounder = - Debouncer(delay: Duration(milliseconds: 20)); + Debouncer overlayRemoveDebounder = Debouncer( + delay: Duration(milliseconds: 20), + ); void addOverlay() { widget.onHoverStateChanged?.call(true); @@ -42,25 +44,25 @@ class HoverMenuState extends State { return Row( children: [ CompositedTransformFollower( - link: link, - followerAnchor: widget.menuAlignment, - targetAnchor: widget.parentAlignment, - child: MouseRegion( - onEnter: (event) { - overlayRemoveDebounder.cancel(); - }, - onExit: (event) { - overlayRemoveDebounder.run(removeOverlay); - }, - child: widget.builder(context))), + link: link, + followerAnchor: widget.menuAlignment, + targetAnchor: widget.parentAlignment, + child: MouseRegion( + onEnter: (event) { + overlayRemoveDebounder.cancel(); + }, + onExit: (event) { + overlayRemoveDebounder.run(removeOverlay); + }, + child: widget.builder(context), + ), + ), ], ); }, ); - Overlay.of( - context, - ).insert(entry!); + Overlay.of(context).insert(entry!); } void removeOverlay() { @@ -77,18 +79,19 @@ class HoverMenuState extends State { return CompositedTransformTarget( link: link, child: MouseRegion( - onEnter: (event) { - overlayRemoveDebounder.cancel(); - if (entry == null) { - addOverlay(); - } - }, - onExit: (event) { - if (!overlayHovered) { - overlayRemoveDebounder.run(removeOverlay); - } - }, - child: widget.child), + onEnter: (event) { + overlayRemoveDebounder.cancel(); + if (entry == null) { + addOverlay(); + } + }, + onExit: (event) { + if (!overlayHovered) { + overlayRemoveDebounder.run(removeOverlay); + } + }, + child: widget.child, + ), ); } } diff --git a/commet/lib/ui/atoms/icon_button.dart b/commet/lib/ui/atoms/icon_button.dart index ad728f570..3e7108812 100644 --- a/commet/lib/ui/atoms/icon_button.dart +++ b/commet/lib/ui/atoms/icon_button.dart @@ -1,8 +1,12 @@ import 'package:flutter/material.dart'; class IconButton extends StatefulWidget { - const IconButton( - {super.key, this.size = 15, required this.icon, this.onPressed}); + const IconButton({ + super.key, + this.size = 15, + required this.icon, + this.onPressed, + }); final double size; final Function? onPressed; final IconData icon; @@ -17,38 +21,40 @@ class _IconButtonState extends State { @override Widget build(BuildContext context) { return Material( - color: Colors.transparent, - child: GestureDetector( - onTap: () => widget.onPressed?.call(), - child: MouseRegion( - onEnter: (event) { - setState(() { - hovered = true; - }); - }, - onExit: (event) { - setState(() { - hovered = false; - }); - }, - cursor: WidgetStateMouseCursor.clickable, - child: Padding( - padding: const EdgeInsets.all(4.0), - child: SizedBox( - width: widget.size, - height: widget.size, - child: Align( - alignment: Alignment.center, - child: Icon( - widget.icon, - size: widget.size, - color: hovered - ? Theme.of(context).colorScheme.onPrimary - : null, - )), + color: Colors.transparent, + child: GestureDetector( + onTap: () => widget.onPressed?.call(), + child: MouseRegion( + onEnter: (event) { + setState(() { + hovered = true; + }); + }, + onExit: (event) { + setState(() { + hovered = false; + }); + }, + cursor: WidgetStateMouseCursor.clickable, + child: Padding( + padding: const EdgeInsets.all(4.0), + child: SizedBox( + width: widget.size, + height: widget.size, + child: Align( + alignment: Alignment.center, + child: Icon( + widget.icon, + size: widget.size, + color: hovered + ? Theme.of(context).colorScheme.onPrimary + : null, + ), ), ), ), - )); + ), + ), + ); } } diff --git a/commet/lib/ui/atoms/inherited_offstage.dart b/commet/lib/ui/atoms/inherited_offstage.dart index 88094d4dc..443d9f5e0 100644 --- a/commet/lib/ui/atoms/inherited_offstage.dart +++ b/commet/lib/ui/atoms/inherited_offstage.dart @@ -1,8 +1,11 @@ import 'package:flutter/material.dart'; class InheritedOffstage extends InheritedWidget { - const InheritedOffstage( - {required this.offstage, super.key, required super.child}); + const InheritedOffstage({ + required this.offstage, + super.key, + required super.child, + }); final bool offstage; diff --git a/commet/lib/ui/atoms/keyboard_adaptor.dart b/commet/lib/ui/atoms/keyboard_adaptor.dart index d831b250f..b08dcf900 100644 --- a/commet/lib/ui/atoms/keyboard_adaptor.dart +++ b/commet/lib/ui/atoms/keyboard_adaptor.dart @@ -1,4 +1,5 @@ import 'dart:math'; + import 'package:commet/main.dart'; import 'package:commet/utils/scaled_app.dart'; import 'package:flutter/material.dart'; @@ -48,7 +49,8 @@ class _KeyboardAdaptorState extends State { var padding = scaledQuery.viewPadding; - bool shouldPushContent = widget.shouldPushContent == null || + bool shouldPushContent = + widget.shouldPushContent == null || widget.shouldPushContent?.call() == true; if (sizeOverride != null && offset > sizeOverride!) { @@ -69,8 +71,9 @@ class _KeyboardAdaptorState extends State { child: AnimatedContainer( duration: Durations.short1, child: widget.paddingContent, - height: - (!widget.enabled && sizeOverride == null) ? 0 : contentHeight, + height: (!widget.enabled && sizeOverride == null) + ? 0 + : contentHeight, ), ), Container( @@ -80,9 +83,7 @@ class _KeyboardAdaptorState extends State { height: widget.enabled ? pushHeight : 0, ), ), - SizedBox( - height: widget.enabled ? padding.bottom : 0, - ) + SizedBox(height: widget.enabled ? padding.bottom : 0), ], ); } diff --git a/commet/lib/ui/atoms/lightbox.dart b/commet/lib/ui/atoms/lightbox.dart index b579d23f5..9da9aa510 100644 --- a/commet/lib/ui/atoms/lightbox.dart +++ b/commet/lib/ui/atoms/lightbox.dart @@ -10,6 +10,7 @@ import 'package:commet/ui/molecules/video_player/video_player_controller.dart'; import 'package:commet/utils/image/lod_image.dart'; import 'package:flutter/material.dart'; import 'package:tiamat/atoms/popup_dialog.dart'; + import 'dart:ui' as ui; class Lightbox extends StatefulWidget { @@ -45,31 +46,35 @@ class Lightbox extends StatefulWidget { Key? key, }) { return showGeneralDialog( - context: context, - barrierDismissible: false, - barrierLabel: "LIGHTBOX", - barrierColor: PopupDialog.barrierColor, - pageBuilder: (context, _, __) { - return Lightbox( - image: image, - video: video, - videoController: videoController, - aspectRatio: aspectRatio, - thumbnail: thumbnail, - contentKey: key, - customWidget: customWidget, - key: GlobalKey(), - ); - }, - transitionDuration: const Duration(milliseconds: 300), - transitionBuilder: (context, animation, secondaryAnimation, child) => - SlideTransition( - position: - Tween(begin: const Offset(0, 1), end: const Offset(0, 0)) - .animate(CurvedAnimation( - parent: animation, curve: Curves.easeOutCubic)), - child: child, - )); + context: context, + barrierDismissible: false, + barrierLabel: "LIGHTBOX", + barrierColor: PopupDialog.barrierColor, + pageBuilder: (context, _, __) { + return Lightbox( + image: image, + video: video, + videoController: videoController, + aspectRatio: aspectRatio, + thumbnail: thumbnail, + contentKey: key, + customWidget: customWidget, + key: GlobalKey(), + ); + }, + transitionDuration: const Duration(milliseconds: 300), + transitionBuilder: (context, animation, secondaryAnimation, child) => + SlideTransition( + position: Tween(begin: const Offset(0, 1), end: const Offset(0, 0)) + .animate( + CurvedAnimation( + parent: animation, + curve: Curves.easeOutCubic, + ), + ), + child: child, + ), + ); } } @@ -98,8 +103,8 @@ class _LightboxState extends State with TickerProviderStateMixin { curve: Curves.easeOut, ).drive(Tween(begin: 0.6, end: 1.0)); - late final Animation rotation = - ConstantTween(0.0).animate(_controller); + late final Animation rotation = ConstantTween(0.0) + .animate(_controller); late final Animation scale = ConstantTween(1.0).animate(_controller); @override @@ -190,7 +195,8 @@ class _LightboxState extends State with TickerProviderStateMixin { var screenRatio = size.width / size.height; bool prevValue = rotate; setState(() { - rotate = (aspectRatio < 1 && screenRatio > 1) || + rotate = + (aspectRatio < 1 && screenRatio > 1) || (aspectRatio > 1 && screenRatio < 1); }); @@ -207,11 +213,13 @@ class _LightboxState extends State with TickerProviderStateMixin { widget.image! .resolve(const ImageConfiguration()) - .addListener(ImageStreamListener((info, synchronousCall) { - if (!completer.isCompleted) { - completer.complete(info.image); - } - })); + .addListener( + ImageStreamListener((info, synchronousCall) { + if (!completer.isCompleted) { + completer.complete(info.image); + } + }), + ); return completer.future; } @@ -252,72 +260,76 @@ class _LightboxState extends State with TickerProviderStateMixin { child: GestureDetector( onTap: () {}, child: AspectRatio( - aspectRatio: aspectRatio, - child: widget.customWidget ?? - (widget.image != null - ? Stack( - fit: StackFit.expand, - children: [ - Image( - fit: BoxFit.cover, - image: widget.image!, - isAntiAlias: true, - filterQuality: - FilterQuality.medium, - ), - if (loadingHighQuality) - Align( - alignment: - Alignment.bottomRight, - child: Padding( - padding: - const EdgeInsets.all( - 8.0), - child: Container( - decoration: BoxDecoration( - color: Theme.of( - context) - .colorScheme - .surfaceContainer, - borderRadius: - BorderRadius - .circular( - 8)), - child: Padding( - padding: - const EdgeInsets - .all(8.0), - child: SizedBox( - width: 12, - height: 12, - child: - CircularProgressIndicator()), - )), + aspectRatio: aspectRatio, + child: + widget.customWidget ?? + (widget.image != null + ? Stack( + fit: StackFit.expand, + children: [ + Image( + fit: BoxFit.cover, + image: widget.image!, + isAntiAlias: true, + filterQuality: + FilterQuality.medium, + ), + if (loadingHighQuality) + Align( + alignment: + Alignment.bottomRight, + child: Padding( + padding: const EdgeInsets.all( + 8.0, ), - ) - ], - ) - : widget.video != null - ? dismissing - ? widget.thumbnail != null - ? Image( - fit: BoxFit.cover, - image: - widget.thumbnail!, - ) - : Container( - color: Colors.black, - ) - : VideoPlayer( - widget.video!, - controller: - widget.videoController, - showProgressBar: true, - canGoFullscreen: false, - thumbnail: widget.thumbnail, - key: widget.contentKey, - ) - : const Placeholder())), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context) + .colorScheme + .surfaceContainer, + borderRadius: + BorderRadius.circular( + 8, + ), + ), + child: Padding( + padding: + const EdgeInsets.all( + 8.0, + ), + child: SizedBox( + width: 12, + height: 12, + child: + CircularProgressIndicator(), + ), + ), + ), + ), + ), + ], + ) + : widget.video != null + ? dismissing + ? widget.thumbnail != null + ? Image( + fit: BoxFit.cover, + image: widget.thumbnail!, + ) + : Container( + color: Colors.black, + ) + : VideoPlayer( + widget.video!, + controller: + widget.videoController, + showProgressBar: true, + canGoFullscreen: false, + thumbnail: widget.thumbnail, + key: widget.contentKey, + ) + : const Placeholder()), + ), ), ), ), diff --git a/commet/lib/ui/atoms/mention.dart b/commet/lib/ui/atoms/mention.dart index f302d22fa..507a3f62c 100644 --- a/commet/lib/ui/atoms/mention.dart +++ b/commet/lib/ui/atoms/mention.dart @@ -2,16 +2,17 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class MentionWidget extends StatelessWidget { - const MentionWidget( - {required this.displayName, - required this.placeholderColor, - this.avatar, - this.style, - this.fallbackIcon, - this.vias, - this.onTap, - this.showAvatar = true, - super.key}); + const MentionWidget({ + required this.displayName, + required this.placeholderColor, + this.avatar, + this.style, + this.fallbackIcon, + this.vias, + this.onTap, + this.showAvatar = true, + super.key, + }); final String displayName; final ImageProvider? avatar; final Function()? onTap; @@ -24,57 +25,64 @@ class MentionWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Material( - color: Theme.of(context).colorScheme.primary.withAlpha(30), - borderRadius: BorderRadius.circular(4), - clipBehavior: Clip.hardEdge, - child: InkWell( - onTap: onTap, - child: Padding( - padding: const EdgeInsets.fromLTRB(4, 0, 4, 0), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (fallbackIcon != null && avatar == null && showAvatar) - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 1, 0), - child: Icon( - fallbackIcon, - size: 14, + color: Theme.of(context).colorScheme.primary.withAlpha(30), + borderRadius: BorderRadius.circular(4), + clipBehavior: Clip.hardEdge, + child: InkWell( + onTap: onTap, + child: Padding( + padding: const EdgeInsets.fromLTRB(4, 0, 4, 0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (fallbackIcon != null && avatar == null && showAvatar) + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 1, 0), + child: Icon( + fallbackIcon, + size: 14, + color: tiamat.Text.adjustColor(context, placeholderColor), + ), + ), + if (avatar != null || fallbackIcon == null && showAvatar) + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 3, 0), + child: tiamat.Avatar( + placeholderText: displayName, + placeholderColor: placeholderColor, + image: avatar, + radius: 8, + ), + ), + Text( + displayName, + textScaler: TextScaler.noScaling, + style: (style ?? Theme.of(context).textTheme.bodyMedium) + ?.copyWith( color: tiamat.Text.adjustColor(context, placeholderColor), ), - ), - if (avatar != null || fallbackIcon == null && showAvatar) + ), + if (vias != null) + for (var i in vias!) Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 3, 0), - child: tiamat.Avatar( - placeholderText: displayName, - placeholderColor: placeholderColor, - image: avatar, - radius: 8, - ), - ), - Text(displayName, - textScaler: TextScaler.noScaling, - style: (style ?? Theme.of(context).textTheme.bodyMedium) - ?.copyWith( + padding: const EdgeInsets.fromLTRB(4, 0, 0, 0), + child: Text( + "($i)", + textScaler: TextScaler.noScaling, + style: (style ?? Theme.of(context).textTheme.bodyMedium) + ?.copyWith( + fontSize: 12, color: tiamat.Text.adjustColor( - context, placeholderColor))), - if (vias != null) - for (var i in vias!) - Padding( - padding: const EdgeInsets.fromLTRB(4, 0, 0, 0), - child: Text("($i)", - textScaler: TextScaler.noScaling, - style: - (style ?? Theme.of(context).textTheme.bodyMedium) - ?.copyWith( - fontSize: 12, - color: tiamat.Text.adjustColor( - context, placeholderColor))), + context, + placeholderColor, + ), + ), ), - ], - ), + ), + ], ), - )); + ), + ), + ); } } diff --git a/commet/lib/ui/atoms/message_attachment.dart b/commet/lib/ui/atoms/message_attachment.dart index b669ec834..404f49836 100644 --- a/commet/lib/ui/atoms/message_attachment.dart +++ b/commet/lib/ui/atoms/message_attachment.dart @@ -15,11 +15,13 @@ import 'package:tiamat/tiamat.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class MessageAttachment extends StatefulWidget { - const MessageAttachment(this.attachment, - {super.key, - this.ignorePointer = false, - this.constrainSize = true, - this.previewMedia = false}); + const MessageAttachment( + this.attachment, { + super.key, + this.ignorePointer = false, + this.constrainSize = true, + this.previewMedia = false, + }); final Attachment attachment; final bool ignorePointer; final bool previewMedia; @@ -57,8 +59,11 @@ class _MessageAttachmentState extends State { return buildAudio(attachment); } - return buildFile(Mime.toIcon(attachment.mimeType), attachment.name, - attachment.fileSize); + return buildFile( + Mime.toIcon(attachment.mimeType), + attachment.name, + attachment.fileSize, + ); } return const Placeholder(); @@ -71,36 +76,43 @@ class _MessageAttachmentState extends State { return IgnorePointer( ignoring: widget.ignorePointer, child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: Material( - color: Colors.transparent, - child: ConstrainedBox( - constraints: BoxConstraints( - maxHeight: 200, minHeight: 40, maxWidth: 500, minWidth: 40), - child: InkWell( - onTap: fullscreenAttachment, - child: Stack( - children: [ - FittedBox( - fit: BoxFit.fitWidth, - child: SizedBox( - width: attachment.width ?? 500, - height: attachment.height ?? 500, - child: Image( - image: attachment.image, - filterQuality: FilterQuality.medium, - // if we know the height, its safe to fill as it wont appear stretched - fit: attachment.width != null && - attachment.height != null - ? BoxFit.fill - : BoxFit.fitWidth, - ), - ), + borderRadius: BorderRadius.circular(10), + child: Material( + color: Colors.transparent, + child: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: 200, + minHeight: 40, + maxWidth: 500, + minWidth: 40, + ), + child: InkWell( + onTap: fullscreenAttachment, + child: Stack( + children: [ + FittedBox( + fit: BoxFit.fitWidth, + child: SizedBox( + width: attachment.width ?? 500, + height: attachment.height ?? 500, + child: Image( + image: attachment.image, + filterQuality: FilterQuality.medium, + // if we know the height, its safe to fill as it wont appear stretched + fit: + attachment.width != null && + attachment.height != null + ? BoxFit.fill + : BoxFit.fitWidth, ), - ], + ), ), - ), - ))), + ], + ), + ), + ), + ), + ), ); } @@ -115,32 +127,37 @@ class _MessageAttachmentState extends State { child: SizedBox( height: widget.constrainSize ? height + (showInfo ? 30 : 0) : null, width: max( - widget.constrainSize ? attachment.aspectRatio * height : 200, 200), + widget.constrainSize ? attachment.aspectRatio * height : 200, + 200, + ), child: Panel( - mainAxisSize: MainAxisSize.min, - header: showInfo - ? "${attachment.name} ${attachment.fileSize != null ? "- ${TextUtils.readableFileSize(attachment.fileSize!)}" : ""}" - : null, - mode: TileType.surfaceContainerLow, - padding: 0, - child: SizedBox( - height: height, - width: 500, - child: AspectRatio( - aspectRatio: attachment.aspectRatio, - child: isFullscreen - ? null - : VideoPlayer( - attachment.file, - streamUrl: attachment.streamUrl, - thumbnail: attachment.thumbnail, - fileName: attachment.name, - doThumbnail: true, - canGoFullscreen: true, - onFullscreen: fullscreenVideo, - controller: controller, - key: videoPlayerKey, - )))), + mainAxisSize: MainAxisSize.min, + header: showInfo + ? "${attachment.name} ${attachment.fileSize != null ? "- ${TextUtils.readableFileSize(attachment.fileSize!)}" : ""}" + : null, + mode: TileType.surfaceContainerLow, + padding: 0, + child: SizedBox( + height: height, + width: 500, + child: AspectRatio( + aspectRatio: attachment.aspectRatio, + child: isFullscreen + ? null + : VideoPlayer( + attachment.file, + streamUrl: attachment.streamUrl, + thumbnail: attachment.thumbnail, + fileName: attachment.name, + doThumbnail: true, + canGoFullscreen: true, + onFullscreen: fullscreenVideo, + controller: controller, + key: videoPlayerKey, + ), + ), + ), + ), ), ); } @@ -161,13 +178,14 @@ class _MessageAttachmentState extends State { setState(() { isFullscreen = true; }); - Lightbox.show(context, - video: attachment.file, - aspectRatio: attachment.aspectRatio, - thumbnail: attachment.thumbnail, - videoController: controller, - key: videoPlayerKey) - .then((value) { + Lightbox.show( + context, + video: attachment.file, + aspectRatio: attachment.aspectRatio, + thumbnail: attachment.thumbnail, + videoController: controller, + key: videoPlayerKey, + ).then((value) { setState(() { isFullscreen = false; }); @@ -205,7 +223,8 @@ class _MessageAttachmentState extends State { ), if (fileSize != null) tiamat.Text.labelLow( - TextUtils.readableFileSize(fileSize)) + TextUtils.readableFileSize(fileSize), + ), ], ), ), @@ -238,7 +257,7 @@ class _MessageAttachmentState extends State { }, ), ), - ) + ), ], ), ), @@ -250,7 +269,9 @@ class _MessageAttachmentState extends State { } Future downloadTask( - FileAttachment attachment, String path) async { + FileAttachment attachment, + String path, + ) async { await attachment.file.save(path); return BackgroundTaskStatus.completed; diff --git a/commet/lib/ui/atoms/notification_badge.dart b/commet/lib/ui/atoms/notification_badge.dart index 619f2d273..7bcc7c719 100644 --- a/commet/lib/ui/atoms/notification_badge.dart +++ b/commet/lib/ui/atoms/notification_badge.dart @@ -8,23 +8,26 @@ class NotificationBadge extends StatelessWidget { @override Widget build(BuildContext context) { return SizedBox( - width: size, - height: size, - child: DecoratedBox( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(size / 2), - color: Colors.red.shade600), - child: Center( - child: Text( - count > 9 ? "9+" : count.toString(), - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.bold, - fontSize: 10, - color: Colors.white, - shadows: [const BoxShadow(blurRadius: 2)]), + width: size, + height: size, + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(size / 2), + color: Colors.red.shade600, + ), + child: Center( + child: Text( + count > 9 ? "9+" : count.toString(), + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.bold, + fontSize: 10, + color: Colors.white, + shadows: [const BoxShadow(blurRadius: 2)], ), ), - )); + ), + ), + ); } } diff --git a/commet/lib/ui/atoms/notifying_list_builder.dart b/commet/lib/ui/atoms/notifying_list_builder.dart index 0c92804c4..320cee499 100644 --- a/commet/lib/ui/atoms/notifying_list_builder.dart +++ b/commet/lib/ui/atoms/notifying_list_builder.dart @@ -5,20 +5,25 @@ import 'package:flutter/widgets.dart'; import 'package:implicitly_animated_list/implicitly_animated_list.dart'; class NotifyingListBuilder extends StatefulWidget { - const NotifyingListBuilder( - {required this.list, - this.builder, - required this.itemBuilder, - this.shrinkWrap = false, - this.implicitlyAnimated = true, - this.sortFunction, - this.physics, - this.onSortStream, - super.key}); + const NotifyingListBuilder({ + required this.list, + this.builder, + required this.itemBuilder, + this.shrinkWrap = false, + this.implicitlyAnimated = true, + this.sortFunction, + this.physics, + this.onSortStream, + super.key, + }); final INotifyingList list; - final Widget Function(BuildContext context, - {required List list, required Widget child})? builder; + final Widget Function( + BuildContext context, { + required List list, + required Widget child, + })? + builder; final Widget Function(BuildContext context, T value) itemBuilder; final Stream? onSortStream; final bool shrinkWrap; @@ -82,7 +87,8 @@ class _NotifyingListBuilderState extends State> { physics: widget.physics, padding: EdgeInsets.zero, initialAnimation: false, - itemBuilder: widget.itemBuilder) + itemBuilder: widget.itemBuilder, + ) : ListView.builder( shrinkWrap: widget.shrinkWrap, itemCount: items.length, diff --git a/commet/lib/ui/atoms/pill.dart b/commet/lib/ui/atoms/pill.dart index bde7d8826..ec5ce4213 100644 --- a/commet/lib/ui/atoms/pill.dart +++ b/commet/lib/ui/atoms/pill.dart @@ -27,13 +27,12 @@ class Pill extends StatelessWidget { child: Container( padding: const EdgeInsets.all(2), decoration: BoxDecoration( - color: Theme.of(context).colorScheme.primary.withAlpha(200)), + color: Theme.of(context).colorScheme.primary.withAlpha(200), + ), child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, - children: [ - Text(displayText), - ], + children: [Text(displayText)], ), ), onTap: () {}, diff --git a/commet/lib/ui/atoms/random_emoji_button.dart b/commet/lib/ui/atoms/random_emoji_button.dart index 6c2a74fed..84bd0a3bc 100644 --- a/commet/lib/ui/atoms/random_emoji_button.dart +++ b/commet/lib/ui/atoms/random_emoji_button.dart @@ -4,11 +4,16 @@ import 'package:commet/config/layout_config.dart'; import 'package:commet/ui/atoms/emoji_widget.dart'; import 'package:commet/utils/emoji/unicode_emoji.dart'; import 'package:flutter/material.dart'; + import 'dart:ui' as ui; class RandomEmojiButton extends StatefulWidget { - const RandomEmojiButton( - {this.size = 20, this.toggled = false, this.onTap, super.key}); + const RandomEmojiButton({ + this.size = 20, + this.toggled = false, + this.onTap, + super.key, + }); final double size; final Function()? onTap; final bool toggled; @@ -31,8 +36,12 @@ class _RandomEmojiButtonState extends State { lightness = ui.clampDouble(hsl.lightness, 0.7, 1); } - color = - HSLColor.fromAHSL(1.0, hsl.hue, hsl.saturation, lightness).toColor(); + color = HSLColor.fromAHSL( + 1.0, + hsl.hue, + hsl.saturation, + lightness, + ).toColor(); bool showColor = hovered || widget.toggled; @@ -68,7 +77,9 @@ class _RandomEmojiButtonState extends State { duration: Duration(milliseconds: 100), child: ColorFiltered( colorFilter: ColorFilter.mode( - color, showColor ? BlendMode.dst : (BlendMode.modulate)), + color, + showColor ? BlendMode.dst : (BlendMode.modulate), + ), child: ColorFiltered( colorFilter: contrast(showColor ? 0 : 0.3), child: ColorFiltered( diff --git a/commet/lib/ui/atoms/rich_text/matrix_html_parser.dart b/commet/lib/ui/atoms/rich_text/matrix_html_parser.dart index f26c18735..ae8f21e51 100644 --- a/commet/lib/ui/atoms/rich_text/matrix_html_parser.dart +++ b/commet/lib/ui/atoms/rich_text/matrix_html_parser.dart @@ -26,8 +26,12 @@ import 'package:tiamat/config/style/theme_extensions.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class MatrixHtmlParser { - static Widget parse(String text, MatrixClient client, Room? room, - {bool mentionsRoom = true}) { + static Widget parse( + String text, + MatrixClient client, + Room? room, { + bool mentionsRoom = true, + }) { return MatrixHtmlState( text, client, @@ -39,8 +43,13 @@ class MatrixHtmlParser { } class MatrixHtmlState extends StatefulWidget { - const MatrixHtmlState(this.text, this.client, this.room, - {this.mentionsRoom = true, super.key}); + const MatrixHtmlState( + this.text, + this.client, + this.room, { + this.mentionsRoom = true, + super.key, + }); final String text; final MatrixClient client; final Room? room; @@ -110,16 +119,21 @@ class _MatrixHtmlStateState extends State { @override Widget build(BuildContext context) { - final SpoilerHtmlExtension spoiler = - SpoilerHtmlExtension(hideSpoiler, onTap); + final SpoilerHtmlExtension spoiler = SpoilerHtmlExtension( + hideSpoiler, + onTap, + ); var document = html_parser.parse(widget.text); bool big = shouldDoBigEmoji(document); var theme = TextTheme.of(context); // Making a new one of these for every message we pass might make a lot of garbage - var extension = - MatrixEmoticonHtmlExtension(widget.client, widget.room, big); + var extension = MatrixEmoticonHtmlExtension( + widget.client, + widget.room, + big, + ); var imageExtension = MatrixImageExtension(widget.client, widget.room); var linkify = LinkifyHtmlExtension(widget.client, widget.room, openLink); @@ -150,13 +164,12 @@ class _MatrixHtmlStateState extends State { "code": Style(backgroundColor: Colors.black.withAlpha(40)), "blockquote": Style( border: Border( - left: BorderSide( - color: Theme.of(context).colorScheme.primary, - width: 2, - )), - padding: HtmlPaddings( - left: HtmlPadding(4), + left: BorderSide( + color: Theme.of(context).colorScheme.primary, + width: 2, + ), ), + padding: HtmlPaddings(left: HtmlPadding(4)), margin: Margins( bottom: Margin(8), left: Margin(8), @@ -180,18 +193,9 @@ class _MatrixHtmlStateState extends State { padding: HtmlPaddings.all(0), color: Theme.of(context).colorScheme.onSurface, ), - "ul": Style( - margin: Margins.all(2), - padding: HtmlPaddings.all(2), - ), - "li": Style( - margin: Margins.all(0), - padding: HtmlPaddings.all(0), - ), - "p": Style( - margin: Margins.all(0), - padding: HtmlPaddings.all(0), - ) + "ul": Style(margin: Margins.all(2), padding: HtmlPaddings.all(2)), + "li": Style(margin: Margins.all(0), padding: HtmlPaddings.all(0)), + "p": Style(margin: Margins.all(0), padding: HtmlPaddings.all(0)), }, onLinkTap: (url, attributes, element) { LinkUtils.open(Uri.parse(url!), context: context); @@ -209,10 +213,12 @@ class _MatrixHtmlStateState extends State { } openLink(Uri uri) { - LinkUtils.open(uri, - clientId: widget.client.identifier, - context: context, - contextRoomId: widget.room?.identifier); + LinkUtils.open( + uri, + clientId: widget.client.identifier, + context: context, + contextRoomId: widget.room?.identifier, + ); } } @@ -254,15 +260,13 @@ class MatrixEmoticonHtmlExtension extends HtmlExtension { for (var char in context.node.text!.characters) { if (char.trim() == "") { - spans.add(TextSpan( - text: char, - )); + spans.add(TextSpan(text: char)); } else { - spans.add(WidgetSpan( - child: EmojiWidget( - UnicodeEmoticon(char), - height: emojiSize, - ))); + spans.add( + WidgetSpan( + child: EmojiWidget(UnicodeEmoticon(char), height: emojiSize), + ), + ); } } @@ -287,34 +291,42 @@ class MatrixEmoticonHtmlExtension extends HtmlExtension { if (room?.shouldPreviewMedia == false) { return WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Tooltip( - padding: const EdgeInsets.all(0), - decoration: const BoxDecoration( - color: Colors.transparent, + alignment: PlaceholderAlignment.middle, + child: Tooltip( + padding: const EdgeInsets.all(0), + decoration: const BoxDecoration(color: Colors.transparent), + richMessage: WidgetSpan( + child: EmojiWidget( + MatrixEmoticon( + uri, + client.matrixClient, + shortcode: context.attributes["alt"] ?? "", + packUsage: EmoticonUsage.all, + usage: EmoticonUsage.emoji, ), - richMessage: WidgetSpan( - child: EmojiWidget( - MatrixEmoticon(uri, client.matrixClient, - shortcode: context.attributes["alt"] ?? "", - packUsage: EmoticonUsage.all, - usage: EmoticonUsage.emoji), - height: 48, - )), - child: tiamat.Text.labelLow(context.attributes["alt"] ?? ""))); + height: 48, + ), + ), + child: tiamat.Text.labelLow(context.attributes["alt"] ?? ""), + ), + ); } return WidgetSpan( - child: Tooltip( - message: context.attributes["alt"] ?? "", - child: EmojiWidget( - MatrixEmoticon(uri, client.matrixClient, + child: Tooltip( + message: context.attributes["alt"] ?? "", + child: EmojiWidget( + MatrixEmoticon( + uri, + client.matrixClient, shortcode: context.attributes["alt"] ?? "", packUsage: EmoticonUsage.all, - usage: EmoticonUsage.emoji), - height: size, + usage: EmoticonUsage.emoji, + ), + height: size, + ), ), - )); + ); } @override @@ -353,10 +365,8 @@ class CodeBlockHtmlExtension extends HtmlExtension { var langauge = element?.className.replaceAll('language-', ''); var code = element!.text; return WidgetSpan( - child: ExpandableCodeBlock( - text: code, - language: langauge, - )); + child: ExpandableCodeBlock(text: code, language: langauge), + ); } static const Set tags = {"pre"}; @@ -368,20 +378,24 @@ class CodeBlockHtmlExtension extends HtmlExtension { class LineBreakHtmlExtension extends HtmlExtension { @override InlineSpan build(ExtensionContext context) { - var result = - context.parser.buildFromExtension(context, extensionsToIgnore: {this}); + var result = context.parser.buildFromExtension( + context, + extensionsToIgnore: {this}, + ); if (context.node is! dom.Element) { return result; } - return TextSpan(children: [ - if (context.element?.previousElementSibling != null) - const TextSpan(text: "\n"), - result, - if (context.element?.nextElementSibling != null) - const TextSpan(text: "\n"), - ]); + return TextSpan( + children: [ + if (context.element?.previousElementSibling != null) + const TextSpan(text: "\n"), + result, + if (context.element?.nextElementSibling != null) + const TextSpan(text: "\n"), + ], + ); } static const Set tags = {"p"}; @@ -393,17 +407,20 @@ class LineBreakHtmlExtension extends HtmlExtension { class CodeHtmlExtension extends HtmlExtension { @override InlineSpan build(ExtensionContext context) { - var color = Theme.of(context.buildContext!) + var color = + Theme.of(context.buildContext!) .extension() ?.codeHighlight ?? Theme.of(context.buildContext!).primaryColor; return TextSpan( - text: context.node.text, - style: TextStyle( - fontFamily: "Code", - color: color, - fontFeatures: const [FontFeature.disable("calt")])); + text: context.node.text, + style: TextStyle( + fontFamily: "Code", + color: color, + fontFeatures: const [FontFeature.disable("calt")], + ), + ); } static const Set tags = {"code"}; @@ -463,19 +480,24 @@ class LinkifyHtmlExtension extends HtmlExtension { placeholderColor: mentionedRoom?.defaultColor ?? MatrixPeer.hashColor(mxid), avatar: mentionedRoom?.avatar, - onTap: () => LinkUtils.open(href, - clientId: client.identifier, contextRoomId: room?.identifier), + onTap: () => LinkUtils.open( + href, + clientId: client.identifier, + contextRoomId: room?.identifier, + ), ); } if (overrideWidget != null) { return WidgetSpan( - child: Transform.translate( - offset: Offset(0, 2), - child: Padding( - padding: const EdgeInsets.fromLTRB(2, 0, 2, 0), - child: overrideWidget, - ))); + child: Transform.translate( + offset: Offset(0, 2), + child: Padding( + padding: const EdgeInsets.fromLTRB(2, 0, 2, 0), + child: overrideWidget, + ), + ), + ); } } } @@ -488,15 +510,21 @@ class LinkifyHtmlExtension extends HtmlExtension { destination = Uri(); } - return LinkSpan.create(context.node.text!, - clientId: client.identifier, - context: context.buildContext!, - destination: destination); + return LinkSpan.create( + context.node.text!, + clientId: client.identifier, + context: context.buildContext!, + destination: destination, + ); } return TextSpan( - children: TextUtils.linkifyString(context.node.text!, - clientId: client.identifier, context: context.buildContext!)); + children: TextUtils.linkifyString( + context.node.text!, + clientId: client.identifier, + context: context.buildContext!, + ), + ); } @override @@ -527,11 +555,13 @@ class SpoilerHtmlExtension extends HtmlExtension { var recogniser = TapGestureRecognizer(); recogniser.onTap = onTap; return TextSpan( - text: context.node.text, - recognizer: recogniser, - style: TextStyle( - color: color, - backgroundColor: hide == true ? color : color.withAlpha(20))); + text: context.node.text, + recognizer: recogniser, + style: TextStyle( + color: color, + backgroundColor: hide == true ? color : color.withAlpha(20), + ), + ); } @override @@ -554,7 +584,10 @@ class ColorHtmlExtension extends HtmlExtension { if (str != null) { color = ColorUtils.fromHexCode(str); } - return TextSpan(text: context.node.text, style: TextStyle(color: color)); + return TextSpan( + text: context.node.text, + style: TextStyle(color: color), + ); } @override @@ -574,23 +607,27 @@ class RoomMentionsHtmlExtension extends HtmlExtension { InlineSpan build(ExtensionContext context) { var data = (context.node as dom.Text).data; return TextSpan( - children: TextUtils.formatMatches( - MatrixRoom.roomMentionRegex.allMatches(data), - data, - builder: (matchedText, theme) { - return WidgetSpan( + children: TextUtils.formatMatches( + MatrixRoom.roomMentionRegex.allMatches(data), + data, + builder: (matchedText, theme) { + return WidgetSpan( child: Transform.translate( - offset: Offset(0, 2), - child: Padding( - padding: const EdgeInsets.fromLTRB(2, 0, 2, 0), - child: MentionWidget( - displayName: matchedText, - showAvatar: false, - placeholderColor: - ColorScheme.of(context.buildContext!).primary), - ))); - }, - )); + offset: Offset(0, 2), + child: Padding( + padding: const EdgeInsets.fromLTRB(2, 0, 2, 0), + child: MentionWidget( + displayName: matchedText, + showAvatar: false, + placeholderColor: ColorScheme.of(context.buildContext!) + .primary, + ), + ), + ), + ); + }, + ), + ); } @override @@ -611,8 +648,11 @@ class MatrixImageExtension extends HtmlExtension { final MatrixClient client; final Room? room; - const MatrixImageExtension(this.client, this.room, - {this.defaultDimension = 64}); + const MatrixImageExtension( + this.client, + this.room, { + this.defaultDimension = 64, + }); @override Set get supportedTags => {'img'}; @@ -626,10 +666,12 @@ class MatrixImageExtension extends HtmlExtension { } if (mxcUrl.scheme != 'mxc' || room?.shouldPreviewMedia == false) { - return LinkSpan.create(mxcUrl.toString(), - clientId: client.identifier, - destination: mxcUrl, - context: context.buildContext!); + return LinkSpan.create( + mxcUrl.toString(), + clientId: client.identifier, + destination: mxcUrl, + context: context.buildContext!, + ); } final width = double.tryParse(context.attributes['width'] ?? ''); @@ -637,14 +679,10 @@ class MatrixImageExtension extends HtmlExtension { return WidgetSpan( child: SizedBox( - width: width ?? height ?? defaultDimension, - height: height ?? width ?? defaultDimension, - child: Image( - image: MatrixMxcImage( - mxcUrl, - client.matrixClient, - ), - )), + width: width ?? height ?? defaultDimension, + height: height ?? width ?? defaultDimension, + child: Image(image: MatrixMxcImage(mxcUrl, client.matrixClient)), + ), ); } } diff --git a/commet/lib/ui/atoms/rich_text/spans/link.dart b/commet/lib/ui/atoms/rich_text/spans/link.dart index 7e8a76c87..6c5ed5534 100644 --- a/commet/lib/ui/atoms/rich_text/spans/link.dart +++ b/commet/lib/ui/atoms/rich_text/spans/link.dart @@ -4,23 +4,29 @@ import 'package:flutter/material.dart'; import 'package:tiamat/config/style/theme_extensions.dart'; class LinkSpan { - static InlineSpan create(String text, - {required BuildContext context, - required String clientId, - destination, - TextStyle? style}) { - var color = Theme.of(context).extension()?.linkColor ?? + static InlineSpan create( + String text, { + required BuildContext context, + required String clientId, + destination, + TextStyle? style, + }) { + var color = + Theme.of(context).extension()?.linkColor ?? Theme.of(context).colorScheme.primary; return TextSpan( - text: text, - style: (style ?? const TextStyle()) - .copyWith(color: color, decorationColor: color), - recognizer: TapGestureRecognizer() - ..onTap = () { - if (destination != null) { - LinkUtils.open(destination, clientId: clientId, context: context); - } - }); + text: text, + style: (style ?? const TextStyle()).copyWith( + color: color, + decorationColor: color, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + if (destination != null) { + LinkUtils.open(destination, clientId: clientId, context: context); + } + }, + ); } } diff --git a/commet/lib/ui/atoms/rich_text_field.dart b/commet/lib/ui/atoms/rich_text_field.dart index 55632c5b9..b380f06a7 100644 --- a/commet/lib/ui/atoms/rich_text_field.dart +++ b/commet/lib/ui/atoms/rich_text_field.dart @@ -24,10 +24,11 @@ class RichTextEditingController extends TextEditingController { final Client? client; @override - TextSpan buildTextSpan( - {required BuildContext context, - TextStyle? style, - required bool withComposing}) { + TextSpan buildTextSpan({ + required BuildContext context, + TextStyle? style, + required bool withComposing, + }) { return build(text, context); } @@ -35,18 +36,24 @@ class RichTextEditingController extends TextEditingController { var roomEmoticons = room?.getComponent(); var clientEmoticons = client?.getComponent(); var doc = md.Document( - encodeHtml: false, - extensionSet: md.ExtensionSet.gitHubFlavored, - inlineSyntaxes: [ - mx_markdown.PillSyntax(), - mx_markdown.SpoilerSyntax(), - if (roomEmoticons != null) - mx_markdown.EmoteSyntax(() => roomEmoticons - .getEmotePacksFlat(matrix.ImagePackUsage.emoticon)), - if (roomEmoticons == null && clientEmoticons != null) - mx_markdown.EmoteSyntax(() => clientEmoticons - .getEmotePacksFlat(matrix.ImagePackUsage.emoticon)) - ]); + encodeHtml: false, + extensionSet: md.ExtensionSet.gitHubFlavored, + inlineSyntaxes: [ + mx_markdown.PillSyntax(), + mx_markdown.SpoilerSyntax(), + if (roomEmoticons != null) + mx_markdown.EmoteSyntax( + () => + roomEmoticons.getEmotePacksFlat(matrix.ImagePackUsage.emoticon), + ), + if (roomEmoticons == null && clientEmoticons != null) + mx_markdown.EmoteSyntax( + () => clientEmoticons.getEmotePacksFlat( + matrix.ImagePackUsage.emoticon, + ), + ), + ], + ); List? parsed; try { @@ -61,8 +68,14 @@ class RichTextEditingController extends TextEditingController { int currentIndex = 0; for (var element in parsed) { - currentIndex = - handleNode(context, currentIndex, text, children, style, element); + currentIndex = handleNode( + context, + currentIndex, + text, + children, + style, + element, + ); } if (currentIndex <= text.length - 1) { @@ -72,9 +85,16 @@ class RichTextEditingController extends TextEditingController { return TextSpan(children: children); } - int handleNode(BuildContext context, int currentIndex, String text, - List children, TextStyle style, md.Node node, - {Widget? overrideWidget, double overrideVerticalOffset = 2.5}) { + int handleNode( + BuildContext context, + int currentIndex, + String text, + List children, + TextStyle style, + md.Node node, { + Widget? overrideWidget, + double overrideVerticalOffset = 2.5, + }) { var originalStyle = style.copyWith(); if (node is md.Text) { @@ -89,8 +109,9 @@ class RichTextEditingController extends TextEditingController { if (index != 0) { var sub = substr.substring(0, index); - children.add(TextSpan( - text: sub, style: Theme.of(context).textTheme.bodyMedium!)); + children.add( + TextSpan(text: sub, style: Theme.of(context).textTheme.bodyMedium!), + ); currentIndex += sub.length; } @@ -100,27 +121,22 @@ class RichTextEditingController extends TextEditingController { // cursor renders in the correct place. // This is a hacky way to acheive that var widgetChildren = List.generate( - nodeText.length, - (i) => WidgetSpan( - child: Container( - child: i == 0 - ? Transform.translate( - offset: Offset(0, overrideVerticalOffset), - child: overrideWidget) - : SizedBox( - width: 0, - height: 0, - )))); + nodeText.length, + (i) => WidgetSpan( + child: Container( + child: i == 0 + ? Transform.translate( + offset: Offset(0, overrideVerticalOffset), + child: overrideWidget, + ) + : SizedBox(width: 0, height: 0), + ), + ), + ); - children.add(TextSpan( - children: widgetChildren, - style: originalStyle, - )); + children.add(TextSpan(children: widgetChildren, style: originalStyle)); } else { - children.add(TextSpan( - text: nodeText, - style: originalStyle, - )); + children.add(TextSpan(text: nodeText, style: originalStyle)); } currentIndex += nodeText.length; @@ -136,23 +152,26 @@ class RichTextEditingController extends TextEditingController { break; case "span": if (node.attributes.containsKey("data-mx-spoiler")) - style = - style.copyWith(backgroundColor: style.color?.withAlpha(200)); + style = style.copyWith( + backgroundColor: style.color?.withAlpha(200), + ); break; case "code": var color = Theme.of(context).extension()?.codeHighlight ?? - Theme.of(context).colorScheme.primary; + Theme.of(context).colorScheme.primary; style = style.copyWith( - color: color, - fontFamily: "code", - fontFeatures: const [FontFeature.disable("calt")]); + color: color, + fontFamily: "code", + fontFeatures: const [FontFeature.disable("calt")], + ); break; case "pre": style = style.copyWith( - color: Theme.of(context).colorScheme.surfaceContainerHighest, - fontFamily: "code", - fontFeatures: const [FontFeature.disable("calt")]); + color: Theme.of(context).colorScheme.surfaceContainerHighest, + fontFamily: "code", + fontFeatures: const [FontFeature.disable("calt")], + ); break; case "img": if (client case MatrixClient mx) { @@ -161,17 +180,28 @@ class RichTextEditingController extends TextEditingController { var uri = Uri.parse(src); var size = 24.0; currentIndex = handleNode( - context, currentIndex, text, children, style, md.Text(content!), - overrideVerticalOffset: 5, - overrideWidget: SizedBox( - height: size, - width: size, - child: EmojiWidget( - height: size, - MatrixEmoticon(uri, mx.matrixClient, - shortcode: content, - packUsage: EmoticonUsage.all, - usage: EmoticonUsage.emoji)))); + context, + currentIndex, + text, + children, + style, + md.Text(content!), + overrideVerticalOffset: 5, + overrideWidget: SizedBox( + height: size, + width: size, + child: EmojiWidget( + height: size, + MatrixEmoticon( + uri, + mx.matrixClient, + shortcode: content, + packUsage: EmoticonUsage.all, + usage: EmoticonUsage.emoji, + ), + ), + ), + ); return currentIndex; } case "a": @@ -187,33 +217,48 @@ class RichTextEditingController extends TextEditingController { var user = room?.getMember(mxId); if (user != null) { currentIndex = handleNode( - context, currentIndex, text, children, style, element, - overrideWidget: MentionWidget( - displayName: user.displayName, - avatar: user.avatar, - style: style, - placeholderColor: user.defaultColor)); + context, + currentIndex, + text, + children, + style, + element, + overrideWidget: MentionWidget( + displayName: user.displayName, + avatar: user.avatar, + style: style, + placeholderColor: user.defaultColor, + ), + ); return currentIndex; } } else if (result.$1 == MatrixLinkType.room) { var taggedRoom = client?.getRoom(mxId); - var vias = - (client as MatrixClient).parseAddressToIdAndVia(href); + var vias = (client as MatrixClient).parseAddressToIdAndVia( + href, + ); if (taggedRoom != null) { currentIndex = handleNode( - context, currentIndex, text, children, style, element, - overrideWidget: MentionWidget( - fallbackIcon: - preferences.usePlaceholderRoomAvatars.value - ? null - : taggedRoom.icon, - displayName: taggedRoom.displayName, - avatar: taggedRoom.avatar, - vias: vias?.$2, - style: style, - placeholderColor: taggedRoom.defaultColor)); + context, + currentIndex, + text, + children, + style, + element, + overrideWidget: MentionWidget( + fallbackIcon: + preferences.usePlaceholderRoomAvatars.value + ? null + : taggedRoom.icon, + displayName: taggedRoom.displayName, + avatar: taggedRoom.avatar, + vias: vias?.$2, + style: style, + placeholderColor: taggedRoom.defaultColor, + ), + ); return currentIndex; } } @@ -228,30 +273,44 @@ class RichTextEditingController extends TextEditingController { style = style.copyWith(fontSize: 14 * 2, fontWeight: FontWeight.bold); break; case "h2": - style = - style.copyWith(fontSize: 14 * 1.5, fontWeight: FontWeight.bold); + style = style.copyWith( + fontSize: 14 * 1.5, + fontWeight: FontWeight.bold, + ); break; case "h3": - style = - style.copyWith(fontSize: 14 * 1.17, fontWeight: FontWeight.bold); + style = style.copyWith( + fontSize: 14 * 1.17, + fontWeight: FontWeight.bold, + ); break; case "h4": style = style.copyWith(fontSize: 14 * 1, fontWeight: FontWeight.bold); break; case "h5": - style = - style.copyWith(fontSize: 14 * 0.83, fontWeight: FontWeight.bold); + style = style.copyWith( + fontSize: 14 * 0.83, + fontWeight: FontWeight.bold, + ); break; case "h6": - style = - style.copyWith(fontSize: 14 * 0.67, fontWeight: FontWeight.bold); + style = style.copyWith( + fontSize: 14 * 0.67, + fontWeight: FontWeight.bold, + ); break; } if (node.children != null) { for (var element in node.children!) { - currentIndex = - handleNode(context, currentIndex, text, children, style, element); + currentIndex = handleNode( + context, + currentIndex, + text, + children, + style, + element, + ); } } } diff --git a/commet/lib/ui/atoms/role_view.dart b/commet/lib/ui/atoms/role_view.dart index fbbc3cd87..649b588ce 100644 --- a/commet/lib/ui/atoms/role_view.dart +++ b/commet/lib/ui/atoms/role_view.dart @@ -24,20 +24,13 @@ class RoleView extends StatelessWidget { child: Row( mainAxisSize: MainAxisSize.min, children: [ - if (icon != null) - Icon( - icon!, - color: fg, - ), + if (icon != null) Icon(icon!, color: fg), Padding( padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), child: tiamat.Text.labelEmphasised(name), ), if (powerLevel != null) - tiamat.Text.tiny( - '${powerLevel!}', - color: fg, - ) + tiamat.Text.tiny('${powerLevel!}', color: fg), ], ), ), diff --git a/commet/lib/ui/atoms/room_created.dart b/commet/lib/ui/atoms/room_created.dart index 0eb0c2858..fe720ddb4 100644 --- a/commet/lib/ui/atoms/room_created.dart +++ b/commet/lib/ui/atoms/room_created.dart @@ -1,6 +1,7 @@ import 'package:flutter/widgets.dart'; import 'package:tiamat/tiamat.dart'; import 'package:tiamat/tiamat.dart' as tiamat; + import '../../client/room.dart'; class RoomCreated extends StatelessWidget { @@ -27,16 +28,14 @@ class RoomCreated extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - tiamat.Text.largeTitle( - "Welcome to ${room.displayName}!", - ), + tiamat.Text.largeTitle("Welcome to ${room.displayName}!"), const tiamat.Text.labelEmphasised( "This is the beginning of the end...", ), ], ), ), - ) + ), ], ), ); diff --git a/commet/lib/ui/atoms/room_header.dart b/commet/lib/ui/atoms/room_header.dart index 59858796a..df06bb128 100644 --- a/commet/lib/ui/atoms/room_header.dart +++ b/commet/lib/ui/atoms/room_header.dart @@ -14,8 +14,13 @@ import 'package:tiamat/tiamat.dart' as tiamat; import '../../client/client.dart'; class RoomHeader extends StatefulWidget { - const RoomHeader(this.room, - {super.key, this.onTap, this.onBurgerMenuTap, this.menu}); + const RoomHeader( + this.room, { + super.key, + this.onTap, + this.onBurgerMenuTap, + this.menu, + }); final Room room; final Widget? menu; final Function()? onTap; @@ -90,7 +95,8 @@ class _RoomHeaderState extends State { bool showRoomIcons = preferences.showRoomAvatars.value; bool useGenericIcons = preferences.usePlaceholderRoomAvatars.value; - bool shouldShowDefaultIcon = (!showRoomIcons && !useGenericIcons) || + bool shouldShowDefaultIcon = + (!showRoomIcons && !useGenericIcons) || (showRoomIcons && !useGenericIcons && widget.room.avatar == null); IconData defaultIcon = widget.room.icon; @@ -100,13 +106,7 @@ class _RoomHeaderState extends State { if (shouldShowDefaultIcon) { iconPadding = EdgeInsets.fromLTRB(0, 0, 4, 0); - iconWidget = Opacity( - opacity: 0.5, - child: m.Icon( - defaultIcon, - size: 20, - ), - ); + iconWidget = Opacity(opacity: 0.5, child: m.Icon(defaultIcon, size: 20)); } else { iconPadding = EdgeInsets.fromLTRB(4, 0, 8, 0); iconWidget = tiamat.Avatar( @@ -116,26 +116,27 @@ class _RoomHeaderState extends State { : null, placeholderText: (showRoomIcons && useGenericIcons && widget.room.avatar == null) || - (!showRoomIcons && useGenericIcons) - ? widget.room.displayName - : "", + (!showRoomIcons && useGenericIcons) + ? widget.room.displayName + : "", placeholderColor: (showRoomIcons && useGenericIcons && widget.room.avatar == null) || - (!showRoomIcons && useGenericIcons) - ? widget.room.defaultColor - : m.Colors.grey, + (!showRoomIcons && useGenericIcons) + ? widget.room.defaultColor + : m.Colors.grey, ); } return HeaderView( - showBurger: MediaQuery.of(context).mobile, - iconWidget: iconWidget, - text: widget.room.displayName, - iconPadding: iconPadding, - topic: widget.room.topic, - onTap: widget.onTap, - onBurgerMenuTap: widget.onBurgerMenuTap, - menu: widget.menu, - status: status); + showBurger: MediaQuery.of(context).mobile, + iconWidget: iconWidget, + text: widget.room.displayName, + iconPadding: iconPadding, + topic: widget.room.topic, + onTap: widget.onTap, + onBurgerMenuTap: widget.onBurgerMenuTap, + menu: widget.menu, + status: status, + ); } } @@ -180,13 +181,15 @@ class HeaderView extends StatelessWidget { children: [ if (showBurger) Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 4, 0), - child: HeaderBurger( - onTap: onBurgerMenuTap, - highlightColor: m.Colors.red.shade600, - notificationColor: - m.Theme.of(context).colorScheme.onSurface, - )), + padding: const EdgeInsets.fromLTRB(0, 0, 4, 0), + child: HeaderBurger( + onTap: onBurgerMenuTap, + highlightColor: m.Colors.red.shade600, + notificationColor: m.Theme.of(context) + .colorScheme + .onSurface, + ), + ), if (iconWidget != null) Padding( padding: iconPadding ?? EdgeInsets.zero, @@ -197,7 +200,9 @@ class HeaderView extends StatelessWidget { iconWidget!, if (status != null) UserPanelView.createPresenceIcon( - context, status!), + context, + status!, + ), ], ), ), @@ -210,13 +215,12 @@ class HeaderView extends StatelessWidget { children: [ m.Text( text, - style: m.Theme.of(context) - .textTheme - .titleSmall! + style: m.Theme.of(context).textTheme.titleSmall! .copyWith( - color: m.TextTheme.of(context) - .bodyMedium! - .color), + color: m.TextTheme.of(context) + .bodyMedium! + .color, + ), maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -232,15 +236,15 @@ class HeaderView extends StatelessWidget { maxLines: 1, overflow: TextOverflow.ellipsis, ), - ) + ), ], ), ), - ) + ), ], ), ), - if (menu != null) menu! + if (menu != null) menu!, ], ), ), @@ -250,11 +254,12 @@ class HeaderView extends StatelessWidget { } class HeaderBurger extends StatefulWidget { - const HeaderBurger( - {required this.highlightColor, - required this.notificationColor, - this.onTap, - super.key}); + const HeaderBurger({ + required this.highlightColor, + required this.notificationColor, + this.onTap, + super.key, + }); final Function()? onTap; final Color highlightColor; final Color notificationColor; @@ -275,8 +280,9 @@ class _HeaderBurgerState extends State { super.initState(); color = widget.notificationColor; subs = [ - clientManager!.directMessages.highlightedRoomsList.onListUpdated - .listen((_) => updateState()), + clientManager!.directMessages.highlightedRoomsList.onListUpdated.listen( + (_) => updateState(), + ), clientManager!.onSpaceUpdated.stream.listen((_) => updateState()), ]; @@ -327,12 +333,13 @@ class _HeaderBurgerState extends State { onPressed: widget.onTap, ), AnimatedScale( - scale: highlightedNotificationCount + notificationCount > 0 - ? 1.0 - : 0.0, - duration: m.Durations.medium4, - curve: Curves.easeOutCubic, - child: createNotificationIcon(context)), + scale: highlightedNotificationCount + notificationCount > 0 + ? 1.0 + : 0.0, + duration: m.Durations.medium4, + curve: Curves.easeOutCubic, + child: createNotificationIcon(context), + ), ], ), ); @@ -348,14 +355,12 @@ class _HeaderBurgerState extends State { color: color, shape: BoxShape.circle, border: Border.all( - width: 3, - strokeAlign: BorderSide.strokeAlignOutside, - color: backgroundColor), - ), - child: SizedBox( - width: 8, - height: 8, + width: 3, + strokeAlign: BorderSide.strokeAlignOutside, + color: backgroundColor, + ), ), + child: SizedBox(width: 8, height: 8), ); } } diff --git a/commet/lib/ui/atoms/room_panel.dart b/commet/lib/ui/atoms/room_panel.dart index bbf36ab14..a2361473d 100644 --- a/commet/lib/ui/atoms/room_panel.dart +++ b/commet/lib/ui/atoms/room_panel.dart @@ -12,8 +12,12 @@ import 'package:commet/utils/event_bus.dart'; import 'package:flutter/material.dart'; class RoomPanel extends StatefulWidget { - const RoomPanel(this.room, - {this.onTap, super.key, this.shouldShowAvatarForRoom}); + const RoomPanel( + this.room, { + this.onTap, + super.key, + this.shouldShowAvatarForRoom, + }); final Room room; final Function()? onTap; @@ -41,18 +45,20 @@ class _RoomPanelState extends State { var typing = widget.room.getComponent(); if (typing != null) { - subs.add(typing.onTypingUsersUpdated.listen((_) { - setState(() { - typingUsers = typing.typingUsers; - }); - })); + subs.add( + typing.onTypingUsersUpdated.listen((_) { + setState(() { + typingUsers = typing.typingUsers; + }); + }), + ); typingUsers = typing.typingUsers; } if (directMessagePartner != null) { - final presenceComponent = - widget.room.client.getComponent(); + final presenceComponent = widget.room.client + .getComponent(); if (presenceComponent == null) { return; @@ -60,13 +66,17 @@ class _RoomPanelState extends State { presenceComponent .getUserPresence(directMessagePartner!) - .then((s) => setState(() { - presence = s; - })); - - subs.add(presenceComponent.onPresenceChanged - .where((tuple) => tuple.$1 == directMessagePartner) - .listen(userPresenceChanged)); + .then( + (s) => setState(() { + presence = s; + }), + ); + + subs.add( + presenceComponent.onPresenceChanged + .where((tuple) => tuple.$1 == directMessagePartner) + .listen(userPresenceChanged), + ); } super.initState(); @@ -103,10 +113,13 @@ class _RoomPanelState extends State { child: RoomPanelView( displayName: widget.room.displayName, avatar: widget.room.avatar, - onTap: widget.onTap ?? + onTap: + widget.onTap ?? () { - EventBus.doOpenRoom(widget.room.identifier, - clientId: widget.room.client.identifier); + EventBus.doOpenRoom( + widget.room.identifier, + clientId: widget.room.client.identifier, + ); }, color: widget.room.defaultColor, showUserAvatar: widget.shouldShowAvatarForRoom == null diff --git a/commet/lib/ui/atoms/room_panel_view.dart b/commet/lib/ui/atoms/room_panel_view.dart index 4712b84ac..1938fd015 100644 --- a/commet/lib/ui/atoms/room_panel_view.dart +++ b/commet/lib/ui/atoms/room_panel_view.dart @@ -12,30 +12,31 @@ import 'package:tiamat/tiamat.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class RoomPanelView extends StatefulWidget { - const RoomPanelView( - {required this.displayName, - this.avatar, - this.onPrimaryButtonPressed, - this.primaryButtonLabel, - this.onSecondaryButtonPressed, - this.secondaryButtonLabel, - this.userColor, - this.onTap, - this.color, - this.body, - this.recentEventSender, - this.recentEventSenderColor, - this.userAvatar, - this.loading = false, - this.directMessagePartner, - this.random = 1, - this.userDisplayName, - this.userPresence, - this.showUserAvatar = false, - this.notificationCount = 0, - this.highlightNotificationCount = 0, - this.typingMembers, - super.key}); + const RoomPanelView({ + required this.displayName, + this.avatar, + this.onPrimaryButtonPressed, + this.primaryButtonLabel, + this.onSecondaryButtonPressed, + this.secondaryButtonLabel, + this.userColor, + this.onTap, + this.color, + this.body, + this.recentEventSender, + this.recentEventSenderColor, + this.userAvatar, + this.loading = false, + this.directMessagePartner, + this.random = 1, + this.userDisplayName, + this.userPresence, + this.showUserAvatar = false, + this.notificationCount = 0, + this.highlightNotificationCount = 0, + this.typingMembers, + super.key, + }); final ImageProvider? avatar; final ImageProvider? userAvatar; final Color? userColor; @@ -111,8 +112,9 @@ class _RoomPanelViewState extends State { child: InkWell( onTap: widget.onTap, child: Container( - decoration: - BoxDecoration(borderRadius: BorderRadius.circular(15)), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + ), child: Padding( padding: const EdgeInsets.all(2.0), child: Column( @@ -162,8 +164,12 @@ class _RoomPanelViewState extends State { ), Flexible( child: Padding( - padding: - const EdgeInsets.fromLTRB(4, 0, 8, 0), + padding: const EdgeInsets.fromLTRB( + 4, + 0, + 8, + 0, + ), child: Column( mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.min, @@ -175,14 +181,19 @@ class _RoomPanelViewState extends State { isLoading: shimmer, child: Padding( padding: const EdgeInsets.fromLTRB( - 0, 4, 0, 0), + 0, + 4, + 0, + 0, + ), child: Container( height: 16, width: (widget.random * 80) + 20, decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(4), - color: shimmerColor), + borderRadius: + BorderRadius.circular(4), + color: shimmerColor, + ), ), ), ), @@ -191,14 +202,19 @@ class _RoomPanelViewState extends State { isLoading: shimmer, child: Padding( padding: const EdgeInsets.fromLTRB( - 0, 4, 0, 0), + 0, + 4, + 0, + 0, + ), child: Container( height: 12, width: (widget.random * 200) + 20, decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(4), - color: shimmerColor), + borderRadius: + BorderRadius.circular(4), + color: shimmerColor, + ), ), ), ), @@ -210,7 +226,9 @@ class _RoomPanelViewState extends State { ), if (widget.body != null) SizedBox( - height: 16, child: recentEvent()), + height: 16, + child: recentEvent(), + ), ], ), ), @@ -228,7 +246,8 @@ class _RoomPanelViewState extends State { Padding( padding: const EdgeInsets.all(4.0), child: NotificationBadge( - widget.highlightNotificationCount), + widget.highlightNotificationCount, + ), ), if (showAnyButton) actionButtons(), ], @@ -243,11 +262,7 @@ class _RoomPanelViewState extends State { ); } - late List blobKeys = [ - GlobalKey(), - GlobalKey(), - GlobalKey(), - ]; + late List blobKeys = [GlobalKey(), GlobalKey(), GlobalKey()]; Timer? timer; @@ -288,8 +303,9 @@ class _RoomPanelViewState extends State { backgroundColor = Colors.transparent; } - var duration = - expanded ? Duration(seconds: 1) : Duration(milliseconds: 300); + var duration = expanded + ? Duration(seconds: 1) + : Duration(milliseconds: 300); var curve = expanded ? Curves.elasticOut : Curves.easeInOutCubic; var offset = expanded ? 7.0 : 0.0; @@ -299,41 +315,46 @@ class _RoomPanelViewState extends State { curve: curve, width: (expanded ? 23 : 10) + rightPad, decoration: BoxDecoration( - color: backgroundColor, borderRadius: BorderRadius.circular(5)), + color: backgroundColor, + borderRadius: BorderRadius.circular(5), + ), height: 12, child: Stack( alignment: AlignmentGeometry.center, children: [ AnimatedPositioned( - duration: duration, - right: rightPad, - curve: curve, - child: SingleTypingIndicatorBlob( - key: blobKeys[0], - border: border, - color: color, - playing: expanded, - )), + duration: duration, + right: rightPad, + curve: curve, + child: SingleTypingIndicatorBlob( + key: blobKeys[0], + border: border, + color: color, + playing: expanded, + ), + ), AnimatedPositioned( - duration: duration, - right: rightPad + offset, - curve: curve, - child: SingleTypingIndicatorBlob( - key: blobKeys[1], - border: border, - color: color, - playing: expanded, - )), + duration: duration, + right: rightPad + offset, + curve: curve, + child: SingleTypingIndicatorBlob( + key: blobKeys[1], + border: border, + color: color, + playing: expanded, + ), + ), AnimatedPositioned( - duration: duration, - right: rightPad + (offset * 2), - curve: curve, - child: SingleTypingIndicatorBlob( - key: blobKeys[2], - border: border, - color: color, - playing: expanded, - )), + duration: duration, + right: rightPad + (offset * 2), + curve: curve, + child: SingleTypingIndicatorBlob( + key: blobKeys[2], + border: border, + color: color, + playing: expanded, + ), + ), ], ), ); @@ -344,29 +365,28 @@ class _RoomPanelViewState extends State { ? tiamat.Text.adjustColor(context, widget.recentEventSenderColor!) : null; - var style = TextTheme.of(context) - .labelMedium + var style = TextTheme.of(context).labelMedium ?.copyWith(fontSize: 12, letterSpacing: 0); return SizedBox( child: RichText( - maxLines: 1, - overflow: TextOverflow.ellipsis, - text: TextSpan(children: [ + maxLines: 1, + overflow: TextOverflow.ellipsis, + text: TextSpan( + children: [ if (widget.recentEventSender != null) TextSpan( text: widget.recentEventSender! + ":", style: style?.copyWith(color: color), ), if (widget.recentEventSender != null) - WidgetSpan( - child: SizedBox( - width: 4, - )), + WidgetSpan(child: SizedBox(width: 4)), TextSpan( - text: widget.body, - style: - style?.copyWith(color: ColorScheme.of(context).secondary)) - ])), + text: widget.body, + style: style?.copyWith(color: ColorScheme.of(context).secondary), + ), + ], + ), + ), ); } diff --git a/commet/lib/ui/atoms/room_preview.dart b/commet/lib/ui/atoms/room_preview.dart index dd4aed4e0..5950a32ea 100644 --- a/commet/lib/ui/atoms/room_preview.dart +++ b/commet/lib/ui/atoms/room_preview.dart @@ -33,35 +33,31 @@ class RoomPreviewView extends StatelessWidget { children: [ if (previewData.type != null) tiamat.Tooltip( - text: previewData.type!.string, - child: Icon(size: 15, previewData.type!.icon)), + text: previewData.type!.string, + child: Icon(size: 15, previewData.type!.icon), + ), if (previewData.numMembers != null) Row( children: [ Icon(size: 15, Icons.people), - tiamat.Text.labelLow("${previewData.numMembers}") + tiamat.Text.labelLow("${previewData.numMembers}"), ], ), - Icon( - size: 15, - switch (previewData.visibility) { - null => Icons.lock, - final RoomVisibilityPublic _ => Icons.public, - final RoomVisibilityPrivate _ => Icons.lock, - final RoomVisibilityRestricted _ => Icons.shield, - _ => Icons.question_mark, - }) + Icon(size: 15, switch (previewData.visibility) { + null => Icons.lock, + final RoomVisibilityPublic _ => Icons.public, + final RoomVisibilityPrivate _ => Icons.lock, + final RoomVisibilityRestricted _ => Icons.shield, + _ => Icons.question_mark, + }), ], ), if (previewData.topic != null) - Flexible( - child: tiamat.Text.labelLow( - previewData.topic!, - )) + Flexible(child: tiamat.Text.labelLow(previewData.topic!)), ], ), ), - ) + ), ], ); } diff --git a/commet/lib/ui/atoms/room_preview_text_button.dart b/commet/lib/ui/atoms/room_preview_text_button.dart index 23e4a1232..7e63d96ea 100644 --- a/commet/lib/ui/atoms/room_preview_text_button.dart +++ b/commet/lib/ui/atoms/room_preview_text_button.dart @@ -7,11 +7,7 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class RoomPreviewTextButton extends StatefulWidget { - const RoomPreviewTextButton( - this.room, { - this.onTap, - super.key, - }); + const RoomPreviewTextButton(this.room, {this.onTap, super.key}); final RoomPreview room; final Function(RoomPreview roomPreview)? onTap; @@ -38,18 +34,19 @@ class _RoomPreviewTextButtonState extends State { Color? avatarPlaceholderColor = (showRoomIcons && useGenericIcons && widget.room.avatar == null) || - (!showRoomIcons && useGenericIcons) - ? widget.room.color - : null; + (!showRoomIcons && useGenericIcons) + ? widget.room.color + : null; String? avatarPlaceholderText = (showRoomIcons && useGenericIcons && widget.room.avatar == null) || - (!showRoomIcons && useGenericIcons) - ? widget.room.displayName - : null; + (!showRoomIcons && useGenericIcons) + ? widget.room.displayName + : null; - bool startsWithEmoji = - TextUtils.isEmoji(widget.room.displayName.characters.first); + bool startsWithEmoji = TextUtils.isEmoji( + widget.room.displayName.characters.first, + ); if (startsWithEmoji && widget.room.avatar == null) { var emoji = displayName.characters.first; @@ -62,24 +59,27 @@ class _RoomPreviewTextButtonState extends State { IconData? icon = widget.room.type?.icon; Widget result = SizedBox( - height: customBuilder == null ? height : null, - child: tiamat.TextButton( - displayName, - customBuilder: customBuilder, - icon: icon, - avatar: showRoomIcons && widget.room.avatar != null - ? widget.room.avatar - : null, - avatarRadius: 12, - avatarPlaceholderColor: avatarPlaceholderColor, - avatarPlaceholderText: avatarPlaceholderText, - iconColor: color, - textColor: color, - softwrap: false, - onTap: () => widget.onTap?.call(widget.room), - footer: tiamat.Text.labelLow(CommonStrings.promptJoin, - color: Theme.of(context).colorScheme.primary), - )); + height: customBuilder == null ? height : null, + child: tiamat.TextButton( + displayName, + customBuilder: customBuilder, + icon: icon, + avatar: showRoomIcons && widget.room.avatar != null + ? widget.room.avatar + : null, + avatarRadius: 12, + avatarPlaceholderColor: avatarPlaceholderColor, + avatarPlaceholderText: avatarPlaceholderText, + iconColor: color, + textColor: color, + softwrap: false, + onTap: () => widget.onTap?.call(widget.room), + footer: tiamat.Text.labelLow( + CommonStrings.promptJoin, + color: Theme.of(context).colorScheme.primary, + ), + ), + ); return result; } diff --git a/commet/lib/ui/atoms/room_text_button.dart b/commet/lib/ui/atoms/room_text_button.dart index da6170301..521619a2a 100644 --- a/commet/lib/ui/atoms/room_text_button.dart +++ b/commet/lib/ui/atoms/room_text_button.dart @@ -36,29 +36,38 @@ class RoomTextButton extends StatefulWidget { State createState() => _RoomTextButtonState(); static List createRoomContextMenuItems( - BuildContext context, Room room) { + BuildContext context, + Room room, + ) { var voipRoom = room.getComponent(); return [ ContextMenuItem( - text: "Mark as Read", - icon: Icons.visibility, - onPressed: () => room.markAsRead()), + text: "Mark as Read", + icon: Icons.visibility, + onPressed: () => room.markAsRead(), + ), if (!room.isFavorite) ContextMenuItem( - text: "Set as Favorite", - icon: Icons.favorite, - onPressed: () => room.setAsFavorite(true)), + text: "Set as Favorite", + icon: Icons.favorite, + onPressed: () => room.setAsFavorite(true), + ), if (room.isFavorite) ContextMenuItem( - text: "Unfavorite", - icon: Icons.heart_broken_outlined, - onPressed: () => room.setAsFavorite(false)), + text: "Unfavorite", + icon: Icons.heart_broken_outlined, + onPressed: () => room.setAsFavorite(false), + ), if (room.isSpecialRoomType) ContextMenuItem( - text: "Open as Text Chat", - icon: Icons.tag, - onPressed: () => EventBus.doOpenRoom(room.identifier, - clientId: room.client.identifier, bypassSpecialRoomType: true)), + text: "Open as Text Chat", + icon: Icons.tag, + onPressed: () => EventBus.doOpenRoom( + room.identifier, + clientId: room.client.identifier, + bypassSpecialRoomType: true, + ), + ), if (voipRoom != null && preferences.developerMode.value) ContextMenuItem( text: "Clear Membership Status", @@ -66,15 +75,12 @@ class RoomTextButton extends StatefulWidget { onPressed: () => voipRoom.clearAllCallMembershipStatus(), ), ContextMenuItem( - text: "Settings", - icon: Icons.settings, - onPressed: () { - NavigationUtils.navigateTo( - context, - RoomSettingsPage( - room: room, - )); - }), + text: "Settings", + icon: Icons.settings, + onPressed: () { + NavigationUtils.navigateTo(context, RoomSettingsPage(room: room)); + }, + ), ]; } } @@ -132,7 +138,8 @@ class _RoomTextButtonState extends State { void sortActivities() { activitySessions?.sort( - (a, b) => (a.thirdparty ? 1 : 0).compareTo(b.thirdparty ? 1 : 0)); + (a, b) => (a.thirdparty ? 1 : 0).compareTo(b.thirdparty ? 1 : 0), + ); } @override @@ -173,25 +180,27 @@ class _RoomTextButtonState extends State { bool showRoomIcons = preferences.showRoomAvatars.value; bool useGenericIcons = preferences.usePlaceholderRoomAvatars.value; - bool shouldShowDefaultIcon = (!showRoomIcons && !useGenericIcons) || + bool shouldShowDefaultIcon = + (!showRoomIcons && !useGenericIcons) || (showRoomIcons && !useGenericIcons && widget.room.avatar == null); String displayName = widget.room.displayName; Color? avatarPlaceholderColor = (showRoomIcons && useGenericIcons && widget.room.avatar == null) || - (!showRoomIcons && useGenericIcons) - ? widget.room.defaultColor - : null; + (!showRoomIcons && useGenericIcons) + ? widget.room.defaultColor + : null; String? avatarPlaceholderText = (showRoomIcons && useGenericIcons && widget.room.avatar == null) || - (!showRoomIcons && useGenericIcons) - ? widget.room.displayName - : null; + (!showRoomIcons && useGenericIcons) + ? widget.room.displayName + : null; - bool startsWithEmoji = - TextUtils.isEmoji(widget.room.displayName.characters.first); + bool startsWithEmoji = TextUtils.isEmoji( + widget.room.displayName.characters.first, + ); if (startsWithEmoji && widget.room.avatar == null) { shouldShowDefaultIcon = false; @@ -230,9 +239,8 @@ class _RoomTextButtonState extends State { footer: widget.room.displayHighlightedNotificationCount > 0 ? NotificationBadge(widget.room.displayHighlightedNotificationCount) : widget.room.displayNotificationCount > 0 - ? const Padding( - padding: EdgeInsets.all(2.0), child: DotIndicator()) - : null, + ? const Padding(padding: EdgeInsets.all(2.0), child: DotIndicator()) + : null, ), ); @@ -260,12 +268,7 @@ class _RoomTextButtonState extends State { child: Column( spacing: 8, crossAxisAlignment: CrossAxisAlignment.start, - children: [ - for (var activity in sessions) - buildActivity( - activity, - ), - ], + children: [for (var activity in sessions) buildActivity(activity)], ), ), ], @@ -285,8 +288,9 @@ class _RoomTextButtonState extends State { child: Container( clipBehavior: Clip.antiAlias, decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceTint.withAlpha(10), - borderRadius: BorderRadius.circular(8)), + color: ColorScheme.of(context).surfaceTint.withAlpha(10), + borderRadius: BorderRadius.circular(8), + ), child: Material( color: Colors.transparent, child: InkWell( @@ -303,20 +307,20 @@ class _RoomTextButtonState extends State { spacing: 8, children: [ SizedBox( - height: 20, - width: 20, - child: activity.icon.build(context)), + height: 20, + width: 20, + child: activity.icon.build(context), + ), tiamat.Text.labelLow(activity.name), ], ), ), - if (activity.thirdparty) - tiamat.Seperator( - padding: 2, - ), + if (activity.thirdparty) tiamat.Seperator(padding: 2), for (var participant in activity.participants) - buildCallMember(participant, - showActivityIcons: activity.thirdparty == false), + buildCallMember( + participant, + showActivityIcons: activity.thirdparty == false, + ), ], ), ), @@ -374,9 +378,11 @@ class _RoomTextButtonState extends State { padding: const EdgeInsets.fromLTRB(0, 2, 0, 2), child: Row( children: [ - for (var i in activitySessions!.where((i) => - i.thirdparty == true && - i.participants.contains(identifier))) + for (var i in activitySessions!.where( + (i) => + i.thirdparty == true && + i.participants.contains(identifier), + )) ClipRRect( borderRadius: BorderRadiusGeometry.circular(4), child: Material( @@ -386,12 +392,13 @@ class _RoomTextButtonState extends State { ? null : () => onWidgetTapped(i), child: SizedBox( - height: 30, - width: 30, - child: Padding( - padding: const EdgeInsets.all(6.0), - child: i.icon.build(context), - )), + height: 30, + width: 30, + child: Padding( + padding: const EdgeInsets.all(6.0), + child: i.icon.build(context), + ), + ), ), ), ), @@ -404,8 +411,9 @@ class _RoomTextButtonState extends State { } Widget buildEvent(MatrixCalendarEventState event) { - var color = - calendarRoom!.calendar!.config.getColorFromUser(event.senderId!); + var color = calendarRoom!.calendar!.config.getColorFromUser( + event.senderId!, + ); return TinyPill( event.data.title, @@ -428,11 +436,16 @@ class _RoomTextButtonState extends State { ); if (isInActivity == false) { - var confirm = await AdaptiveDialog.confirmation(context, - prompt: "Open **${activity.associatedWidget!.name}**?"); + var confirm = await AdaptiveDialog.confirmation( + context, + prompt: "Open **${activity.associatedWidget!.name}**?", + ); if (confirm == true) { WidgetComponent.runWidget( - widget.room, context, activity.associatedWidget!); + widget.room, + context, + activity.associatedWidget!, + ); } } else { Log.i("Already has a widget in for this session"); diff --git a/commet/lib/ui/atoms/scaled_safe_area.dart b/commet/lib/ui/atoms/scaled_safe_area.dart index b21dfc83a..bba902b67 100644 --- a/commet/lib/ui/atoms/scaled_safe_area.dart +++ b/commet/lib/ui/atoms/scaled_safe_area.dart @@ -1,5 +1,6 @@ import 'package:commet/utils/scaled_app.dart'; import 'package:flutter/material.dart'; + import 'dart:math' as math; class ScaledSafeArea extends SafeArea { @@ -19,7 +20,8 @@ class ScaledSafeArea extends SafeArea { if (maintainBottomViewPadding) { padding = padding.copyWith( - bottom: MediaQuery.of(context).scale().viewPadding.bottom); + bottom: MediaQuery.of(context).scale().viewPadding.bottom, + ); } return Padding( diff --git a/commet/lib/ui/atoms/shader/star_trails.dart b/commet/lib/ui/atoms/shader/star_trails.dart index 2b2a853ac..eb3185a44 100644 --- a/commet/lib/ui/atoms/shader/star_trails.dart +++ b/commet/lib/ui/atoms/shader/star_trails.dart @@ -21,8 +21,9 @@ class _StarTrailsBackgroundState extends State { void loadShader() async { loadingShader = true; - var program = - await FragmentProgram.fromAsset('assets/shader/constellation.frag'); + var program = await FragmentProgram.fromAsset( + 'assets/shader/constellation.frag', + ); shader = program.fragmentShader(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { @@ -69,9 +70,7 @@ class _StarTrailsBackgroundState extends State { } else { return CustomPaint( painter: StarTrailsPainter(shader!, delta * .3), - child: Container( - child: widget.child, - ), + child: Container(child: widget.child), ); } } diff --git a/commet/lib/ui/atoms/shimmer_loading.dart b/commet/lib/ui/atoms/shimmer_loading.dart index f338db23c..f08c622c3 100644 --- a/commet/lib/ui/atoms/shimmer_loading.dart +++ b/commet/lib/ui/atoms/shimmer_loading.dart @@ -6,11 +6,7 @@ const _shimmerGradient = LinearGradient( Color.fromARGB(100, 244, 244, 244), Color.fromARGB(50, 65, 65, 65), ], - stops: [ - 0.1, - 0.3, - 0.4, - ], + stops: [0.1, 0.3, 0.4], begin: Alignment(-1.0, -0.3), end: Alignment(1.0, 0.3), tileMode: TileMode.clamp, @@ -27,11 +23,7 @@ class Shimmer extends StatefulWidget { Color.fromARGB(200, 244, 244, 244), Color.fromARGB(200, 65, 65, 65), ], - stops: [ - 0.0, - 0.3, - 0.4, - ], + stops: [0.0, 0.3, 0.4], begin: Alignment(-1, 0), end: Alignment(1, 0), tileMode: TileMode.clamp, @@ -68,13 +60,14 @@ class ShimmerState extends State with SingleTickerProviderStateMixin { } LinearGradient get gradient => LinearGradient( - colors: widget.linearGradient.colors, - stops: widget.linearGradient.stops, - begin: widget.linearGradient.begin, - end: widget.linearGradient.end, - transform: - _SlidingGradientTransform(slidePercent: _shimmerController.value), - ); + colors: widget.linearGradient.colors, + stops: widget.linearGradient.stops, + begin: widget.linearGradient.begin, + end: widget.linearGradient.end, + transform: _SlidingGradientTransform( + slidePercent: _shimmerController.value, + ), + ); bool get isSized => (context.findRenderObject() as RenderBox?)?.hasSize ?? false; @@ -98,9 +91,7 @@ class ShimmerState extends State with SingleTickerProviderStateMixin { } class _SlidingGradientTransform extends GradientTransform { - const _SlidingGradientTransform({ - required this.slidePercent, - }); + const _SlidingGradientTransform({required this.slidePercent}); final double slidePercent; diff --git a/commet/lib/ui/atoms/space_header.dart b/commet/lib/ui/atoms/space_header.dart index 4ed14d45f..8e363ac22 100644 --- a/commet/lib/ui/atoms/space_header.dart +++ b/commet/lib/ui/atoms/space_header.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:commet/client/components/space_banner/space_banner_component.dart'; import 'package:commet/client/components/space_color_scheme/space_color_scheme_component.dart'; import 'package:commet/utils/scaled_app.dart'; @@ -7,8 +8,12 @@ import 'package:flutter/material.dart'; import '../../client/client.dart'; class SpaceHeader extends StatefulWidget { - const SpaceHeader(this.space, - {this.onTap, this.backgroundColor = Colors.transparent, super.key}); + const SpaceHeader( + this.space, { + this.onTap, + this.backgroundColor = Colors.transparent, + super.key, + }); final Space space; final Color backgroundColor; final void Function()? onTap; @@ -49,10 +54,13 @@ class _SpaceHeaderState extends State { return ClipRRect( borderRadius: const BorderRadius.only( - bottomLeft: Radius.circular(8), bottomRight: Radius.circular(8)), + bottomLeft: Radius.circular(8), + bottomRight: Radius.circular(8), + ), child: ConstrainedBox( constraints: BoxConstraints.expand( - height: 100 + MediaQuery.of(context).padding.top), + height: 100 + MediaQuery.of(context).padding.top, + ), child: Stack( fit: StackFit.expand, children: [ @@ -73,35 +81,40 @@ class _SpaceHeaderState extends State { onTap: widget.onTap, child: DecoratedBox( decoration: BoxDecoration( - gradient: widget.space.avatar != null - ? LinearGradient( - begin: AlignmentGeometry.bottomCenter, - end: AlignmentGeometry.topCenter, - colors: [colorScheme.primary, Colors.transparent], - ) - : null), + gradient: widget.space.avatar != null + ? LinearGradient( + begin: AlignmentGeometry.bottomCenter, + end: AlignmentGeometry.topCenter, + colors: [colorScheme.primary, Colors.transparent], + ) + : null, + ), child: Align( alignment: Alignment.bottomLeft, child: Padding( padding: const EdgeInsets.fromLTRB(8, 2, 0, 2), - child: Text(widget.space.displayName, - style: - Theme.of(context).textTheme.titleMedium!.copyWith( - color: colorScheme.onPrimary, - shadows: widget.space.avatar != null - ? [ - const BoxShadow( - blurRadius: 2, - spreadRadius: 10, - color: Colors.black, - offset: Offset(2, 2)) - ] - : null)), + child: Text( + widget.space.displayName, + style: Theme.of(context).textTheme.titleMedium! + .copyWith( + color: colorScheme.onPrimary, + shadows: widget.space.avatar != null + ? [ + const BoxShadow( + blurRadius: 2, + spreadRadius: 10, + color: Colors.black, + offset: Offset(2, 2), + ), + ] + : null, + ), + ), ), ), ), ), - ) + ), ], ), ), diff --git a/commet/lib/ui/atoms/space_icon.dart b/commet/lib/ui/atoms/space_icon.dart index ff1aeb472..1ef6c8318 100644 --- a/commet/lib/ui/atoms/space_icon.dart +++ b/commet/lib/ui/atoms/space_icon.dart @@ -7,22 +7,23 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart'; class SpaceIcon extends StatefulWidget { - const SpaceIcon( - {super.key, - this.width = 44, - this.onTap, - this.showUser = false, - this.onUpdate, - required this.spaceId, - required this.clientId, - this.avatar, - this.placeholderColor, - this.notificationCount = 0, - this.highlightedNotificationCount = 0, - required this.displayName, - this.userAvatar, - this.userDisplayName, - this.userColor}); + const SpaceIcon({ + super.key, + this.width = 44, + this.onTap, + this.showUser = false, + this.onUpdate, + required this.spaceId, + required this.clientId, + this.avatar, + this.placeholderColor, + this.notificationCount = 0, + this.highlightedNotificationCount = 0, + required this.displayName, + this.userAvatar, + this.userDisplayName, + this.userColor, + }); final double width; final void Function()? onTap; final bool showUser; @@ -51,8 +52,9 @@ class _SpaceIconState extends State { setState(() {}); }); - spaceSelectionSub = - EventBus.onSelectedSpaceChanged.stream.listen(onSelectedSpaceChanged); + spaceSelectionSub = EventBus.onSelectedSpaceChanged.stream.listen( + onSelectedSpaceChanged, + ); super.initState(); } @@ -61,7 +63,8 @@ class _SpaceIconState extends State { void onSelectedSpaceChanged(Space? event) { setState(() { - selected = event?.identifier == widget.spaceId && + selected = + event?.identifier == widget.spaceId && event?.client.identifier == widget.clientId; }); } @@ -75,26 +78,29 @@ class _SpaceIconState extends State { @override Widget build(BuildContext context) { - return Stack(children: [ - AspectRatio( - aspectRatio: 1.0, - child: ImageButton( - border: selected - ? Border.all( - color: ColorScheme.of(context).inverseSurface, - width: 3, - strokeAlign: 0.5) - : null, - image: widget.avatar, - onTap: widget.onTap, - size: widget.width, - placeholderColor: widget.placeholderColor, - placeholderText: widget.displayName, + return Stack( + children: [ + AspectRatio( + aspectRatio: 1.0, + child: ImageButton( + border: selected + ? Border.all( + color: ColorScheme.of(context).inverseSurface, + width: 3, + strokeAlign: 0.5, + ) + : null, + image: widget.avatar, + onTap: widget.onTap, + size: widget.width, + placeholderColor: widget.placeholderColor, + placeholderText: widget.displayName, + ), ), - ), - if (widget.showUser) avatarOverlay(), - if (widget.highlightedNotificationCount > 0) notificationOverlay(), - ]); + if (widget.showUser) avatarOverlay(), + if (widget.highlightedNotificationCount > 0) notificationOverlay(), + ], + ); } Positioned avatarOverlay() { @@ -106,18 +112,17 @@ class _SpaceIconState extends State { width: 20, height: 20, child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - boxShadow: const [ - BoxShadow(color: Colors.black, blurRadius: 4) - ], - ), - child: Avatar( - radius: 10, - image: widget.userAvatar, - placeholderColor: widget.userColor, - placeholderText: widget.userDisplayName, - )), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + boxShadow: const [BoxShadow(color: Colors.black, blurRadius: 4)], + ), + child: Avatar( + radius: 10, + image: widget.userAvatar, + placeholderColor: widget.userColor, + placeholderText: widget.userDisplayName, + ), + ), ), ), ); @@ -139,8 +144,9 @@ class _SpaceIconState extends State { height: 8, child: DecoratedBox( decoration: BoxDecoration( - color: Theme.of(context).colorScheme.onSurface, - borderRadius: BorderRadius.circular(5)), + color: Theme.of(context).colorScheme.onSurface, + borderRadius: BorderRadius.circular(5), + ), ), ), ); diff --git a/commet/lib/ui/atoms/space_list.dart b/commet/lib/ui/atoms/space_list.dart index 4fb419423..bba0b917e 100644 --- a/commet/lib/ui/atoms/space_list.dart +++ b/commet/lib/ui/atoms/space_list.dart @@ -15,12 +15,14 @@ import 'package:intl/intl.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class SpaceList extends StatefulWidget { - const SpaceList(this.space, - {this.onRoomSelected, - this.isTopLevel = true, - this.currentDepth = 0, - this.maxDepth = 5, - super.key}); + const SpaceList( + this.space, { + this.onRoomSelected, + this.isTopLevel = true, + this.currentDepth = 0, + this.maxDepth = 5, + super.key, + }); final Function(Room room, {bool bypassSpecialRoomType})? onRoomSelected; final bool isTopLevel; @@ -43,8 +45,11 @@ class _SpaceListState extends State { late List subs; Room? selectedRoom; - String get labelRoomsList => Intl.message("Rooms", - desc: "Header label for the list of rooms", name: "labelRoomsList"); + String get labelRoomsList => Intl.message( + "Rooms", + desc: "Header label for the list of rooms", + name: "labelRoomsList", + ); @override void initState() { @@ -52,12 +57,15 @@ class _SpaceListState extends State { previews = widget.space.childPreviews; subs = [ - widget.space.onChildRoomPreviewAdded - .listen((_) => onPreviewListChanged()), - widget.space.onChildRoomPreviewsUpdated - .listen((_) => onPreviewListChanged()), - widget.space.onChildRoomPreviewRemoved - .listen((_) => onPreviewListChanged()), + widget.space.onChildRoomPreviewAdded.listen( + (_) => onPreviewListChanged(), + ), + widget.space.onChildRoomPreviewsUpdated.listen( + (_) => onPreviewListChanged(), + ), + widget.space.onChildRoomPreviewRemoved.listen( + (_) => onPreviewListChanged(), + ), EventBus.onSelectedRoomChanged.stream.listen(onRoomSelected), widget.space.onUpdate.listen(onSpaceUpdated), widget.space.onChildSpaceAdded.listen(onSpaceUpdated), @@ -118,12 +126,14 @@ class _SpaceListState extends State { Widget roomsList() { if (widget.isTopLevel) { - return tiamat.TextButtonExpander(labelRoomsList, - childrenPadding: const EdgeInsets.fromLTRB(2, 0, 0, 0), - initiallyExpanded: true, - iconColor: Theme.of(context).colorScheme.secondary, - textColor: Theme.of(context).colorScheme.secondary, - children: [buildRoomsList()]); + return tiamat.TextButtonExpander( + labelRoomsList, + childrenPadding: const EdgeInsets.fromLTRB(2, 0, 0, 0), + initiallyExpanded: true, + iconColor: Theme.of(context).colorScheme.secondary, + textColor: Theme.of(context).colorScheme.secondary, + children: [buildRoomsList()], + ); } else { return buildRoomsList(); } @@ -147,16 +157,15 @@ class _SpaceListState extends State { } Widget buildPreviewChild(RoomPreview preview) { - return RoomPreviewTextButton( - preview, - onTap: joinRoomWithConfirmation, - ); + return RoomPreviewTextButton(preview, onTap: joinRoomWithConfirmation); } Future joinRoomWithConfirmation(RoomPreview preview) async { - if (await AdaptiveDialog.confirmation(context, - prompt: - "Are you sure you want to join the room '${preview.displayName}' ?") == + if (await AdaptiveDialog.confirmation( + context, + prompt: + "Are you sure you want to join the room '${preview.displayName}' ?", + ) == true) { Room room = await widget.space.client.joinRoomFromPreview(preview); await widget.onRoomSelected?.call(room); @@ -178,24 +187,26 @@ class _SpaceListState extends State { widget.space.removeChild(child); } }, - ) + ), ], - child: tiamat.TextButtonExpander(child.child.displayName, - initiallyExpanded: true, - childrenPadding: const EdgeInsets.fromLTRB(2, 0, 0, 0), - iconColor: Theme.of(context).colorScheme.secondary, - textColor: Theme.of(context).colorScheme.secondary, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), - child: SpaceList( - child.child, - isTopLevel: false, - currentDepth: widget.currentDepth + 1, - onRoomSelected: widget.onRoomSelected, - ), - ) - ]), + child: tiamat.TextButtonExpander( + child.child.displayName, + initiallyExpanded: true, + childrenPadding: const EdgeInsets.fromLTRB(2, 0, 0, 0), + iconColor: Theme.of(context).colorScheme.secondary, + textColor: Theme.of(context).colorScheme.secondary, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), + child: SpaceList( + child.child, + isTopLevel: false, + currentDepth: widget.currentDepth + 1, + onRoomSelected: widget.onRoomSelected, + ), + ), + ], + ), ); } else { return tiamat.TextButton(widget.space.displayName); diff --git a/commet/lib/ui/atoms/thread_reply_footer.dart b/commet/lib/ui/atoms/thread_reply_footer.dart index e5fbdbe95..f2f0ea0fc 100644 --- a/commet/lib/ui/atoms/thread_reply_footer.dart +++ b/commet/lib/ui/atoms/thread_reply_footer.dart @@ -4,13 +4,14 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class ThreadReplyFooter extends StatelessWidget { - const ThreadReplyFooter( - {required this.body, - required this.senderName, - this.senderAvatar, - this.senderColor, - this.onTap, - super.key}); + const ThreadReplyFooter({ + required this.body, + required this.senderName, + this.senderAvatar, + this.senderColor, + this.onTap, + super.key, + }); final String body; final String senderName; final Color? senderColor; @@ -36,7 +37,8 @@ class ThreadReplyFooter extends StatelessWidget { child: SizedBox.expand( child: CustomPaint( painter: ThreadLinePainter( - pathColor: Theme.of(context).colorScheme.secondary), + pathColor: Theme.of(context).colorScheme.secondary, + ), ), ), ), @@ -88,10 +90,7 @@ class ThreadReplyFooter extends StatelessWidget { ), const Padding( padding: EdgeInsets.fromLTRB(4, 0, 4, 0), - child: Icon( - Icons.chevron_right_rounded, - size: 15, - ), + child: Icon(Icons.chevron_right_rounded, size: 15), ), ], ), diff --git a/commet/lib/ui/layout/bento.dart b/commet/lib/ui/layout/bento.dart index c3af1cef3..8090082b0 100644 --- a/commet/lib/ui/layout/bento.dart +++ b/commet/lib/ui/layout/bento.dart @@ -26,12 +26,10 @@ class BentoLayout extends StatelessWidget { gridSize = gridSize.clamp(1, children.length); - var across = ({required List children}) => Column( - children: children, - ) as Widget; - var down = ({required List children}) => Row( - children: children, - ) as Widget; + var across = ({required List children}) => + Column(children: children) as Widget; + var down = ({required List children}) => + Row(children: children) as Widget; if (aspect < 1.3) { var temp = across; @@ -49,13 +47,14 @@ class BentoLayout extends StatelessWidget { for (var j = 0; j < gridSize; j++) if (j + (i * gridSize) < children.length) Flexible( - child: Padding( - padding: const EdgeInsets.all(2.0), - child: children[j + (i * gridSize)], - )) + child: Padding( + padding: const EdgeInsets.all(2.0), + child: children[j + (i * gridSize)], + ), + ), ], ), - ) + ), ], )); }, diff --git a/commet/lib/ui/molecules/alert_view.dart b/commet/lib/ui/molecules/alert_view.dart index 568f160ef..282149a5f 100644 --- a/commet/lib/ui/molecules/alert_view.dart +++ b/commet/lib/ui/molecules/alert_view.dart @@ -12,25 +12,24 @@ class AlertView extends StatelessWidget { color: Colors.transparent, child: InkWell( onTap: alert.action == null ? null : () => alert.action?.call(context), - child: Row(children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Icon( - getIcon(), - color: getColor(context), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Icon(getIcon(), color: getColor(context)), ), - ), - Flexible( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - tiamat.Text.labelEmphasised(alert.title), - tiamat.Text.labelLow(alert.message), - ], + Flexible( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + tiamat.Text.labelEmphasised(alert.title), + tiamat.Text.labelLow(alert.message), + ], + ), ), - ) - ]), + ], + ), ), ); } diff --git a/commet/lib/ui/molecules/audio_player/audio_player.dart b/commet/lib/ui/molecules/audio_player/audio_player.dart index db7df0be8..b635baeab 100644 --- a/commet/lib/ui/molecules/audio_player/audio_player.dart +++ b/commet/lib/ui/molecules/audio_player/audio_player.dart @@ -9,8 +9,12 @@ import 'package:tiamat/tiamat.dart' as tiamat; import 'package:commet/main.dart'; class AudioPlayer extends StatefulWidget { - const AudioPlayer( - {required this.file, this.fileName, this.fileSize, super.key}); + const AudioPlayer({ + required this.file, + this.fileName, + this.fileSize, + super.key, + }); final String? fileName; final int? fileSize; @@ -20,11 +24,7 @@ class AudioPlayer extends StatefulWidget { State createState() => _AudioPlayerState(); } -enum AudioPlayerState { - paused, - loading, - playing, -} +enum AudioPlayerState { paused, loading, playing } class _AudioPlayerState extends State { Player player = Player(); @@ -74,8 +74,9 @@ class _AudioPlayerState extends State { Widget build(BuildContext context) { return Container( decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerLow, - borderRadius: BorderRadius.circular(8)), + color: Theme.of(context).colorScheme.surfaceContainerLow, + borderRadius: BorderRadius.circular(8), + ), child: SizedBox( width: 500, child: Column( @@ -89,13 +90,8 @@ class _AudioPlayerState extends State { children: [ Row( children: [ - Icon( - Icons.audio_file, - size: 20, - ), - SizedBox( - width: 8, - ), + Icon(Icons.audio_file, size: 20), + SizedBox(width: 8), tiamat.Text.labelLow(widget.fileName!), ], ), @@ -103,57 +99,57 @@ class _AudioPlayerState extends State { Padding( padding: const EdgeInsets.fromLTRB(0, 0, 12, 0), child: tiamat.Text.labelLow( - TextUtils.readableFileSize(widget.fileSize!)), + TextUtils.readableFileSize(widget.fileSize!), + ), ), ], ), ), Padding( padding: const EdgeInsets.fromLTRB(0, 8, 0, 4), - child: tiamat.Seperator( - padding: 0, - ), + child: tiamat.Seperator(padding: 0), ), Row( children: [ + SizedBox(width: 8), SizedBox( - width: 8, + width: 40, + height: 40, + child: state == AudioPlayerState.loading + ? Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + value: downloadProgress, + ), + ), + ) + : tiamat.IconButton( + icon: state == AudioPlayerState.paused + ? Icons.play_arrow + : Icons.pause, + onPressed: onPlayButtonPressed, + ), ), - SizedBox( - width: 40, - height: 40, - child: state == AudioPlayerState.loading - ? Center( - child: SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - value: downloadProgress, - )), - ) - : tiamat.IconButton( - icon: state == AudioPlayerState.paused - ? Icons.play_arrow - : Icons.pause, - onPressed: onPlayButtonPressed, - )), Expanded( - child: tiamat.Slider( - value: displayPosition, - onChangeStart: (value) { - dragging = true; - }, - onChangeEnd: (value) { - dragging = false; - - var position = player.state.duration * value; - - player.seek(position); - }, - onChanged: (value) => setState(() { - displayPosition = value; - }), - )), + child: tiamat.Slider( + value: displayPosition, + onChangeStart: (value) { + dragging = true; + }, + onChangeEnd: (value) { + dragging = false; + + var position = player.state.duration * value; + + player.seek(position); + }, + onChanged: (value) => setState(() { + displayPosition = value; + }), + ), + ), const SizedBox(width: 8), HoverMenu( key: menuKey, @@ -163,8 +159,8 @@ class _AudioPlayerState extends State { icon: isMuted ? Icons.volume_mute : volume == 0 - ? Icons.volume_off - : Icons.volume_up, + ? Icons.volume_off + : Icons.volume_up, onPressed: (() { toggleIsMuted(); preferences.isPlayerMuted.set(isMuted); @@ -172,22 +168,24 @@ class _AudioPlayerState extends State { ), builder: (context) { return RotatedBox( - quarterTurns: 3, - child: Container( - decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainer, - borderRadius: BorderRadius.circular(8)), - child: SizedBox( - width: 200, - height: 50, - child: tiamat.Slider( - value: volume / 100, - onChanged: (value) => setVolume(value * 100), - onChangeEnd: (value) => - preferences.playerVolume.set(appliedVolume), - ), + quarterTurns: 3, + child: Container( + decoration: BoxDecoration( + color: ColorScheme.of(context).surfaceContainer, + borderRadius: BorderRadius.circular(8), + ), + child: SizedBox( + width: 200, + height: 50, + child: tiamat.Slider( + value: volume / 100, + onChanged: (value) => setVolume(value * 100), + onChangeEnd: (value) => + preferences.playerVolume.set(appliedVolume), ), - )); + ), + ), + ); }, ), const SizedBox(width: 12), @@ -254,7 +252,8 @@ class _AudioPlayerState extends State { void onPositionChanged(Duration event) { if (!dragging) { setState(() { - var pos = event.inMilliseconds.toDouble() / + var pos = + event.inMilliseconds.toDouble() / player.state.duration.inMilliseconds.toDouble(); if (pos >= 0 && pos <= 1) { diff --git a/commet/lib/ui/molecules/call_sessions_panel.dart b/commet/lib/ui/molecules/call_sessions_panel.dart index cc3d37f97..5a0f94ba0 100644 --- a/commet/lib/ui/molecules/call_sessions_panel.dart +++ b/commet/lib/ui/molecules/call_sessions_panel.dart @@ -33,17 +33,15 @@ class _CallSessionsPanelState extends State { Widget build(BuildContext context) { return Container( decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceTint.withAlpha(10), - borderRadius: BorderRadius.circular(8)), + color: ColorScheme.of(context).surfaceTint.withAlpha(10), + borderRadius: BorderRadius.circular(8), + ), child: Column( children: [ for (var entry in clientManager!.callManager.currentSessions) ClipRRect( borderRadius: BorderRadiusGeometry.circular(8), - child: CallSessionPanel( - session: entry, - height: widget.height, - ), + child: CallSessionPanel(session: entry, height: widget.height), ), ], ), @@ -71,7 +69,9 @@ class _CallSessionPanelState extends State room = widget.session.client.getRoom(widget.session.roomId); audioLevel = AnimationController( - vsync: this, duration: CallView.volumeAnimationDuration); + vsync: this, + duration: CallView.volumeAnimationDuration, + ); subs = [ widget.session.onStateChanged.listen((event) { @@ -80,7 +80,7 @@ class _CallSessionPanelState extends State widget.session.onUpdateVolumeVisualizers.listen((_) async { await widget.session.updateStats(); audioLevel.animateTo(widget.session.generalAudioLevel); - }) + }), ]; super.initState(); @@ -101,8 +101,10 @@ class _CallSessionPanelState extends State color: Colors.transparent, child: InkWell( onTap: () { - EventBus.doOpenRoom(widget.session.roomId, - clientId: widget.session.client.identifier); + EventBus.doOpenRoom( + widget.session.roomId, + clientId: widget.session.client.identifier, + ); }, child: SizedBox( height: widget.height, @@ -113,28 +115,31 @@ class _CallSessionPanelState extends State mainAxisSize: MainAxisSize.min, children: [ pickAnimation( - entry: widget.session, - child: SizedBox( - height: widget.height, - width: widget.height, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: AnimatedBuilder( - animation: audioLevel, - builder: (context, child) { - return Container( - child: Icon( - Icons.volume_up_rounded, - color: Color.lerp( - ColorScheme.of(context).onSurface, - ColorScheme.of(context).inversePrimary, - audioLevel.value), - size: 16, - ), - ); - }, - )), - )), + entry: widget.session, + child: SizedBox( + height: widget.height, + width: widget.height, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: AnimatedBuilder( + animation: audioLevel, + builder: (context, child) { + return Container( + child: Icon( + Icons.volume_up_rounded, + color: Color.lerp( + ColorScheme.of(context).onSurface, + ColorScheme.of(context).inversePrimary, + audioLevel.value, + ), + size: 16, + ), + ); + }, + ), + ), + ), + ), tiamat.Text(widget.session.roomName), ], ), @@ -145,30 +150,34 @@ class _CallSessionPanelState extends State width: widget.height, height: widget.height, child: AspectRatio( - aspectRatio: 1.0, - child: tiamat.IconButton( - onPressed: () { - if (widget.session.isMicrophoneMuted) { - clientManager!.callManager.unmute(); - } else { - clientManager!.callManager.mute(); - } - }, - icon: widget.session.isMicrophoneMuted - ? Icons.mic_off_rounded - : Icons.mic_rounded)), + aspectRatio: 1.0, + child: tiamat.IconButton( + onPressed: () { + if (widget.session.isMicrophoneMuted) { + clientManager!.callManager.unmute(); + } else { + clientManager!.callManager.mute(); + } + }, + icon: widget.session.isMicrophoneMuted + ? Icons.mic_off_rounded + : Icons.mic_rounded, + ), + ), ), SizedBox( width: widget.height, height: widget.height, child: AspectRatio( - aspectRatio: 1.0, - child: tiamat.IconButton( - onPressed: () { - widget.session.hangUpCall(); - }, - iconColor: ColorScheme.of(context).error, - icon: Icons.call_end_rounded)), + aspectRatio: 1.0, + child: tiamat.IconButton( + onPressed: () { + widget.session.hangUpCall(); + }, + iconColor: ColorScheme.of(context).error, + icon: Icons.call_end_rounded, + ), + ), ), ], ), diff --git a/commet/lib/ui/molecules/current_session_panel.dart b/commet/lib/ui/molecules/current_session_panel.dart index 7f6421a52..760be8f94 100644 --- a/commet/lib/ui/molecules/current_session_panel.dart +++ b/commet/lib/ui/molecules/current_session_panel.dart @@ -75,100 +75,106 @@ class _CurrentSessionPanelState extends State { children: [ if (WidgetComponent.currentSessions.isNotEmpty) Padding( - padding: EdgeInsetsGeometry.fromLTRB(4, 4, 4, 0), - child: WidgetSessionsPanel( - height: 40, - )), + padding: EdgeInsetsGeometry.fromLTRB(4, 4, 4, 0), + child: WidgetSessionsPanel(height: 40), + ), if (clientManager!.callManager.currentSessions.isNotEmpty) Padding( padding: EdgeInsetsGeometry.fromLTRB(4, 4, 4, 0), - child: CallSessionsPanel( - height: 40, - ), + child: CallSessionsPanel(height: 40), ), Material( color: Colors.transparent, child: Container( - child: AdaptiveContextMenu( - modal: true, - items: [ - if (clientManager!.clients.length > 1) - tiamat.ContextMenuItem( + child: AdaptiveContextMenu( + modal: true, + items: [ + if (clientManager!.clients.length > 1) + tiamat.ContextMenuItem( text: "Mix Accounts", onPressed: () { EventBus.setFilterClient.add(null); preferences.filterClient.set(null); - }), - if (clientManager!.clients.length > 1) - ...clientManager!.clients - .map((i) => tiamat.ContextMenuItem( - text: i.self!.identifier, - onPressed: () { - print("Setting filter client"); - EventBus.setFilterClient.add(i); - preferences.filterClient.set(i.identifier); - })) - .toList() - ], - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - spacing: 8, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - spacing: 8, - children: [ - if (current != null) - tiamat.Avatar( - radius: 12, - image: current.avatar, - placeholderColor: current.defaultColor, - placeholderText: current.displayName, + }, + ), + if (clientManager!.clients.length > 1) + ...clientManager!.clients + .map( + (i) => tiamat.ContextMenuItem( + text: i.self!.identifier, + onPressed: () { + print("Setting filter client"); + EventBus.setFilterClient.add(i); + preferences.filterClient.set(i.identifier); + }, ), - if (current != null) - Flexible( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - tiamat.Text.name( + ) + .toList(), + ], + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + spacing: 8, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + spacing: 8, + children: [ + if (current != null) + tiamat.Avatar( + radius: 12, + image: current.avatar, + placeholderColor: current.defaultColor, + placeholderText: current.displayName, + ), + if (current != null) + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + tiamat.Text.name( maxLines: 1, overflow: TextOverflow.ellipsis, color: current.defaultColor, - current.displayName), - Material( - color: Colors.transparent, - child: InkWell( - onTap: () => Clipboard.setData( + current.displayName, + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () => Clipboard.setData( ClipboardData( - text: current!.identifier)), - child: Opacity( - opacity: 0.7, - child: Text( - maxLines: 1, - current.identifier, - overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .labelSmall - ?.copyWith( + text: current!.identifier, + ), + ), + child: Opacity( + opacity: 0.7, + child: Text( + maxLines: 1, + current.identifier, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .labelSmall + ?.copyWith( fontFamily: "Code", fontSize: 10, color: Theme.of(context) .colorScheme - .secondary), + .secondary, + ), + ), ), ), ), - ), - ], + ], + ), ), - ), - if (current == null) - ...clientManager!.clients - .where((i) => i.self != null) - .map((i) => SizedBox( + if (current == null) + ...clientManager!.clients + .where((i) => i.self != null) + .map( + (i) => SizedBox( width: 24, height: 24, child: AspectRatio( @@ -180,16 +186,16 @@ class _CurrentSessionPanelState extends State { image: i.self!.avatar, ), ), - )), - ], - ), - UserPanelSettings( - height: profileHeight, - ) - ], + ), + ), + ], + ), + UserPanelSettings(height: profileHeight), + ], + ), ), ), - )), + ), ), ], ), diff --git a/commet/lib/ui/molecules/editable_label.dart b/commet/lib/ui/molecules/editable_label.dart index e0fd88ffa..40a209629 100644 --- a/commet/lib/ui/molecules/editable_label.dart +++ b/commet/lib/ui/molecules/editable_label.dart @@ -36,9 +36,7 @@ class _EditableLabelState extends State { @override Widget build(BuildContext context) { - return Row( - children: [nameEditor(), toggleNameEdit()], - ); + return Row(children: [nameEditor(), toggleNameEdit()]); } void _confirmName() { @@ -55,20 +53,18 @@ class _EditableLabelState extends State { Widget nameEditor() { return material.Material( - color: material.Colors.transparent, - child: editingName - ? SizedBox( - width: 200, - child: TextInput( - maxLines: 1, - controller: nameController, - onSubmitted: (_) => _confirmName(), - ), - ) - : tiamat.Text( - text, - type: widget.type, - )); + color: material.Colors.transparent, + child: editingName + ? SizedBox( + width: 200, + child: TextInput( + maxLines: 1, + controller: nameController, + onSubmitted: (_) => _confirmName(), + ), + ) + : tiamat.Text(text, type: widget.type), + ); } Widget toggleNameEdit() { diff --git a/commet/lib/ui/molecules/emoji_picker.dart b/commet/lib/ui/molecules/emoji_picker.dart index d41af76e5..744fb7b0e 100644 --- a/commet/lib/ui/molecules/emoji_picker.dart +++ b/commet/lib/ui/molecules/emoji_picker.dart @@ -10,18 +10,20 @@ import 'package:commet/client/components/emoticon/emoji_pack.dart'; import 'package:commet/ui/atoms/emoji_widget.dart'; class EmojiPicker extends StatefulWidget { - EmojiPicker(this.packs, - {super.key, - this.size = BuildConfig.MOBILE ? 48 : 42, - this.onEmoticonPressed, - this.packButtonSize = BuildConfig.MOBILE ? 48 : 42, - this.onlyEmoji = false, - this.onlyStickers = false, - this.staggered = false, - this.searchDelegate, - this.focus, - this.preferredTooltipDirection = AxisDirection.right, - this.packListAxis = Axis.vertical}); + EmojiPicker( + this.packs, { + super.key, + this.size = BuildConfig.MOBILE ? 48 : 42, + this.onEmoticonPressed, + this.packButtonSize = BuildConfig.MOBILE ? 48 : 42, + this.onlyEmoji = false, + this.onlyStickers = false, + this.staggered = false, + this.searchDelegate, + this.focus, + this.preferredTooltipDirection = AxisDirection.right, + this.packListAxis = Axis.vertical, + }); final void Function(Emoticon emoticon)? onEmoticonPressed; final List packs; final double size; @@ -32,7 +34,7 @@ class EmojiPicker extends StatefulWidget { final bool onlyStickers; final bool onlyEmoji; final List Function(String text)? - searchDelegate; + searchDelegate; final AxisDirection preferredTooltipDirection; @override @@ -113,10 +115,11 @@ class _EmojiPickerState extends State { @override Widget build(BuildContext context) { return Material( - color: Colors.transparent, - child: widget.packListAxis == Axis.vertical - ? buildWithVerticalList(context) - : buildWithHorizontalList(context)); + color: Colors.transparent, + child: widget.packListAxis == Axis.vertical + ? buildWithVerticalList(context) + : buildWithHorizontalList(context), + ); } Row buildWithVerticalList(BuildContext context) { @@ -130,8 +133,8 @@ class _EmojiPickerState extends State { child: SizedBox( width: widget.packButtonSize, child: ScrollConfiguration( - behavior: - ScrollConfiguration.of(context).copyWith(scrollbars: false), + behavior: ScrollConfiguration.of(context) + .copyWith(scrollbars: false), child: ListView.builder( itemCount: widget.packs.length, padding: EdgeInsets.all(0), @@ -162,8 +165,8 @@ class _EmojiPickerState extends State { child: ConstrainedBox( constraints: BoxConstraints(maxHeight: widget.packButtonSize), child: ScrollConfiguration( - behavior: - ScrollConfiguration.of(context).copyWith(scrollbars: false), + behavior: ScrollConfiguration.of(context) + .copyWith(scrollbars: false), child: ListView.builder( padding: EdgeInsets.all(0), scrollDirection: Axis.horizontal, @@ -204,8 +207,9 @@ class _EmojiPickerState extends State { Expanded buildEmojiList() { return Expanded( - key: key, - child: LayoutBuilder(builder: (context, constraints) { + key: key, + child: LayoutBuilder( + builder: (context, constraints) { var count = (constraints.maxWidth / widget.size).toInt(); if (count != crossAxisCount) { WidgetsBinding.instance.addPostFrameCallback((_) { @@ -220,12 +224,13 @@ class _EmojiPickerState extends State { slivers: [ if (widget.searchDelegate != null) SliverList( - delegate: SliverChildListDelegate([ - SizedBox( + delegate: SliverChildListDelegate([ + SizedBox( height: searchBarSize, child: Container( - color: - Theme.of(context).colorScheme.surfaceContainerLow, + color: Theme.of(context) + .colorScheme + .surfaceContainerLow, child: Center( child: Padding( padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), @@ -235,27 +240,33 @@ class _EmojiPickerState extends State { controller: textController, onChanged: onSearchTextChanged, decoration: InputDecoration( - border: InputBorder.none, - hintText: CommonStrings.promptSearch, - icon: Icon(Icons.search)), + border: InputBorder.none, + hintText: CommonStrings.promptSearch, + icon: Icon(Icons.search), + ), ), ), ), - )) - ])), + ), + ), + ]), + ), if (searchResults?.isEmpty == true) SliverList( - delegate: SliverChildListDelegate([ - SizedBox( - height: 50, - child: Center( - child: tiamat.Text.labelLow("No results found :(")), - ), - ])), + delegate: SliverChildListDelegate([ + SizedBox( + height: 50, + child: Center( + child: tiamat.Text.labelLow("No results found :("), + ), + ), + ]), + ), if (searchResults?.isNotEmpty == true) SliverGrid.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: crossAxisCount), + crossAxisCount: crossAxisCount, + ), itemCount: searchResults!.length, itemBuilder: (context, index) { var emote = searchResults![index].emoticon; @@ -265,46 +276,50 @@ class _EmojiPickerState extends State { if (searchResults == null) for (var pack in widget.packs) ...[ SliverList( - delegate: SliverChildListDelegate([ - SizedBox( - height: headerSize, - child: Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), - child: Align( + delegate: SliverChildListDelegate([ + SizedBox( + height: headerSize, + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), + child: Align( alignment: AlignmentGeometry.centerLeft, - child: Text(pack.displayName)), + child: Text(pack.displayName), + ), + ), ), - ), - ])), + ]), + ), SliverGrid.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: crossAxisCount), + crossAxisCount: crossAxisCount, + ), itemCount: getEmoticonList(pack).length, itemBuilder: (context, index) { var emote = getEmoticonList(pack)[index]; return buildEmoticon(emote); }, - ) + ), ], ], ); - })); + }, + ), + ); } Widget buildEmoticon(Emoticon emoticon) { return SizedBox( - width: widget.size, - height: widget.size, - child: InkWell( - borderRadius: BorderRadius.circular(3), - onTap: () => widget.onEmoticonPressed?.call(emoticon), - mouseCursor: SystemMouseCursors.click, - child: Padding( - padding: const EdgeInsets.all(2.0), - child: Center( - child: EmojiWidget( - emoticon, - height: widget.size, - ))))); + width: widget.size, + height: widget.size, + child: InkWell( + borderRadius: BorderRadius.circular(3), + onTap: () => widget.onEmoticonPressed?.call(emoticon), + mouseCursor: SystemMouseCursors.click, + child: Padding( + padding: const EdgeInsets.all(2.0), + child: Center(child: EmojiWidget(emoticon, height: widget.size)), + ), + ), + ); } } diff --git a/commet/lib/ui/molecules/emoticon_picker.dart b/commet/lib/ui/molecules/emoticon_picker.dart index 3e2c89700..1594f9b83 100644 --- a/commet/lib/ui/molecules/emoticon_picker.dart +++ b/commet/lib/ui/molecules/emoticon_picker.dart @@ -41,7 +41,7 @@ class EmoticonPicker extends StatefulWidget { final void Function(Emoticon emoticon)? onStickerPressed; final List Function(String text)? - searchDelegate; + searchDelegate; final Future Function(GifSearchResult emoticon)? onGifPressed; final Future Function(FavoriteGif gif)? onFavoritePicked; final Axis packListAxis; @@ -54,17 +54,23 @@ class _EmoticonPickerState extends State with TickerProviderStateMixin { late TabController controller; PageStorageBucket bucket = PageStorageBucket(); - String get labelEmojiPickerEmojiTab => Intl.message("Emoji", - desc: "Label for the emoji tab in emoji picker", - name: "labelEmojiPickerEmojiTab"); - - String get labelEmojiPickerStickerTab => Intl.message("Sticker", - desc: "Label for the sticker tab in the emoji picker", - name: "labelEmojiPickerStickerTab"); - - String get labelEmojiPickerGifTab => Intl.message("Gif", - desc: "Label for the gif search tab in the emoji picker", - name: "labelEmojiPickerGifTab"); + String get labelEmojiPickerEmojiTab => Intl.message( + "Emoji", + desc: "Label for the emoji tab in emoji picker", + name: "labelEmojiPickerEmojiTab", + ); + + String get labelEmojiPickerStickerTab => Intl.message( + "Sticker", + desc: "Label for the sticker tab in the emoji picker", + name: "labelEmojiPickerStickerTab", + ); + + String get labelEmojiPickerGifTab => Intl.message( + "Gif", + desc: "Label for the gif search tab in the emoji picker", + name: "labelEmojiPickerGifTab", + ); List favorites = []; StreamSubscription? sub; @@ -109,68 +115,70 @@ class _EmoticonPickerState extends State mainAxisSize: MainAxisSize.min, children: [ Expanded( - child: TabBarView(controller: controller, children: [ - Tab( - child: EmojiPicker( - widget.emoji, - focus: widget.emojiSearchFocus, - searchDelegate: (value) => widget.searchDelegate! - .call(value) - .where((i) => i.emoticon.isEmoji) - .toList(), - onlyEmoji: true, - onEmoticonPressed: (emoticon) => - widget.onEmojiPressed?.call(emoticon), - ), - ), - if (widget.stickers.isNotEmpty) + child: TabBarView( + controller: controller, + children: [ Tab( child: EmojiPicker( - widget.stickers, - focus: widget.stickerSearchFocus, + widget.emoji, + focus: widget.emojiSearchFocus, searchDelegate: (value) => widget.searchDelegate! .call(value) - .where((i) => i.emoticon.isSticker) + .where((i) => i.emoticon.isEmoji) .toList(), - onlyStickers: true, - size: BuildConfig.MOBILE ? 125 : 125, + onlyEmoji: true, onEmoticonPressed: (emoticon) => - widget.onStickerPressed?.call(emoticon), + widget.onEmojiPressed?.call(emoticon), ), ), - if (widget.allowGifSearch && widget.gifComponent != null) - Tab( - child: GifPicker( - focus: widget.gifSearchFocus, - favorites: widget.gifComponent?.favorites ?? [], - search: widget.gifComponent!.search, - placeholderText: widget.gifComponent!.searchPlaceholder, - favoritePicked: widget.onFavoritePicked, - gifPicked: widget.onGifPressed, - onUnfavoriteGif: (gif) async { - widget.gifComponent?.removeFavorite(gif); - }, + if (widget.stickers.isNotEmpty) + Tab( + child: EmojiPicker( + widget.stickers, + focus: widget.stickerSearchFocus, + searchDelegate: (value) => widget.searchDelegate! + .call(value) + .where((i) => i.emoticon.isSticker) + .toList(), + onlyStickers: true, + size: BuildConfig.MOBILE ? 125 : 125, + onEmoticonPressed: (emoticon) => + widget.onStickerPressed?.call(emoticon), + ), + ), + if (widget.allowGifSearch && widget.gifComponent != null) + Tab( + child: GifPicker( + focus: widget.gifSearchFocus, + favorites: widget.gifComponent?.favorites ?? [], + search: widget.gifComponent!.search, + placeholderText: widget.gifComponent!.searchPlaceholder, + favoritePicked: widget.onFavoritePicked, + gifPicked: widget.onGifPressed, + onUnfavoriteGif: (gif) async { + widget.gifComponent?.removeFavorite(gif); + }, + ), ), - ) - ]), + ], + ), ), if (controller.length > 1) tiamat.Tile.low( child: SizedBox( height: 40, child: TabBar( - controller: controller, - dividerColor: Colors.transparent, - dividerHeight: 0, - tabs: [ - Tab( - text: labelEmojiPickerEmojiTab, - ), - if (widget.stickers.isNotEmpty) - Tab(text: labelEmojiPickerStickerTab), - if (widget.allowGifSearch) - Tab(text: labelEmojiPickerGifTab) - ]), + controller: controller, + dividerColor: Colors.transparent, + dividerHeight: 0, + tabs: [ + Tab(text: labelEmojiPickerEmojiTab), + if (widget.stickers.isNotEmpty) + Tab(text: labelEmojiPickerStickerTab), + if (widget.allowGifSearch) + Tab(text: labelEmojiPickerGifTab), + ], + ), ), ), ], diff --git a/commet/lib/ui/molecules/expanding_drop_target.dart b/commet/lib/ui/molecules/expanding_drop_target.dart index 1ebff5a22..945304eb6 100644 --- a/commet/lib/ui/molecules/expanding_drop_target.dart +++ b/commet/lib/ui/molecules/expanding_drop_target.dart @@ -3,15 +3,16 @@ import 'dart:math'; import 'package:flutter/material.dart'; class ExpandingDropTarget extends StatefulWidget { - const ExpandingDropTarget( - {this.position, - this.min = 70, - this.max = 200, - this.height = 30, - super.key, - this.onAcceptWithDetails, - this.distanceBasedHeight = true, - required this.onWillAcceptWithDetails}); + const ExpandingDropTarget({ + this.position, + this.min = 70, + this.max = 200, + this.height = 30, + super.key, + this.onAcceptWithDetails, + this.distanceBasedHeight = true, + required this.onWillAcceptWithDetails, + }); final Offset? position; final double min; final double max; @@ -37,8 +38,13 @@ class _ExpandingDropTargetState } double remapRange( - double value, double low1, double high1, double low2, double high2, - {bool clamp = true}) { + double value, + double low1, + double high1, + double low2, + double high2, { + bool clamp = true, + }) { if (clamp) { value = value.clamp(low1, high1); } @@ -67,8 +73,10 @@ class _ExpandingDropTargetState dragPosition = widget.position; if (dragPosition != null) { - var dist = min((position.dy - dragPosition!.dy).abs(), - ((position.dy + box!.size.height) - dragPosition!.dy).abs()); + var dist = min( + (position.dy - dragPosition!.dy).abs(), + ((position.dy + box!.size.height) - dragPosition!.dy).abs(), + ); distance = remapRange(dist, widget.min, widget.max, 1, 0); } else { @@ -104,18 +112,20 @@ class _ExpandingDropTargetState key: key, height: widget.distanceBasedHeight ? distance == null - ? 0 - : (distance! * widget.height) + ? 0 + : (distance! * widget.height) : widget.height, width: 50, child: Container( decoration: BoxDecoration( - border: BoxBorder.all( - color: isInside - ? ColorScheme.of(context).secondary - : Colors.transparent, - width: 3), - borderRadius: BorderRadius.circular(8)), + border: BoxBorder.all( + color: isInside + ? ColorScheme.of(context).secondary + : Colors.transparent, + width: 3, + ), + borderRadius: BorderRadius.circular(8), + ), ), ), ); diff --git a/commet/lib/ui/molecules/file_preview.dart b/commet/lib/ui/molecules/file_preview.dart index d5137d2cf..5975b6999 100644 --- a/commet/lib/ui/molecules/file_preview.dart +++ b/commet/lib/ui/molecules/file_preview.dart @@ -11,12 +11,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; class FilePreview extends StatefulWidget { - const FilePreview( - {required this.mimeType, - this.path, - this.data, - this.videoController, - super.key}); + const FilePreview({ + required this.mimeType, + this.path, + this.data, + this.videoController, + super.key, + }); final String? mimeType; final String? path; final Uint8List? data; @@ -76,8 +77,6 @@ class _FilePreviewState extends State { controller: widget.videoController, ); } - return const SizedBox( - height: 0, - ); + return const SizedBox(height: 0); } } diff --git a/commet/lib/ui/molecules/gif_picker.dart b/commet/lib/ui/molecules/gif_picker.dart index b5a8f4cfb..d363b540c 100644 --- a/commet/lib/ui/molecules/gif_picker.dart +++ b/commet/lib/ui/molecules/gif_picker.dart @@ -9,19 +9,21 @@ import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:intl/intl.dart'; import 'package:tiamat/tiamat.dart' as tiamat; + import '../../utils/debounce.dart'; import '../../client/components/gif/gif_search_result.dart'; class GifPicker extends StatefulWidget { - const GifPicker( - {super.key, - this.gifPicked, - this.search, - this.focus, - this.favorites = const [], - this.favoritePicked, - this.onUnfavoriteGif, - this.placeholderText = "Search Gif"}); + const GifPicker({ + super.key, + this.gifPicked, + this.search, + this.focus, + this.favorites = const [], + this.favoritePicked, + this.onUnfavoriteGif, + this.placeholderText = "Search Gif", + }); final List favorites; final Future Function(GifSearchResult gif)? gifPicked; final Future Function(FavoriteGif gif)? favoritePicked; @@ -35,10 +37,10 @@ class GifPicker extends StatefulWidget { State createState() => _GifPickerState(); static String get promptUnfavoriteGif => Intl.message( - "Unfavorite GIF", - desc: "Prompt the user remove a gif from favorites", - name: "promptUnfavoriteGif", - ); + "Unfavorite GIF", + desc: "Prompt the user remove a gif from favorites", + name: "promptUnfavoriteGif", + ); } class _GifPickerState extends State { @@ -98,29 +100,35 @@ class _GifPickerState extends State { @override Widget build(BuildContext context) { - return Stack(children: [ - buildContent(context), - IgnorePointer( - ignoring: !sending, - child: AnimatedOpacity( - opacity: sending ? 1 : 0, - duration: const Duration(milliseconds: 100), - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 2, sigmaY: 2, tileMode: TileMode.repeated), - child: Container( - color: Colors.black.withAlpha(100), - child: const Center( + return Stack( + children: [ + buildContent(context), + IgnorePointer( + ignoring: !sending, + child: AnimatedOpacity( + opacity: sending ? 1 : 0, + duration: const Duration(milliseconds: 100), + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 2, + sigmaY: 2, + tileMode: TileMode.repeated, + ), + child: Container( + color: Colors.black.withAlpha(100), + child: const Center( child: SizedBox( - width: 50, - height: 50, - child: CircularProgressIndicator(), - )), + width: 50, + height: 50, + child: CircularProgressIndicator(), + ), + ), + ), ), ), ), - ), - ]); + ], + ); } Widget buildContent(BuildContext context) { @@ -136,16 +144,18 @@ class _GifPickerState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( - height: BuildConfig.DESKTOP ? 30 : null, - child: TextField( - controller: _textController, - focusNode: widget.focus, - decoration: InputDecoration( - icon: const Icon(Icons.search), - isDense: true, - border: InputBorder.none, - hintText: widget.placeholderText), - )), + height: BuildConfig.DESKTOP ? 30 : null, + child: TextField( + controller: _textController, + focusNode: widget.focus, + decoration: InputDecoration( + icon: const Icon(Icons.search), + isDense: true, + border: InputBorder.none, + hintText: widget.placeholderText, + ), + ), + ), ), ); } @@ -153,97 +163,95 @@ class _GifPickerState extends State { Widget buildSearch(BuildContext context) { if (!searching) { return Expanded( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: MasonryGridView.extent( - maxCrossAxisExtent: 300, - mainAxisSpacing: 8, - padding: EdgeInsetsGeometry.all(0), - crossAxisSpacing: 8, - itemCount: widget.favorites.length, - itemBuilder: (context, index) { - var result = widget.favorites.elementAt(index); - return AdaptiveContextMenu( - items: [ - tiamat.ContextMenuItem( - text: GifPicker.promptUnfavoriteGif, - icon: Icons.heart_broken, - onPressed: () { - widget.onUnfavoriteGif?.call(result); - }, - ), - ], - child: MouseRegion( - cursor: SystemMouseCursors.click, - child: GestureDetector( - onTap: () => sendFavoriteGif(result), - child: ClipRRect( - borderRadius: BorderRadius.circular(8), - child: Container( - color: ColorScheme.of(context).surfaceContainerLowest, - child: AspectRatio( - aspectRatio: result.width / result.height, - child: SizedBox( - child: Image( - fit: BoxFit.fill, - filterQuality: FilterQuality.medium, - image: result.image, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: MasonryGridView.extent( + maxCrossAxisExtent: 300, + mainAxisSpacing: 8, + padding: EdgeInsetsGeometry.all(0), + crossAxisSpacing: 8, + itemCount: widget.favorites.length, + itemBuilder: (context, index) { + var result = widget.favorites.elementAt(index); + return AdaptiveContextMenu( + items: [ + tiamat.ContextMenuItem( + text: GifPicker.promptUnfavoriteGif, + icon: Icons.heart_broken, + onPressed: () { + widget.onUnfavoriteGif?.call(result); + }, + ), + ], + child: MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () => sendFavoriteGif(result), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Container( + color: ColorScheme.of(context).surfaceContainerLowest, + child: AspectRatio( + aspectRatio: result.width / result.height, + child: SizedBox( + child: Image( + fit: BoxFit.fill, + filterQuality: FilterQuality.medium, + image: result.image, + ), ), ), ), ), ), ), - ), - ); - }, + ); + }, + ), ), - )); + ); } if (searchResult == null) - return const Expanded( - child: Center( - child: CircularProgressIndicator(), - ), - ); + return const Expanded(child: Center(child: CircularProgressIndicator())); return Expanded( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: MasonryGridView.extent( - maxCrossAxisExtent: 300, - mainAxisSpacing: 8, - padding: EdgeInsetsGeometry.all(0), - crossAxisSpacing: 8, - itemCount: searchResult!.length, - itemBuilder: (context, index) { - var result = searchResult!.elementAt(index); - return MouseRegion( - cursor: SystemMouseCursors.click, - child: GestureDetector( - onTap: () => sendGif(result), - child: ClipRRect( - borderRadius: BorderRadius.circular(8), - child: Container( - color: ColorScheme.of(context).surfaceContainerLowest, - child: AspectRatio( - aspectRatio: result.x / result.y, - child: SizedBox( - child: Image( - fit: BoxFit.fill, - filterQuality: FilterQuality.medium, - image: NetworkImage(result.previewUrl.toString()), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: MasonryGridView.extent( + maxCrossAxisExtent: 300, + mainAxisSpacing: 8, + padding: EdgeInsetsGeometry.all(0), + crossAxisSpacing: 8, + itemCount: searchResult!.length, + itemBuilder: (context, index) { + var result = searchResult!.elementAt(index); + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () => sendGif(result), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Container( + color: ColorScheme.of(context).surfaceContainerLowest, + child: AspectRatio( + aspectRatio: result.x / result.y, + child: SizedBox( + child: Image( + fit: BoxFit.fill, + filterQuality: FilterQuality.medium, + image: NetworkImage(result.previewUrl.toString()), + ), ), ), ), ), ), - ), - ); - }, + ); + }, + ), ), - )); + ); } void sendGif(GifSearchResult gif) { @@ -251,9 +259,13 @@ class _GifPickerState extends State { sending = true; }); - widget.gifPicked?.call(gif).then((value) => setState(() { - sending = false; - })); + widget.gifPicked + ?.call(gif) + .then( + (value) => setState(() { + sending = false; + }), + ); } void sendFavoriteGif(FavoriteGif gif) { diff --git a/commet/lib/ui/molecules/image_picker.dart b/commet/lib/ui/molecules/image_picker.dart index d0b9079bd..c2855c3f9 100644 --- a/commet/lib/ui/molecules/image_picker.dart +++ b/commet/lib/ui/molecules/image_picker.dart @@ -7,16 +7,17 @@ import 'package:tiamat/tiamat.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class ImagePickerButton extends StatefulWidget { - const ImagePickerButton( - {super.key, - this.currentImage, - this.onImagePicked, - this.onImageRead, - this.size = 128, - this.cropAspectRatio, - this.tooltip = "Pick Image", - this.withData = false, - this.icon}); + const ImagePickerButton({ + super.key, + this.currentImage, + this.onImagePicked, + this.onImageRead, + this.size = 128, + this.cropAspectRatio, + this.tooltip = "Pick Image", + this.withData = false, + this.icon, + }); final ImageProvider? currentImage; final bool withData; final double? cropAspectRatio; @@ -25,7 +26,7 @@ class ImagePickerButton extends StatefulWidget { final IconData? icon; final Function(String filepath)? onImagePicked; final Function(Uint8List bytes, String? mimeType, String filePath)? - onImageRead; + onImageRead; @override State createState() => _ImagePickerButtonState(); @@ -55,8 +56,10 @@ class _ImagePickerButtonState extends State { } void pickImage() async { - var result = await PickerUtils.pickImageAndCrop(context, - aspectRatio: widget.cropAspectRatio); + var result = await PickerUtils.pickImageAndCrop( + context, + aspectRatio: widget.cropAspectRatio, + ); if (result == null) return; diff --git a/commet/lib/ui/molecules/image_select_dialog.dart b/commet/lib/ui/molecules/image_select_dialog.dart index 4f8069557..30ac7cfcb 100644 --- a/commet/lib/ui/molecules/image_select_dialog.dart +++ b/commet/lib/ui/molecules/image_select_dialog.dart @@ -5,11 +5,7 @@ import 'package:intl/intl.dart'; import 'package:commet/utils/common_strings.dart'; import 'package:tiamat/tiamat.dart' as tiamat; -enum ImageEditAction { - cancel, - remove, - pick, -} +enum ImageEditAction { cancel, remove, pick } class ImageSelectDialog extends StatelessWidget { static Future show( @@ -42,24 +38,35 @@ class ImageSelectDialog extends StatelessWidget { required this.onPick, }); - static String get changeImageDialogTitle => Intl.message("Change Image", - name: "changeImageDialogTitle", - desc: "Title for the dialog used to change an image"); + static String get changeImageDialogTitle => Intl.message( + "Change Image", + name: "changeImageDialogTitle", + desc: "Title for the dialog used to change an image", + ); - String get removeImagePrompt => Intl.message("Remove Image", - name: "removeImagePrompt", desc: "Button text for removing an image"); + String get removeImagePrompt => Intl.message( + "Remove Image", + name: "removeImagePrompt", + desc: "Button text for removing an image", + ); - String get pickImagePrompt => Intl.message("Pick Image", - name: "pickImagePrompt", desc: "Button text for picking an image"); + String get pickImagePrompt => Intl.message( + "Pick Image", + name: "pickImagePrompt", + desc: "Button text for picking an image", + ); - String get confirmRemovePrompt => - Intl.message("Are you sure you want to remove this image?", - name: "confirmRemovePrompt", - desc: "Prompt text for confirming image removal"); + String get confirmRemovePrompt => Intl.message( + "Are you sure you want to remove this image?", + name: "confirmRemovePrompt", + desc: "Prompt text for confirming image removal", + ); - String get emptyImagePrompt => Intl.message("No image set", - name: "emptyImagePrompt", - desc: "Text shown when there is no image to display"); + String get emptyImagePrompt => Intl.message( + "No image set", + name: "emptyImagePrompt", + desc: "Text shown when there is no image to display", + ); final ImageProvider? image; final VoidCallback onCancel; @@ -89,10 +96,7 @@ class ImageSelectDialog extends StatelessWidget { ), ), Expanded( - child: tiamat.Button( - text: pickImagePrompt, - onTap: onPick, - ), + child: tiamat.Button(text: pickImagePrompt, onTap: onPick), ), ], ); @@ -102,10 +106,7 @@ class ImageSelectDialog extends StatelessWidget { spacing: 8, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - tiamat.Button( - text: pickImagePrompt, - onTap: onPick, - ), + tiamat.Button(text: pickImagePrompt, onTap: onPick), tiamat.Button( text: removeImagePrompt, type: tiamat.ButtonType.danger, @@ -138,16 +139,11 @@ class ImageSelectDialog extends StatelessWidget { decoration: BoxDecoration( color: Theme.of(context).colorScheme.surfaceContainerLow, image: image != null - ? DecorationImage( - image: image!, - fit: BoxFit.cover, - ) + ? DecorationImage(image: image!, fit: BoxFit.cover) : null, ), child: image == null - ? Center( - child: tiamat.Text.labelLow(emptyImagePrompt), - ) + ? Center(child: tiamat.Text.labelLow(emptyImagePrompt)) : null, ), ), @@ -169,9 +165,7 @@ class ImageSelectDialog extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.stretch, spacing: 12, children: [ - tiamat.Text.body( - confirmRemovePrompt, - ), + tiamat.Text.body(confirmRemovePrompt), Row( spacing: 8, children: [ diff --git a/commet/lib/ui/molecules/invitation_display.dart b/commet/lib/ui/molecules/invitation_display.dart index 6444e1c66..c73f3a436 100644 --- a/commet/lib/ui/molecules/invitation_display.dart +++ b/commet/lib/ui/molecules/invitation_display.dart @@ -5,8 +5,12 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; class InvitationDisplay extends StatefulWidget { - const InvitationDisplay(this.invitation, - {super.key, this.acceptInvitation, this.rejectInvitation}); + const InvitationDisplay( + this.invitation, { + super.key, + this.acceptInvitation, + this.rejectInvitation, + }); final Invitation invitation; final Future Function(Invitation invite)? acceptInvitation; final Future Function(Invitation invite)? rejectInvitation; @@ -17,11 +21,11 @@ class InvitationDisplay extends StatefulWidget { class _InvitationDisplayState extends State { String labelInvitationBodyWithSender(String user) => Intl.message( - "$user invited you to a room", - desc: - "Message body for when an invitation was received, and we have a name for the sender", - args: [user], - name: "labelInvitationBodyWithSender"); + "$user invited you to a room", + desc: "Message body for when an invitation was received, and we have a name for the sender", + args: [user], + name: "labelInvitationBodyWithSender", + ); @override Widget build(BuildContext context) { diff --git a/commet/lib/ui/molecules/message.dart b/commet/lib/ui/molecules/message.dart index b3751b468..b2aa3d574 100644 --- a/commet/lib/ui/molecules/message.dart +++ b/commet/lib/ui/molecules/message.dart @@ -14,28 +14,29 @@ import 'package:flutter/material.dart' as material; import 'package:intl/intl.dart' as intl; class Message extends StatefulWidget { - const Message( - {super.key, - required this.senderName, - required this.senderColor, - required this.sentTimeStamp, - required this.body, - required this.currentUserIdentifier, - this.senderAvatar, - this.replyBody, - this.replySenderColor, - this.replySenderName, - this.edited = false, - this.showDetailed = false, - this.onDoubleTap, - this.reactions, - this.onReactionTapped, - this.onLongPress, - this.links, - this.loadingUrlPreviews = false, - this.isInReply = false, - this.child, - this.showSender = true}); + const Message({ + super.key, + required this.senderName, + required this.senderColor, + required this.sentTimeStamp, + required this.body, + required this.currentUserIdentifier, + this.senderAvatar, + this.replyBody, + this.replySenderColor, + this.replySenderName, + this.edited = false, + this.showDetailed = false, + this.onDoubleTap, + this.reactions, + this.onReactionTapped, + this.onLongPress, + this.links, + this.loadingUrlPreviews = false, + this.isInReply = false, + this.child, + this.showSender = true, + }); final double avatarSize = 32; final bool showSender; @@ -76,21 +77,24 @@ class _MessageState extends State { bool hovered = false; bool editMode = false; - String get messageEditedMarker => Intl.message("(Edited)", - name: "messageEditedMarker", - desc: "Short text to mark that a message has been edited"); + String get messageEditedMarker => Intl.message( + "(Edited)", + name: "messageEditedMarker", + desc: "Short text to mark that a message has been edited", + ); @override Widget build(BuildContext context) { return material.Material( - color: material.Colors.transparent, - child: BuildConfig.MOBILE - ? material.InkWell( - onLongPress: widget.onLongPress, - onDoubleTap: widget.onDoubleTap, - child: buildContent(), - ) - : buildContent()); + color: material.Colors.transparent, + child: BuildConfig.MOBILE + ? material.InkWell( + onLongPress: widget.onLongPress, + onDoubleTap: widget.onDoubleTap, + child: buildContent(), + ) + : buildContent(), + ); } @override @@ -121,10 +125,7 @@ class _MessageState extends State { padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - senderName(), - timeStamp(), - ], + children: [senderName(), timeStamp()], ), ), body(), @@ -136,7 +137,7 @@ class _MessageState extends State { ], ), ), - ) + ), ], ), ], @@ -192,15 +193,14 @@ class _MessageState extends State { textBaseline: TextBaseline.ideographic, mainAxisAlignment: MainAxisAlignment.start, children: [ - SizedBox( - width: widget.avatarSize / 2, - ), + SizedBox(width: widget.avatarSize / 2), SizedBox( width: 30, height: 20, child: CustomPaint( painter: ReplyLinePainter( - pathColor: Theme.of(context).colorScheme.secondary), + pathColor: Theme.of(context).colorScheme.secondary, + ), ), ), tiamat.Text.name( @@ -217,7 +217,7 @@ class _MessageState extends State { color: material.Theme.of(context).colorScheme.secondary, ), ), - ) + ), ], ), ); @@ -225,21 +225,23 @@ class _MessageState extends State { Widget timeStamp() { return Padding( - padding: const EdgeInsets.fromLTRB(4, 0, 4, 0), - child: SizedBox( - child: tiamat.Text.labelLow(widget.showDetailed - ? MediaQuery.of(context).alwaysUse24HourFormat - ? intl.DateFormat.yMMMMd() - .add_Hms() - .format(widget.sentTimeStamp.toLocal()) - : intl.DateFormat.yMMMMd() - .add_jms() - .format(widget.sentTimeStamp.toLocal()) - : MediaQuery.of(context).alwaysUse24HourFormat - ? intl.DateFormat.Hm() - .format(widget.sentTimeStamp.toLocal()) - : intl.DateFormat.jm() - .format(widget.sentTimeStamp.toLocal())))); + padding: const EdgeInsets.fromLTRB(4, 0, 4, 0), + child: SizedBox( + child: tiamat.Text.labelLow( + widget.showDetailed + ? MediaQuery.of(context).alwaysUse24HourFormat + ? intl.DateFormat.yMMMMd().add_Hms().format( + widget.sentTimeStamp.toLocal(), + ) + : intl.DateFormat.yMMMMd().add_jms().format( + widget.sentTimeStamp.toLocal(), + ) + : MediaQuery.of(context).alwaysUse24HourFormat + ? intl.DateFormat.Hm().format(widget.sentTimeStamp.toLocal()) + : intl.DateFormat.jm().format(widget.sentTimeStamp.toLocal()), + ), + ), + ); } Widget body() { @@ -252,17 +254,19 @@ class _MessageState extends State { Widget reactions() { return Wrap( - spacing: 3, - runSpacing: 3, - direction: material.Axis.horizontal, - children: widget.reactions!.keys.map((key) { - var value = widget.reactions![key]!; - return EmojiReaction( - emoji: key, - onTapped: widget.onReactionTapped, - numReactions: value.length, - highlighted: value.contains(widget.currentUserIdentifier)); - }).toList()); + spacing: 3, + runSpacing: 3, + direction: material.Axis.horizontal, + children: widget.reactions!.keys.map((key) { + var value = widget.reactions![key]!; + return EmojiReaction( + emoji: key, + onTapped: widget.onReactionTapped, + numReactions: value.length, + highlighted: value.contains(widget.currentUserIdentifier), + ); + }).toList(), + ); } } @@ -271,11 +275,12 @@ class ReplyLinePainter extends CustomPainter { double strokeWidth; double radius; double padding; - ReplyLinePainter( - {this.pathColor = Colors.white, - this.strokeWidth = 2, - this.radius = 3, - this.padding = 2}) { + ReplyLinePainter({ + this.pathColor = Colors.white, + this.strokeWidth = 2, + this.radius = 3, + this.padding = 2, + }) { _paint = Paint() ..color = pathColor ..style = PaintingStyle.stroke @@ -290,8 +295,10 @@ class ReplyLinePainter extends CustomPainter { Path path = Path(); path.moveTo(0, size.height - padding); path.lineTo(0, (size.height / 2) + radius); - path.relativeArcToPoint(Offset(radius, -radius), - radius: Radius.circular(radius)); + path.relativeArcToPoint( + Offset(radius, -radius), + radius: Radius.circular(radius), + ); path.lineTo(size.width - 5, size.height / 2); canvas.drawPath(path, _paint); } @@ -307,11 +314,12 @@ class ThreadLinePainter extends CustomPainter { double strokeWidth; double radius; double padding; - ThreadLinePainter( - {this.pathColor = Colors.white, - this.strokeWidth = 1.5, - this.radius = 3, - this.padding = 2}) { + ThreadLinePainter({ + this.pathColor = Colors.white, + this.strokeWidth = 1.5, + this.radius = 3, + this.padding = 2, + }) { _paint = Paint() ..color = pathColor ..style = PaintingStyle.stroke diff --git a/commet/lib/ui/molecules/message_input.dart b/commet/lib/ui/molecules/message_input.dart index 93cc7fadb..d8df88b9f 100644 --- a/commet/lib/ui/molecules/message_input.dart +++ b/commet/lib/ui/molecules/message_input.dart @@ -36,6 +36,7 @@ import 'package:just_the_tooltip/just_the_tooltip.dart'; import 'package:matrix/matrix.dart' as matrix; import 'package:pasteboard/pasteboard.dart'; import 'package:tiamat/tiamat.dart' as tiamat; + import '../../client/attachment.dart'; import '../../client/components/emoticon/emoticon.dart'; @@ -47,61 +48,68 @@ class AttachmentPicker { Function() execute; - AttachmentPicker( - {required this.icon, required this.label, required this.execute}); + AttachmentPicker({ + required this.icon, + required this.label, + required this.execute, + }); } class MessageInput extends StatefulWidget { - const MessageInput( - {super.key, - required this.client, - this.room, - this.maxHeight = 200, - this.onSendMessage, - this.isRoomE2EE = false, - this.onFocusChanged, - this.readIndicator, - this.relatedEventBody, - this.relatedEventSenderColor, - this.relatedEventSenderName, - this.interactionType, - this.focusKeyboard, - this.setInputText, - this.isProcessing = false, - this.initialText, - this.enabled = true, - this.editLastMessage, - this.hintText, - this.attachments, - this.addAttachment, - this.onTextUpdated, - this.removeAttachment, - this.typingIndicatorWidget, - this.availibleEmoticons, - this.availibleStickers, - this.compact = false, - this.gifComponent, - this.enableKeyboardAdapter = true, - this.onReadReceiptsClicked, - this.findOverrideClient, - this.onTapOverrideClient, - this.disableEnterToSend = false, - this.sendGif, - this.sendFavoriteGif, - this.showGifSearch = true, - this.size = 35, - this.iconScale = 0.5, - this.showAttachmentButton = true, - this.sendSticker, - this.processAutofill, - this.cancelReply}); + const MessageInput({ + super.key, + required this.client, + this.room, + this.maxHeight = 200, + this.onSendMessage, + this.isRoomE2EE = false, + this.onFocusChanged, + this.readIndicator, + this.relatedEventBody, + this.relatedEventSenderColor, + this.relatedEventSenderName, + this.interactionType, + this.focusKeyboard, + this.setInputText, + this.isProcessing = false, + this.initialText, + this.enabled = true, + this.editLastMessage, + this.hintText, + this.attachments, + this.addAttachment, + this.onTextUpdated, + this.removeAttachment, + this.typingIndicatorWidget, + this.availibleEmoticons, + this.availibleStickers, + this.compact = false, + this.gifComponent, + this.enableKeyboardAdapter = true, + this.onReadReceiptsClicked, + this.findOverrideClient, + this.onTapOverrideClient, + this.disableEnterToSend = false, + this.sendGif, + this.sendFavoriteGif, + this.showGifSearch = true, + this.size = 35, + this.iconScale = 0.5, + this.showAttachmentButton = true, + this.sendSticker, + this.processAutofill, + this.cancelReply, + }); final double maxHeight; final double size; final double iconScale; final bool isRoomE2EE; final bool disableEnterToSend; - final MessageInputSendResult Function(String message, - {Client? overrideClient})? onSendMessage; + final MessageInputSendResult Function( + String message, { + Client? overrideClient, + })? + onSendMessage; final Widget? readIndicator; final String? relatedEventBody; final String? relatedEventSenderName; @@ -179,8 +187,10 @@ class MessageInputState extends State { void onSetInputText(String newText) { controller.text = newText; - controller.selection = - TextSelection(baseOffset: newText.length, extentOffset: newText.length); + controller.selection = TextSelection( + baseOffset: newText.length, + extentOffset: newText.length, + ); onTextfieldUpdated(newText); } @@ -199,10 +209,14 @@ class MessageInputState extends State { @override void initState() { controller = RichTextEditingController( - client: widget.client, room: widget.room, text: widget.initialText); + client: widget.client, + room: widget.room, + text: widget.initialText, + ); controller.addListener(controllerListener); - keyboardFocusSubscription = - widget.focusKeyboard?.listen((_) => onKeyboardFocusRequested()); + keyboardFocusSubscription = widget.focusKeyboard?.listen( + (_) => onKeyboardFocusRequested(), + ); setInputTextSubscription = widget.setInputText?.listen(onSetInputText); onScopePopInvoked = EventBus.onPopInvoked.stream.listen(onPopped); @@ -210,8 +224,9 @@ class MessageInputState extends State { textFocus = FocusNode(onKeyEvent: onKey); textFocus.addListener(onTextFocusChanged); - preferencesSubscription = - preferences.onSettingChanged.listen((_) => setState(() {})); + preferencesSubscription = preferences.onSettingChanged.listen( + (_) => setState(() {}), + ); if (preferences.autoFocusMessageTextBox.value) { WidgetsBinding.instance.addPostFrameCallback((_) { @@ -329,8 +344,10 @@ class MessageInputState extends State { if (controller.text.trim().isEmpty) return; } - var result = widget.onSendMessage - ?.call(controller.text.trim(), overrideClient: senderOverride); + var result = widget.onSendMessage?.call( + controller.text.trim(), + overrideClient: senderOverride, + ); if (result == MessageInputSendResult.success) { controller.text = ""; @@ -341,8 +358,9 @@ class MessageInputState extends State { void showMoreAttachmentOptions() {} // This duration is to try and hide the transition from keyboard popup animation - Debouncer removeHeightOverrideDebouncer = - Debouncer(delay: Duration(seconds: 1)); + Debouncer removeHeightOverrideDebouncer = Debouncer( + delay: Duration(seconds: 1), + ); bool get isInEmojiPicker => showEmotePicker && !textFocus.hasFocus; @@ -465,9 +483,11 @@ class MessageInputState extends State { autofillScrollController.position.viewportDimension * 0.25; if (distance > maxDistance) { - autofillScrollController.animateTo(offset, - duration: const Duration(milliseconds: 200), - curve: Curves.easeInOutExpo); + autofillScrollController.animateTo( + offset, + duration: const Duration(milliseconds: 200), + curve: Curves.easeInOutExpo, + ); } } @@ -494,11 +514,13 @@ class MessageInputState extends State { return; } - var startFill = - getAutofillTextRange(cursorPosition: controller.selection.baseOffset); + var startFill = getAutofillTextRange( + cursorPosition: controller.selection.baseOffset, + ); - var endFill = - getAutofillTextRange(cursorPosition: controller.selection.extentOffset); + var endFill = getAutofillTextRange( + cursorPosition: controller.selection.extentOffset, + ); var len = controller.selection.start - controller.selection.end; @@ -540,8 +562,10 @@ class MessageInputState extends State { if (len == 0) { extentOffset = baseOffset; } - controller.selection = - TextSelection(baseOffset: baseOffset, extentOffset: extentOffset); + controller.selection = TextSelection( + baseOffset: baseOffset, + extentOffset: extentOffset, + ); prevSelection = controller.selection; } @@ -550,8 +574,9 @@ class MessageInputState extends State { if (BuildConfig.MOBILE) return KeyEventResult.ignored; if (!preferences.disableTextCursorManagement.value) { - if (HardwareKeyboard.instance - .isLogicalKeyPressed(LogicalKeyboardKey.backspace)) { + if (HardwareKeyboard.instance.isLogicalKeyPressed( + LogicalKeyboardKey.backspace, + )) { var selection = controller.selection.baseOffset; var selectionEnd = controller.selection.extentOffset; @@ -568,16 +593,20 @@ class MessageInputState extends State { var text = controller.text.substring(range.$1, range.$2); if (isKnownAutofillMatch(text)) { - controller.text = - controller.text.replaceRange(selection, selectionEnd, ""); + controller.text = controller.text.replaceRange( + selection, + selectionEnd, + "", + ); onTextfieldUpdated(controller.text); return KeyEventResult.handled; } } } - if (HardwareKeyboard.instance - .isLogicalKeyPressed(LogicalKeyboardKey.keyV)) { + if (HardwareKeyboard.instance.isLogicalKeyPressed( + LogicalKeyboardKey.keyV, + )) { if (HardwareKeyboard.instance.isControlPressed) { readImageFromClipboard(); return KeyEventResult.ignored; @@ -610,8 +639,9 @@ class MessageInputState extends State { } if (widget.disableEnterToSend != true) { - if (HardwareKeyboard.instance - .isLogicalKeyPressed(LogicalKeyboardKey.enter)) { + if (HardwareKeyboard.instance.isLogicalKeyPressed( + LogicalKeyboardKey.enter, + )) { if (autoFillSelection != null && autoFillRange != null) { applyAutoFill(autoFillResults![autoFillSelection!]); return KeyEventResult.handled; @@ -626,14 +656,16 @@ class MessageInputState extends State { } } - if (HardwareKeyboard.instance - .isLogicalKeyPressed(LogicalKeyboardKey.escape)) { + if (HardwareKeyboard.instance.isLogicalKeyPressed( + LogicalKeyboardKey.escape, + )) { doCancelInteraction(); return KeyEventResult.handled; } - if (HardwareKeyboard.instance - .isLogicalKeyPressed(LogicalKeyboardKey.arrowUp) && + if (HardwareKeyboard.instance.isLogicalKeyPressed( + LogicalKeyboardKey.arrowUp, + ) && controller.text.isEmpty) { widget.editLastMessage?.call(); } @@ -654,8 +686,11 @@ class MessageInputState extends State { replacement = "$replacement "; } - controller.text = controller.text - .replaceRange(autoFillRange!.$1, autoFillRange!.$2, replacement); + controller.text = controller.text.replaceRange( + autoFillRange!.$1, + autoFillRange!.$2, + replacement, + ); setState(() { autoFillSelection = null; autoFillResults = null; @@ -709,35 +744,36 @@ class MessageInputState extends State { child: Padding( padding: padding, child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.enabled && widget.showAttachmentButton) - addAttachmentButton(), - Flexible( - child: ClipRRect( - borderRadius: BorderRadius.circular(5), - child: Container( - decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .surfaceContainerLow), - child: Row( - crossAxisAlignment: - CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - textInput(context), - if (widget.enabled) toggleEmojiButton(), - ], - ), + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.enabled && widget.showAttachmentButton) + addAttachmentButton(), + Flexible( + child: ClipRRect( + borderRadius: BorderRadius.circular(5), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context) + .colorScheme + .surfaceContainerLow, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + textInput(context), + if (widget.enabled) toggleEmojiButton(), + ], ), ), ), - if (widget.enabled) sendMessageButton() - ]), + ), + if (widget.enabled) sendMessageButton(), + ], + ), ), ), if (!widget.compact) @@ -745,16 +781,16 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.fromLTRB(0, 2, 0, 0), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 30), - if (senderOverride != null) senderOverrideView(), - if (autoFillResults != null) - autofillResultsList(), - if (autoFillResults == null) - const Expanded(child: SizedBox()), - ]), + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 30), + if (senderOverride != null) senderOverrideView(), + if (autoFillResults != null) autofillResultsList(), + if (autoFillResults == null) + const Expanded(child: SizedBox()), + ], + ), ), ), ], @@ -790,21 +826,16 @@ class MessageInputState extends State { padding: const EdgeInsets.all(2), child: Row( children: [ - SizedBox( - width: 5, - ), + SizedBox(width: 5), tiamat.Avatar( - radius: 10, - image: profile.avatar, - placeholderColor: profile.defaultColor, - placeholderText: profile.displayName), - SizedBox( - width: 10, + radius: 10, + image: profile.avatar, + placeholderColor: profile.defaultColor, + placeholderText: profile.displayName, ), + SizedBox(width: 10), tiamat.Text.labelLow("Sending as: ${profile.displayName}"), - SizedBox( - width: 5, - ) + SizedBox(width: 5), ], ), ), @@ -822,14 +853,8 @@ class MessageInputState extends State { return const LinearGradient( begin: Alignment.centerRight, end: Alignment.center, - colors: [ - Colors.purple, - Colors.transparent, - ], - stops: [ - 0.0, - 0.1, - ], + colors: [Colors.purple, Colors.transparent], + stops: [0.0, 0.1], ).createShader(rect); }, blendMode: BlendMode.dstOut, @@ -844,8 +869,11 @@ class MessageInputState extends State { final offset = event.scrollDelta.dy; autofillScrollController.jumpTo( - (autofillScrollController.offset + offset).clamp(0, - autofillScrollController.position.maxScrollExtent)); + (autofillScrollController.offset + offset).clamp( + 0, + autofillScrollController.position.maxScrollExtent, + ), + ); } }, child: ListView.builder( @@ -877,13 +905,18 @@ class MessageInputState extends State { EmojiWidget(data.emoticon), if (data is AutofillSearchResultAvatar) Padding( - padding: - const EdgeInsets.fromLTRB(0, 0, 3, 0), + padding: const EdgeInsets.fromLTRB( + 0, + 0, + 3, + 0, + ), child: tiamat.Avatar( - image: data.image, - radius: 10, - placeholderColor: data.fallbackColor, - placeholderText: data.result), + image: data.image, + radius: 10, + placeholderColor: data.fallbackColor, + placeholderText: data.result, + ), ), tiamat.Text.labelLow( data.result, @@ -914,106 +947,116 @@ class MessageInputState extends State { double targetValue = canSend ? 1 : 0; return Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), - child: TweenAnimationBuilder( - tween: Tween(begin: 0, end: targetValue), - duration: Durations.medium1, - builder: (context, value, child) { - return ClipRRect( - borderRadius: BorderRadiusGeometry.circular(widget.size), - child: Material( - child: AdaptiveContextMenu( - modal: true, - items: canSend - ? List.empty() - : [ - if (pollComponent != null) - tiamat.ContextMenuItem( - text: "Poll", - icon: Icons.poll, - onPressed: () async { - var createArgs = - await AdaptiveDialog.show( - context, - title: "Create Poll", - builder: (context) => PollCreator()); - - if (createArgs != null) { - print(createArgs); - pollComponent.createPoll( - widget.room!, createArgs); - } - }, - ) - ], - child: SizedBox( - width: widget.size, - height: widget.size, - child: tiamat.CircleButton( - icon: canSend ? Icons.send : Icons.more_horiz, - radius: widget.size * widget.iconScale, - onPressed: canSend - ? () { - sendMessage(); + padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), + child: TweenAnimationBuilder( + tween: Tween(begin: 0, end: targetValue), + duration: Durations.medium1, + builder: (context, value, child) { + return ClipRRect( + borderRadius: BorderRadiusGeometry.circular(widget.size), + child: Material( + child: AdaptiveContextMenu( + modal: true, + items: canSend + ? List.empty() + : [ + if (pollComponent != null) + tiamat.ContextMenuItem( + text: "Poll", + icon: Icons.poll, + onPressed: () async { + var createArgs = + await AdaptiveDialog.show( + context, + title: "Create Poll", + builder: (context) => PollCreator(), + ); + + if (createArgs != null) { + print(createArgs); + pollComponent.createPoll( + widget.room!, + createArgs, + ); } - : null, - color: Color.lerp( - Theme.of(context).colorScheme.primary.withAlpha(0), - Theme.of(context).colorScheme.primary, - value), - iconColor: Color.lerp( - Theme.of(context).colorScheme.secondary, - Theme.of(context).colorScheme.onPrimary, - value), - )), + }, + ), + ], + child: SizedBox( + width: widget.size, + height: widget.size, + child: tiamat.CircleButton( + icon: canSend ? Icons.send : Icons.more_horiz, + radius: widget.size * widget.iconScale, + onPressed: canSend + ? () { + sendMessage(); + } + : null, + color: Color.lerp( + Theme.of(context).colorScheme.primary.withAlpha(0), + Theme.of(context).colorScheme.primary, + value, + ), + iconColor: Color.lerp( + Theme.of(context).colorScheme.secondary, + Theme.of(context).colorScheme.onPrimary, + value, + ), + ), ), ), - ); - }, - )); + ), + ); + }, + ), + ); } Widget toggleEmojiButton() { var button = SizedBox( - width: widget.size, - height: widget.size, - child: RandomEmojiButton( - size: widget.size, - onTap: toggleEmojiOverlay, - toggled: MediaQuery.of(context).mobile - ? (emojiTooltipController.value == TooltipStatus.isShowing || - (emotePickerActive == true)) - : false)); + width: widget.size, + height: widget.size, + child: RandomEmojiButton( + size: widget.size, + onTap: toggleEmojiOverlay, + toggled: MediaQuery.of(context).mobile + ? (emojiTooltipController.value == TooltipStatus.isShowing || + (emotePickerActive == true)) + : false, + ), + ); if (MediaQuery.of(context).mobile) return button; return Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 2, 0), - child: JustTheTooltip( - isModal: true, - preferredDirection: AxisDirection.up, - controller: emojiTooltipController, - backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - onDismiss: () { - if (MediaQuery.of(context).desktop) { - textFocus.requestFocus(); - } - }, - content: ClipRRect( - borderRadius: BorderRadiusGeometry.circular(8), - child: Material( - child: Container( - color: Theme.of(context).colorScheme.surfaceContainerLow, - child: SizedBox( - height: 500, - width: 500, - child: buildEmojiPicker(skipIfNeverOpened: false), - ), + padding: const EdgeInsets.fromLTRB(0, 0, 2, 0), + child: JustTheTooltip( + isModal: true, + preferredDirection: AxisDirection.up, + controller: emojiTooltipController, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, + onDismiss: () { + if (MediaQuery.of(context).desktop) { + textFocus.requestFocus(); + } + }, + content: ClipRRect( + borderRadius: BorderRadiusGeometry.circular(8), + child: Material( + child: Container( + color: Theme.of(context).colorScheme.surfaceContainerLow, + child: SizedBox( + height: 500, + width: 500, + child: buildEmojiPicker(skipIfNeverOpened: false), ), ), ), - child: button, - )); + ), + child: button, + ), + ); } Expanded textInput(BuildContext context) { @@ -1038,12 +1081,17 @@ class MessageInputState extends State { keyboardType: TextInputType.multiline, textCapitalization: TextCapitalization.sentences, decoration: InputDecoration( - contentPadding: - EdgeInsets.fromLTRB(8, padding / 2, 4, padding / 2), - border: InputBorder.none, - isDense: true, - hintStyle: hintStyle, - hintText: widget.hintText), + contentPadding: EdgeInsets.fromLTRB( + 8, + padding / 2, + 4, + padding / 2, + ), + border: InputBorder.none, + isDense: true, + hintStyle: hintStyle, + hintText: widget.hintText, + ), ), ), ], @@ -1079,13 +1127,15 @@ class MessageInputState extends State { if (recent != null && recent.isNotEmpty) { availableEmoji.insert( - 0, - DynamicEmoticonPack( - identifier: "dynamic_pack_frequently_used_typing", - displayName: "Frequently Used", - icon: Icons.schedule, - emoticons: recent, - usage: EmoticonUsage.all)); + 0, + DynamicEmoticonPack( + identifier: "dynamic_pack_frequently_used_typing", + displayName: "Frequently Used", + icon: Icons.schedule, + emoticons: recent, + usage: EmoticonUsage.all, + ), + ); } return (!hasEmotePickerOpened && skipIfNeverOpened) @@ -1095,10 +1145,12 @@ class MessageInputState extends State { emojiSearchFocus: emojiSearchFocus, stickerSearchFocus: stickerSearchFocus, gifSearchFocus: gifSearchFocus, - searchDelegate: (search) => AutofillUtils.searchEmoticon(search, - client: widget.client, room: widget.room, limit: 50) - .whereType() - .toList(), + searchDelegate: (search) => AutofillUtils.searchEmoticon( + search, + client: widget.client, + room: widget.room, + limit: 50, + ).whereType().toList(), stickers: widget.availibleStickers ?? [], onEmojiPressed: insertEmoticon, packListAxis: BuildConfig.DESKTOP ? Axis.vertical : Axis.horizontal, @@ -1122,7 +1174,8 @@ class MessageInputState extends State { setState(() { clearKeyboardOverride(debounce: false); }); - }); + }, + ); } Future handlePickedAttachment(PendingFileAttachment attachment) async { @@ -1131,9 +1184,7 @@ class MessageInputState extends State { scrollable: false, context, builder: (context) { - return AttachmentProcessor( - attachment: attachment, - ); + return AttachmentProcessor(attachment: attachment); }, ); @@ -1147,85 +1198,104 @@ class MessageInputState extends State { var pickers = [ if (PlatformUtils.isAndroid) AttachmentPicker( - icon: Icons.photo, - label: "Gallery", - execute: () async { - var picker = ImagePicker(); - var result = await picker.pickMultiImage(); - for (var file in result) { - var data = await file.readAsBytes(); - await handlePickedAttachment(PendingFileAttachment( - name: file.name, - mimeType: file.mimeType, - size: data.lengthInBytes, - data: data)); - } - }), - AttachmentPicker( - icon: Icons.attach_file, - label: "File", + icon: Icons.photo, + label: "Gallery", execute: () async { - FilePickerResult? result = await FilePicker.platform.pickFiles( - type: FileType.any, withData: true, allowMultiple: true); - if (result == null) return; - - for (var file in result.files) { - var attachment = PendingFileAttachment( + var picker = ImagePicker(); + var result = await picker.pickMultiImage(); + for (var file in result) { + var data = await file.readAsBytes(); + await handlePickedAttachment( + PendingFileAttachment( name: file.name, - path: PlatformUtils.isWeb ? null : file.path, - data: file.bytes, - size: file.bytes?.length); - - await handlePickedAttachment(attachment); + mimeType: file.mimeType, + size: data.lengthInBytes, + data: data, + ), + ); } - }), + }, + ), + AttachmentPicker( + icon: Icons.attach_file, + label: "File", + execute: () async { + FilePickerResult? result = await FilePicker.platform.pickFiles( + type: FileType.any, + withData: true, + allowMultiple: true, + ); + if (result == null) return; + + for (var file in result.files) { + var attachment = PendingFileAttachment( + name: file.name, + path: PlatformUtils.isWeb ? null : file.path, + data: file.bytes, + size: file.bytes?.length, + ); + + await handlePickedAttachment(attachment); + } + }, + ), if (PlatformUtils.isAndroid && preferences.developerMode.value) AttachmentPicker( - icon: Icons.perm_media, - label: "Media", - execute: () async { - var picker = ImagePicker(); - var result = await picker.pickMultipleMedia(); - for (var file in result) { - var data = await file.readAsBytes(); - await handlePickedAttachment(PendingFileAttachment( - name: file.name, - mimeType: file.mimeType, - size: data.lengthInBytes, - data: data)); - } - }), - if (PlatformUtils.isAndroid) - AttachmentPicker( - icon: Icons.camera_alt, - label: "Take a photo", - execute: () async { - var picker = ImagePicker(); - var file = await picker.pickImage(source: ImageSource.camera); - if (file == null) return; - + icon: Icons.perm_media, + label: "Media", + execute: () async { + var picker = ImagePicker(); + var result = await picker.pickMultipleMedia(); + for (var file in result) { var data = await file.readAsBytes(); - await handlePickedAttachment(PendingFileAttachment( + await handlePickedAttachment( + PendingFileAttachment( name: file.name, mimeType: file.mimeType, size: data.lengthInBytes, - data: data)); - }), + data: data, + ), + ); + } + }, + ), + if (PlatformUtils.isAndroid) + AttachmentPicker( + icon: Icons.camera_alt, + label: "Take a photo", + execute: () async { + var picker = ImagePicker(); + var file = await picker.pickImage(source: ImageSource.camera); + if (file == null) return; + + var data = await file.readAsBytes(); + await handlePickedAttachment( + PendingFileAttachment( + name: file.name, + mimeType: file.mimeType, + size: data.lengthInBytes, + data: data, + ), + ); + }, + ), ]; if (pickers.length == 1) { pickers.first.execute(); } else { - final picker = await AdaptiveDialog.pickOne(context, - items: pickers, - itemBuilder: (context, item, onTapped) => SizedBox( - height: 50, - child: tiamat.TextButton( - item.label, - icon: item.icon, - onTap: onTapped, - ), - )); + final picker = await AdaptiveDialog.pickOne( + context, + items: pickers, + itemBuilder: (context, item, onTapped) => SizedBox( + height: 50, + child: tiamat.TextButton( + item.label, + icon: item.icon, + onTap: onTapped, + ), + ), + ); picker?.execute(); } @@ -1275,8 +1345,10 @@ class MessageInputState extends State { controller.text = text.replaceRange(start, end, slug); var newOffset = start + slug.length; - controller.selection = - TextSelection(baseOffset: newOffset, extentOffset: newOffset); + controller.selection = TextSelection( + baseOffset: newOffset, + extentOffset: newOffset, + ); } Widget interactionText() { @@ -1295,11 +1367,13 @@ class MessageInputState extends State { onPressed: doCancelInteraction, ), ), - Icon(widget.interactionType == EventInteractionType.reply - ? Icons.keyboard_arrow_right_rounded - : widget.interactionType == EventInteractionType.edit - ? Icons.edit - : null), + Icon( + widget.interactionType == EventInteractionType.reply + ? Icons.keyboard_arrow_right_rounded + : widget.interactionType == EventInteractionType.edit + ? Icons.edit + : null, + ), tiamat.Text.name( widget.relatedEventSenderName!, color: widget.relatedEventSenderColor, @@ -1314,7 +1388,7 @@ class MessageInputState extends State { color: Theme.of(context).colorScheme.secondary, ), ), - ) + ), ], ), ), @@ -1348,7 +1422,9 @@ class MessageInputState extends State { } Widget contextMenuBuilder( - BuildContext buildContext, EditableTextState editableTextState) { + BuildContext buildContext, + EditableTextState editableTextState, + ) { return AdaptiveTextSelectionToolbar.editable( anchors: editableTextState.contextMenuAnchors, clipboardStatus: ClipboardStatus.pasteable, @@ -1375,7 +1451,9 @@ class MessageInputState extends State { // to apply the normal behavior when click on select all onSelectAll: () => editableTextState.selectAll(SelectionChangedCause.toolbar), - onLiveTextInput: null, onLookUp: null, onSearchWeb: null, + onLiveTextInput: null, + onLookUp: null, + onSearchWeb: null, onShare: null, ); } @@ -1386,13 +1464,13 @@ class MessageInputState extends State { return; } - var processedAttachment = - await AdaptiveDialog.show(context, - scrollable: false, - builder: (context) => AttachmentProcessor( - attachment: - PendingFileAttachment(data: image, size: image.length), - )); + var processedAttachment = await AdaptiveDialog.show( + context, + scrollable: false, + builder: (context) => AttachmentProcessor( + attachment: PendingFileAttachment(data: image, size: image.length), + ), + ); if (processedAttachment != null) { setState(() { diff --git a/commet/lib/ui/molecules/notification_debugger.dart b/commet/lib/ui/molecules/notification_debugger.dart index 5c06e9864..048bb2a03 100644 --- a/commet/lib/ui/molecules/notification_debugger.dart +++ b/commet/lib/ui/molecules/notification_debugger.dart @@ -27,8 +27,12 @@ import 'package:window_manager/window_manager.dart'; import 'package:http/http.dart' as http; class NotificationDebugger extends StatefulWidget { - const NotificationDebugger( - {this.event, this.room, required this.client, super.key}); + const NotificationDebugger({ + this.event, + this.room, + required this.client, + super.key, + }); final TimelineEvent? event; final Client client; final Room? room; @@ -41,13 +45,17 @@ class _NotificationDebugStep { String description; bool? passed; - _NotificationDebugStep( - {required this.name, required this.description, required this.passed}); + _NotificationDebugStep({ + required this.name, + required this.description, + required this.passed, + }); } class _NotificationDebuggerState extends State { - NotifyingList<_NotificationDebugStep> steps = - NotifyingList.empty(growable: true); + NotifyingList<_NotificationDebugStep> steps = NotifyingList.empty( + growable: true, + ); bool running = true; @override @@ -83,10 +91,13 @@ class _NotificationDebuggerState extends State { } } } catch (e) { - steps.add(_NotificationDebugStep( + steps.add( + _NotificationDebugStep( name: "Tests failed", description: "An error occured while running tests: ${e}", - passed: false)); + passed: false, + ), + ); } setState(() { running = false; @@ -97,11 +108,14 @@ class _NotificationDebuggerState extends State { var evaluator = room.matrixRoom.client.pushruleEvaluator; var match = evaluator.match(event.event); - steps.add(_NotificationDebugStep( + steps.add( + _NotificationDebugStep( name: "Push Rules", description: "Check if the event matches your account's defined push rules", - passed: match.notify)); + passed: match.notify, + ), + ); } Future checkPermissions() async { @@ -117,10 +131,10 @@ class _NotificationDebuggerState extends State { } var step = _NotificationDebugStep( - name: "Check permissions", - description: - "Tests if we have permission from the system to display a notification", - passed: permission); + name: "Check permissions", + description: "Tests if we have permission from the system to display a notification", + passed: permission, + ); steps.add(step); } @@ -130,49 +144,63 @@ class _NotificationDebuggerState extends State { event, onNotificationRejected: (reason) { var step = _NotificationDebugStep( - name: "Notification rejected", - description: "$reason", - passed: false); + name: "Notification rejected", + description: "$reason", + passed: false, + ); steps.add(step); }, ); var step = _NotificationDebugStep( - name: "Should Notify", - description: - "Tests whether the given event should trigger a notification", - passed: shouldNotify); + name: "Should Notify", + description: + "Tests whether the given event should trigger a notification", + passed: shouldNotify, + ); steps.add(step); } Future checkPushGateway( - MatrixTimelineEvent event, MatrixRoom room) async { + MatrixTimelineEvent event, + MatrixRoom room, + ) async { var matrixClient = (widget.client as MatrixClient).getMatrixClient(); var pushers = await matrixClient.getPushers(); if (BuildConfig.ENABLE_GOOGLE_SERVICES == false) { - steps.add(_NotificationDebugStep( + steps.add( + _NotificationDebugStep( name: "Unified Push Configuration", description: "Checks the current config for unified push", - passed: preferences.unifiedPushEnabled.value == true && - preferences.unifiedPushEndpoint.value != null)); + passed: + preferences.unifiedPushEnabled.value == true && + preferences.unifiedPushEndpoint.value != null, + ), + ); if (preferences.unifiedPushEnabled.value == true) { var distributor = await UnifiedPush.getDistributor(); - steps.add(_NotificationDebugStep( + steps.add( + _NotificationDebugStep( name: "Unified Push Distributor", description: "distributor for unified push: $distributor", - passed: distributor != null)); + passed: distributor != null, + ), + ); } } else { - steps.add(_NotificationDebugStep( + steps.add( + _NotificationDebugStep( name: "Google Services Configuration", description: "Checks the current config for Google services notifications: ${preferences.fcmKey.value == null ? "null" : preferences.fcmKey.value!.substring(0, 10) + "..."}", - passed: preferences.fcmKey.value != null)); + passed: preferences.fcmKey.value != null, + ), + ); } String? pushKey = BuildConfig.ENABLE_GOOGLE_SERVICES @@ -180,27 +208,33 @@ class _NotificationDebuggerState extends State { : preferences.unifiedPushEndpoint.value; var pusher = pushers - ?.where((i) => - i.deviceDisplayName == matrixClient.clientName && - i.pushkey == pushKey) + ?.where( + (i) => + i.deviceDisplayName == matrixClient.clientName && + i.pushkey == pushKey, + ) .firstOrNull; var step = _NotificationDebugStep( - name: "Has Registered Pusher", - description: - "Tests if the client has registered a push notification service with the homeserver: ${pusher?.data.url?.host}", - passed: pusher != null); + name: "Has Registered Pusher", + description: + "Tests if the client has registered a push notification service with the homeserver: ${pusher?.data.url?.host}", + passed: pusher != null, + ); steps.add(step); if (pusher != null) { if (BuildConfig.ENABLE_GOOGLE_SERVICES && pusher.data.additionalProperties["type"] == "fcm") { - steps.add(_NotificationDebugStep( + steps.add( + _NotificationDebugStep( name: "Pusher configuration", description: "Checks the pusher is configured to use Google services", - passed: true)); + passed: true, + ), + ); } final url = pusher.data.url!.replace(path: "/_matrix/push/v1/notify"); @@ -210,37 +244,35 @@ class _NotificationDebuggerState extends State { "devices": [ { "app_id": pusher.appId, - "data": { - ...pusher.data.additionalProperties, - }, + "data": {...pusher.data.additionalProperties}, "pushkey": pusher.pushkey, }, ], "event_id": event.eventId, "prio": "high", - "room_id": room.identifier - } + "room_id": room.identifier, + }, }; Log.i("Sending to: $url"); - Log.i( - "Sending test notification: ${content}", - ); + Log.i("Sending test notification: ${content}"); var startTime = DateTime.now(); - var nextData = - EventBus.onReceivedPushNotificationData.stream.nextItemAsFuture(); + var nextData = EventBus.onReceivedPushNotificationData.stream + .nextItemAsFuture(); - var result = await http.post(url, body: jsonEncode(content), headers: { - 'Content-Type': 'application/json; charset=UTF-8', - }); + var result = await http.post( + url, + body: jsonEncode(content), + headers: {'Content-Type': 'application/json; charset=UTF-8'}, + ); var step = _NotificationDebugStep( - name: "Send test notification", - description: - "Tests if sending a notification to the registered pusher is accepted", - passed: result.statusCode == 200); + name: "Send test notification", + description: "Tests if sending a notification to the registered pusher is accepted", + passed: result.statusCode == 200, + ); steps.add(step); try { @@ -248,27 +280,29 @@ class _NotificationDebuggerState extends State { var endTime = DateTime.now(); var length = endTime.difference(startTime); var step = _NotificationDebugStep( - name: "Receive notification", - description: - "Received data back from push service in ${length.inMilliseconds}ms: $result", - passed: true); + name: "Receive notification", + description: + "Received data back from push service in ${length.inMilliseconds}ms: $result", + passed: true, + ); steps.add(step); } catch (e) { if (e is TimeoutException) { var step = _NotificationDebugStep( - name: "Receive notification", - description: - "Did not receive any data back from push service after waiting 20 seconds", - passed: false); + name: "Receive notification", + description: "Did not receive any data back from push service after waiting 20 seconds", + passed: false, + ); steps.add(step); } else { var step = _NotificationDebugStep( - name: "Receive notification", - description: - "Unknown error occured waiting for notification data: $e", - passed: false); + name: "Receive notification", + description: + "Unknown error occured waiting for notification data: $e", + passed: false, + ); steps.add(step); } @@ -281,9 +315,10 @@ class _NotificationDebuggerState extends State { event, onNotificationRejected: (reason) { var step = _NotificationDebugStep( - name: "Notification rejected", - description: "$reason", - passed: false); + name: "Notification rejected", + description: "$reason", + passed: false, + ); steps.add(step); }, @@ -292,9 +327,10 @@ class _NotificationDebuggerState extends State { await f; var step = _NotificationDebugStep( - name: "Handle Notification", - description: "If you saw a notification, this test passed.", - passed: null); + name: "Handle Notification", + description: "If you saw a notification, this test passed.", + passed: null, + ); steps.add(step); } @@ -311,7 +347,8 @@ class _NotificationDebuggerState extends State { children: [ if (usesDesktopNotification) tiamat.Text.labelLow( - "The app may be minimized while testing. if minimized, wait for atleast 5 seconds before re-opening"), + "The app may be minimized while testing. if minimized, wait for atleast 5 seconds before re-opening", + ), CircularProgressIndicator(), ], ), @@ -333,22 +370,20 @@ class _NotificationDebuggerState extends State { value.passed == null ? Icons.question_mark : value.passed! - ? Icons.check - : Icons.error, + ? Icons.check + : Icons.error, color: value.passed == null ? null : value.passed! - ? Colors.green - : Colors.red, + ? Colors.green + : Colors.red, ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text(value.name), - tiamat.Text.labelLow( - value.description, - ) + tiamat.Text.labelLow(value.description), ], ), ), diff --git a/commet/lib/ui/molecules/overlapping_panels.dart b/commet/lib/ui/molecules/overlapping_panels.dart index 69d8d39d2..fe55ac4d0 100644 --- a/commet/lib/ui/molecules/overlapping_panels.dart +++ b/commet/lib/ui/molecules/overlapping_panels.dart @@ -4,6 +4,7 @@ import 'package:commet/main.dart'; import 'package:commet/ui/atoms/inherited_offstage.dart'; import 'package:flutter/material.dart'; + import 'dart:core'; import 'package:tiamat/config/config.dart'; @@ -38,14 +39,15 @@ class OverlappingPanels extends StatefulWidget { final double threshold = 0.2; - const OverlappingPanels( - {this.left, - required this.main, - this.right, - this.restWidth = 40, - this.onSideChange, - this.onDragStart, - super.key}); + const OverlappingPanels({ + this.left, + required this.main, + this.right, + this.restWidth = 40, + this.onSideChange, + this.onDragStart, + super.key, + }); static OverlappingPanelsState? of(BuildContext context) { return context.findAncestorStateOfType(); @@ -71,21 +73,26 @@ class OverlappingPanelsState extends State final mediaWidth = MediaQuery.of(context).size.width / preferences.appScale.value; final animationController = AnimationController( - vsync: this, duration: const Duration(milliseconds: 300)); + vsync: this, + duration: const Duration(milliseconds: 300), + ); animationController.addStatusListener((status) { if (status == AnimationStatus.completed) { if (widget.onSideChange != null) { - widget.onSideChange!(translate == 0 - ? RevealSide.main - : (translate > 0 ? RevealSide.left : RevealSide.right)); + widget.onSideChange!( + translate == 0 + ? RevealSide.main + : (translate > 0 ? RevealSide.left : RevealSide.right), + ); } animationController.dispose(); } }); var percent = -translate / mediaWidth; - bool crossedThreshold = percent.abs() > widget.threshold && + bool crossedThreshold = + percent.abs() > widget.threshold && percent.abs() < 1 - widget.threshold; if (crossedThreshold) { @@ -118,13 +125,17 @@ class OverlappingPanelsState extends State } void revealLeftPanel( - double mediaWidth, AnimationController animationController) { + double mediaWidth, + AnimationController animationController, + ) { currentSide = RevealSide.left; _setTranslateMultiplier(mediaWidth, 1, animationController); } void revealRightPanel( - double mediaWidth, AnimationController animationController) { + double mediaWidth, + AnimationController animationController, + ) { currentSide = RevealSide.right; _setTranslateMultiplier(mediaWidth, -1, animationController); } @@ -132,8 +143,8 @@ class OverlappingPanelsState extends State void revealMainPanel(AnimationController animationController) { currentSide = RevealSide.main; final animation = Tween(begin: translate, end: 0).animate( - CurvedAnimation( - parent: animationController, curve: Curves.easeOutExpo)); + CurvedAnimation(parent: animationController, curve: Curves.easeOutExpo), + ); animation.addListener(() { setState(() { @@ -142,14 +153,18 @@ class OverlappingPanelsState extends State }); } - void _setTranslateMultiplier(double mediaWidth, int multiplier, - AnimationController animationController) { + void _setTranslateMultiplier( + double mediaWidth, + int multiplier, + AnimationController animationController, + ) { final goal = _calculateGoal(mediaWidth, multiplier); final Tween tween = Tween(begin: translate, end: goal); - final animation = tween.animate(CurvedAnimation( - parent: animationController, curve: Curves.easeOutExpo)); + final animation = tween.animate( + CurvedAnimation(parent: animationController, curve: Curves.easeOutExpo), + ); animation.addListener(() { setState(() { @@ -162,7 +177,9 @@ class OverlappingPanelsState extends State final mediaWidth = MediaQuery.of(context).size.width / preferences.appScale.value; final animationController = AnimationController( - vsync: this, duration: const Duration(milliseconds: 300)); + vsync: this, + duration: const Duration(milliseconds: 300), + ); switch (direction) { case RevealSide.left: @@ -194,65 +211,65 @@ class OverlappingPanelsState extends State double borderRadius = 20; return GestureDetector( - onHorizontalDragStart: (details) { - widget.onDragStart?.call(); - }, - onHorizontalDragUpdate: (details) { - onTranslate(details.delta.dx); - }, - onHorizontalDragEnd: (details) { - _onApplyTranslation(); - }, - child: Stack( - children: [ - Padding( - padding: EdgeInsets.fromLTRB(0, 0, widget.restWidth + 3, 0), - child: ClipRRect( - borderRadius: BorderRadius.only( - topRight: Radius.circular(borderRadius), - bottomRight: Radius.circular(borderRadius)), - child: InheritedOffstage( - offstage: translate <= 0, - child: Offstage( - offstage: translate <= 0, - child: widget.left, - ), - ), + onHorizontalDragStart: (details) { + widget.onDragStart?.call(); + }, + onHorizontalDragUpdate: (details) { + onTranslate(details.delta.dx); + }, + onHorizontalDragEnd: (details) { + _onApplyTranslation(); + }, + child: Stack( + children: [ + Padding( + padding: EdgeInsets.fromLTRB(0, 0, widget.restWidth + 3, 0), + child: ClipRRect( + borderRadius: BorderRadius.only( + topRight: Radius.circular(borderRadius), + bottomRight: Radius.circular(borderRadius), + ), + child: InheritedOffstage( + offstage: translate <= 0, + child: Offstage(offstage: translate <= 0, child: widget.left), + ), + ), + ), + Padding( + padding: EdgeInsets.fromLTRB(widget.restWidth + 3, 0, 0, 0), + child: ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(borderRadius), + bottomLeft: Radius.circular(borderRadius), + ), + child: InheritedOffstage( + offstage: translate >= 0, + child: Offstage(offstage: translate >= 0, child: widget.right), ), ), - Padding( - padding: EdgeInsets.fromLTRB(widget.restWidth + 3, 0, 0, 0), - child: ClipRRect( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(borderRadius), - bottomLeft: Radius.circular(borderRadius)), - child: InheritedOffstage( - offstage: translate >= 0, - child: Offstage( - offstage: translate >= 0, - child: widget.right, - ), + ), + Transform.translate( + offset: Offset(translate, 0), + child: Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular( + (translate.abs() * 0.1).clamp(0, 20), ), + boxShadow: + Theme.of(context).extension()?.shadows ?? + [ + BoxShadow( + color: Colors.black.withAlpha(30), + blurRadius: 20, + ), + ], ), + child: widget.main, ), - Transform.translate( - offset: Offset(translate, 0), - child: Container( - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular( - (translate.abs() * 0.1).clamp(0, 20)), - boxShadow: Theme.of(context) - .extension() - ?.shadows ?? - [ - BoxShadow( - color: Colors.black.withAlpha(30), - blurRadius: 20) - ]), - child: widget.main), - ) - ], - )); + ), + ], + ), + ); } } diff --git a/commet/lib/ui/molecules/poll_creator.dart b/commet/lib/ui/molecules/poll_creator.dart index f94b998d0..a71ab800b 100644 --- a/commet/lib/ui/molecules/poll_creator.dart +++ b/commet/lib/ui/molecules/poll_creator.dart @@ -37,9 +37,7 @@ class _PollCreatorState extends State { border: const OutlineInputBorder(), ), ), - SizedBox( - height: 8, - ), + SizedBox(height: 8), tiamat.DropdownSelector( value: openPoll, items: [true, false], @@ -62,20 +60,18 @@ class _PollCreatorState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text(msg), - tiamat.Text.labelLow(descriptor) + tiamat.Text.labelLow(descriptor), ], ), ); }, ), - SizedBox( - height: 12, - ), + SizedBox(height: 12), SizedBox( height: 200, child: ScrollConfiguration( - behavior: - ScrollConfiguration.of(context).copyWith(scrollbars: false), + behavior: ScrollConfiguration.of(context) + .copyWith(scrollbars: false), child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.fromLTRB(2, 8, 2, 8), @@ -90,21 +86,23 @@ class _PollCreatorState extends State { child: TextField( controller: options[i], decoration: InputDecoration( - suffixIcon: SizedBox( - height: 34, - width: 34, - child: options.length > 2 - ? tiamat.IconButton( - icon: Icons.remove, - onPressed: () { - setState(() { - options.removeAt(i); - }); - }, - ) - : null), - border: const OutlineInputBorder(), - labelText: "Option ${i + 1}"), + suffixIcon: SizedBox( + height: 34, + width: 34, + child: options.length > 2 + ? tiamat.IconButton( + icon: Icons.remove, + onPressed: () { + setState(() { + options.removeAt(i); + }); + }, + ) + : null, + ), + border: const OutlineInputBorder(), + labelText: "Option ${i + 1}", + ), ), ), ], @@ -122,17 +120,18 @@ class _PollCreatorState extends State { children: [ Flexible( child: CheckboxListTile( - dense: true, - title: tiamat.Text("Allow multiple answers"), - value: multiAnswer, - controlAffinity: ListTileControlAffinity.leading, - onChanged: (value) { - if (value != null) { - setState(() { - multiAnswer = value; - }); - } - }), + dense: true, + title: tiamat.Text("Allow multiple answers"), + value: multiAnswer, + controlAffinity: ListTileControlAffinity.leading, + onChanged: (value) { + if (value != null) { + setState(() { + multiAnswer = value; + }); + } + }, + ), ), TextButton.icon( label: Text("Add Option"), @@ -145,43 +144,45 @@ class _PollCreatorState extends State { ], ), if (errorMessage != null) tiamat.Text.error(errorMessage!), - SizedBox( - height: 12, - ), + SizedBox(height: 12), tiamat.Button( - text: "Create", - onTap: () async { + text: "Create", + onTap: () async { + setState(() { + errorMessage = null; + }); + + String question = questionController.text; + if (question.isEmpty) { setState(() { - errorMessage = null; + errorMessage = "Poll must have a question"; }); + return; + } - String question = questionController.text; - if (question.isEmpty) { + List parsedOptions = List.empty(growable: true); + + for (var controller in options) { + if (controller.text.trim().isEmpty) { setState(() { - errorMessage = "Poll must have a question"; + errorMessage = "Poll cannot have a blank option"; }); return; } - List parsedOptions = List.empty(growable: true); - - for (var controller in options) { - if (controller.text.trim().isEmpty) { - setState(() { - errorMessage = "Poll cannot have a blank option"; - }); - return; - } - - parsedOptions.add(controller.text.trim()); - } + parsedOptions.add(controller.text.trim()); + } - Navigator.of(context).pop(PollCreateArgs( - question: question, - options: parsedOptions, - multiAnswer: multiAnswer, - publicAnswers: openPoll)); - }) + Navigator.of(context).pop( + PollCreateArgs( + question: question, + options: parsedOptions, + multiAnswer: multiAnswer, + publicAnswers: openPoll, + ), + ); + }, + ), ], ), ), diff --git a/commet/lib/ui/molecules/popup_icon_menu.dart b/commet/lib/ui/molecules/popup_icon_menu.dart index 04426c4e7..45d519f93 100644 --- a/commet/lib/ui/molecules/popup_icon_menu.dart +++ b/commet/lib/ui/molecules/popup_icon_menu.dart @@ -1,5 +1,6 @@ import 'package:flutter/widgets.dart'; import 'package:flutter/material.dart' as m; + import '../atoms/icon_button.dart' as i; class PopupIconMenu extends StatelessWidget { @@ -11,27 +12,30 @@ class PopupIconMenu extends StatelessWidget { Widget build(BuildContext context) { return DecoratedBox( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: m.Theme.of(context).colorScheme.surface, - boxShadow: [ - BoxShadow(blurRadius: 4, color: m.Theme.of(context).shadowColor) - ]), + borderRadius: BorderRadius.circular(8), + color: m.Theme.of(context).colorScheme.surface, + boxShadow: [ + BoxShadow(blurRadius: 4, color: m.Theme.of(context).shadowColor), + ], + ), child: Padding( padding: const EdgeInsets.all(8.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: icons - .map((icon) => Padding( - padding: const EdgeInsets.fromLTRB(4, 0, 4, 0), - child: i.IconButton( - icon: icon.key, - size: height / 1.5, - onPressed: () { - icon.value.call(); - }, - ), - )) + .map( + (icon) => Padding( + padding: const EdgeInsets.fromLTRB(4, 0, 4, 0), + child: i.IconButton( + icon: icon.key, + size: height / 1.5, + onPressed: () { + icon.value.call(); + }, + ), + ), + ) .toList(), ), ), diff --git a/commet/lib/ui/molecules/profile/mini_profile_view.dart b/commet/lib/ui/molecules/profile/mini_profile_view.dart index 7e7cadc1e..5779a570f 100644 --- a/commet/lib/ui/molecules/profile/mini_profile_view.dart +++ b/commet/lib/ui/molecules/profile/mini_profile_view.dart @@ -8,12 +8,13 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class MiniProfileView extends StatefulWidget { - const MiniProfileView( - {required this.client, - required this.userId, - this.initialProfile, - this.onTap, - super.key}); + const MiniProfileView({ + required this.client, + required this.userId, + this.initialProfile, + this.onTap, + super.key, + }); final Client client; final String userId; final Profile? initialProfile; @@ -36,9 +37,11 @@ class _MiniProfileViewState extends State { widget.client .getComponent()! .getProfile(widget.userId) - .then((value) => setState(() { - profile = value; - })); + .then( + (value) => setState(() { + profile = value; + }), + ); } else { profile = widget.initialProfile; } @@ -82,8 +85,9 @@ class _MiniProfileViewState extends State { height: 12, width: (random * 50) + 50, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: shimmerColor), + borderRadius: BorderRadius.circular(4), + color: shimmerColor, + ), ), profile != null ? tiamat.Text.labelLow(profile!.identifier) @@ -93,8 +97,9 @@ class _MiniProfileViewState extends State { height: 8, width: (random * 10) + 100, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: shimmerColor), + borderRadius: BorderRadius.circular(4), + color: shimmerColor, + ), ), ), ], diff --git a/commet/lib/ui/molecules/read_indicator.dart b/commet/lib/ui/molecules/read_indicator.dart index 1962785f5..d906bbb78 100644 --- a/commet/lib/ui/molecules/read_indicator.dart +++ b/commet/lib/ui/molecules/read_indicator.dart @@ -4,12 +4,13 @@ import 'package:tiamat/tiamat.dart' as tiamat; import '../../client/room.dart'; class ReadIndicator extends StatelessWidget { - const ReadIndicator( - {required this.room, - required this.users, - this.spacing = 6, - this.onTap, - super.key}); + const ReadIndicator({ + required this.room, + required this.users, + this.spacing = 6, + this.onTap, + super.key, + }); final Room room; final Function()? onTap; final Iterable users; @@ -23,20 +24,21 @@ class ReadIndicator extends StatelessWidget { return Material( color: Colors.transparent, child: Row( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - InkWell( - onTap: onTap, - child: Stack( - children: [ - for (int i = 0; i < users.length && i < maxItems; i++) - buildEntry(i, context, fade: diff > 0), - ], - ), - ) - ]), + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + InkWell( + onTap: onTap, + child: Stack( + children: [ + for (int i = 0; i < users.length && i < maxItems; i++) + buildEntry(i, context, fade: diff > 0), + ], + ), + ), + ], + ), ); } @@ -48,9 +50,10 @@ class ReadIndicator extends StatelessWidget { padding: EdgeInsets.fromLTRB(index.toDouble() * spacing, 0, 0, 0), child: tiamat.Avatar( border: BoxBorder.all( - color: ColorScheme.of(context).surfaceContainerLow, - width: 2, - strokeAlign: 0.5), + color: ColorScheme.of(context).surfaceContainerLow, + width: 2, + strokeAlign: 0.5, + ), radius: 8, image: member.avatar, placeholderColor: member.defaultColor, diff --git a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_overlay.dart b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_overlay.dart index 343467087..344ce5a49 100644 --- a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_overlay.dart +++ b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_overlay.dart @@ -14,12 +14,13 @@ import 'package:tiamat/tiamat.dart' as tiamat; import 'package:flutter/material.dart' as m; class TimelineOverlay extends StatefulWidget { - const TimelineOverlay( - {required this.link, - this.showMessageMenu = true, - this.jumpToLatest, - this.onScrolled, - super.key}); + const TimelineOverlay({ + required this.link, + this.showMessageMenu = true, + this.jumpToLatest, + this.onScrolled, + super.key, + }); final LayerLink link; final bool showMessageMenu; final Function()? jumpToLatest; @@ -43,10 +44,11 @@ class TimelineOverlayState extends State { bool isAttatchedToBottom = true; - String get labelJumpToLatest => Intl.message("Jump to latest", - desc: - "Label for the button which jumps the room timeline view to the latest message", - name: "labelJumpToLatest"); + String get labelJumpToLatest => Intl.message( + "Jump to latest", + desc: "Label for the button which jumps the room timeline view to the latest message", + name: "labelJumpToLatest", + ); @override Widget build(BuildContext context) { @@ -54,28 +56,33 @@ class TimelineOverlayState extends State { children: [ if (widget.showMessageMenu) Positioned( - right: 0, - top: 0, - child: CompositedTransformFollower( - targetAnchor: Alignment.topRight, - followerAnchor: openDownwards == true - ? Alignment.topRight - : Alignment.bottomRight, - showWhenUnlinked: false, - offset: Offset(-20, openDownwards == true ? -50 : 0), - link: widget.link, - child: MouseRegion( - child: Padding( - padding: const EdgeInsets.fromLTRB(20, 20, 20, 0), - child: buildTooltipMenu( - child: Listener( - onPointerSignal: (event) { - if (event is PointerScrollEvent) { - widget.onScrolled?.call(event); - } - }, - child: buildPrimaryMenu(context))), - )))), + right: 0, + top: 0, + child: CompositedTransformFollower( + targetAnchor: Alignment.topRight, + followerAnchor: openDownwards == true + ? Alignment.topRight + : Alignment.bottomRight, + showWhenUnlinked: false, + offset: Offset(-20, openDownwards == true ? -50 : 0), + link: widget.link, + child: MouseRegion( + child: Padding( + padding: const EdgeInsets.fromLTRB(20, 20, 20, 0), + child: buildTooltipMenu( + child: Listener( + onPointerSignal: (event) { + if (event is PointerScrollEvent) { + widget.onScrolled?.call(event); + } + }, + child: buildPrimaryMenu(context), + ), + ), + ), + ), + ), + ), Align( alignment: Alignment.bottomCenter, child: AnimatedSlide( @@ -87,7 +94,7 @@ class TimelineOverlayState extends State { onTap: widget.jumpToLatest, ), ), - ) + ), ], ); } @@ -110,11 +117,15 @@ class TimelineOverlayState extends State { borderRadius: BorderRadius.circular(8), child: Tile.surfaceContainer( child: SizedBox( - width: tooltipHeight, - height: tooltipHeight, - child: MouseRegion( - child: selectedEntry!.secondaryMenuBuilder - ?.call(context, clearSelection))), + width: tooltipHeight, + height: tooltipHeight, + child: MouseRegion( + child: selectedEntry!.secondaryMenuBuilder?.call( + context, + clearSelection, + ), + ), + ), ), ), ), @@ -135,67 +146,80 @@ class TimelineOverlayState extends State { return MouseRegion( child: DecoratedBox( - key: menuKey, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: m.Theme.of(context).colorScheme.surfaceDim, - border: Border.all( - color: - m.Theme.of(context).colorScheme.surfaceContainerHighest, - width: 1)), - child: currentMenu != null - ? Padding( - padding: const EdgeInsets.fromLTRB(4, 0, 4, 0), - child: Row(children: [ + key: menuKey, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: m.Theme.of(context).colorScheme.surfaceDim, + border: Border.all( + color: m.Theme.of(context).colorScheme.surfaceContainerHighest, + width: 1, + ), + ), + child: currentMenu != null + ? Padding( + padding: const EdgeInsets.fromLTRB(4, 0, 4, 0), + child: Row( + children: [ for (var e in reactions!) buildAction( - name: e.shortcode, - child: EmojiWidget( + name: e.shortcode, + child: EmojiWidget( + e, + height: size / 1.5, + padding: const EdgeInsetsGeometry.all(2), + ), + onTap: () { + currentMenu?.timeline.room.addReaction( + currentMenu!.event, e, - height: size / 1.5, - padding: const EdgeInsetsGeometry.all(2), - ), - onTap: () { - currentMenu?.timeline.room - .addReaction(currentMenu!.event, e); - }), + ); + }, + ), if (currentMenu!.addReactionAction != null) buildAction( - name: currentMenu!.addReactionAction!.name, - child: m.Icon( - currentMenu!.addReactionAction!.icon, - color: Theme.of(context).colorScheme.secondary, - size: size / 1.5, - ), - onTap: () => - togglePopupMenu(currentMenu!.addReactionAction!)), + name: currentMenu!.addReactionAction!.name, + child: m.Icon( + currentMenu!.addReactionAction!.icon, + color: Theme.of(context).colorScheme.secondary, + size: size / 1.5, + ), + onTap: () => + togglePopupMenu(currentMenu!.addReactionAction!), + ), if (currentMenu!.addReactionAction != null) SizedBox(height: 10, child: VerticalDivider()), for (var e in currentMenu!.primaryActions) buildAction( - name: e.name, - child: m.Icon( - e.icon, - color: Theme.of(context).colorScheme.secondary, - size: size / 1.5, - ), - size: size, - onTap: e.secondaryMenuBuilder != null - ? () => togglePopupMenu(e) - : () => e.action?.call(context)), - buildAction( - name: "Options", - child: Icon(m.Icons.more_vert), + name: e.name, + child: m.Icon( + e.icon, + color: Theme.of(context).colorScheme.secondary, + size: size / 1.5, + ), size: size, - contextMenuItems: currentMenu!.secondaryActions - .map((e) => ContextMenuItem( - text: e.name, - icon: e.icon, - onPressed: () => e.action?.call(context))) - .toList()) - ]), - ) - : Container()), + onTap: e.secondaryMenuBuilder != null + ? () => togglePopupMenu(e) + : () => e.action?.call(context), + ), + buildAction( + name: "Options", + child: Icon(m.Icons.more_vert), + size: size, + contextMenuItems: currentMenu!.secondaryActions + .map( + (e) => ContextMenuItem( + text: e.name, + icon: e.icon, + onPressed: () => e.action?.call(context), + ), + ) + .toList(), + ), + ], + ), + ) + : Container(), + ), ); } @@ -236,12 +260,13 @@ class TimelineOverlayState extends State { } } - Widget buildAction( - {required Widget child, - String? name, - Function()? onTap, - double size = 30, - List? contextMenuItems}) { + Widget buildAction({ + required Widget child, + String? name, + Function()? onTap, + double size = 30, + List? contextMenuItems, + }) { var pad = const EdgeInsets.all(2); var result = m.Padding( @@ -257,17 +282,12 @@ class TimelineOverlayState extends State { ? ContextMenu( modal: true, items: contextMenuItems, - child: Padding( - padding: pad, - child: child, - ), + child: Padding(padding: pad, child: child), ) : InkWell( onTap: onTap, - child: Padding( - padding: pad, - child: child, - )), + child: Padding(padding: pad, child: child), + ), ), ), ), diff --git a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_overlay_button.dart b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_overlay_button.dart index c03c9a74d..81f58a1c1 100644 --- a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_overlay_button.dart +++ b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_overlay_button.dart @@ -3,8 +3,11 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class RoomTimelineOverlayButton extends StatelessWidget { - const RoomTimelineOverlayButton( - {this.onTap, this.text = "Hello, World!", super.key}); + const RoomTimelineOverlayButton({ + this.onTap, + this.text = "Hello, World!", + super.key, + }); final void Function()? onTap; final String text; @@ -14,36 +17,36 @@ class RoomTimelineOverlayButton extends StatelessWidget { ? const EdgeInsets.fromLTRB(18, 12, 18, 12) : const EdgeInsets.fromLTRB(12, 4, 12, 4); return Padding( - padding: const EdgeInsets.all(8.0), - child: DecoratedBox( - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - color: Theme.of(context).shadowColor, - blurRadius: 5, - ) - ], - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: Theme.of(context).colorScheme.surfaceContainerHigh, - width: 1), - color: Theme.of(context).colorScheme.surfaceContainer), - child: ClipRRect( - borderRadius: BorderRadius.circular(20), - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: onTap, - child: Padding( - padding: padding, - child: tiamat.Text.labelLow( - text, - color: Theme.of(context).colorScheme.onSurface, - ), + padding: const EdgeInsets.all(8.0), + child: DecoratedBox( + decoration: BoxDecoration( + boxShadow: [ + BoxShadow(color: Theme.of(context).shadowColor, blurRadius: 5), + ], + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: Theme.of(context).colorScheme.surfaceContainerHigh, + width: 1, + ), + color: Theme.of(context).colorScheme.surfaceContainer, + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(20), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: onTap, + child: Padding( + padding: padding, + child: tiamat.Text.labelLow( + text, + color: Theme.of(context).colorScheme.onSurface, ), ), ), ), - )); + ), + ), + ); } } diff --git a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget.dart b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget.dart index ea0c160de..56b8bc3a7 100644 --- a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget.dart +++ b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget.dart @@ -7,13 +7,14 @@ import 'package:commet/ui/molecules/room_timeline_widget/room_timeline_widget_vi import 'package:flutter/material.dart'; class RoomTimelineWidget extends StatefulWidget { - const RoomTimelineWidget( - {required this.timeline, - this.setEditingEvent, - this.setReplyingEvent, - this.isThreadTimeline = false, - this.clearNotifications, - super.key}); + const RoomTimelineWidget({ + required this.timeline, + this.setEditingEvent, + this.setReplyingEvent, + this.isThreadTimeline = false, + this.clearNotifications, + super.key, + }); final Timeline timeline; final Function(TimelineEvent? event)? setReplyingEvent; final Function(TimelineEvent? event)? setEditingEvent; diff --git a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget_view.dart b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget_view.dart index 2cbef8049..ef82f16de 100644 --- a/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget_view.dart +++ b/commet/lib/ui/molecules/room_timeline_widget/room_timeline_widget_view.dart @@ -18,15 +18,16 @@ import 'package:commet/utils/event_bus.dart'; import 'package:flutter/material.dart'; class RoomTimelineWidgetView extends StatefulWidget { - const RoomTimelineWidgetView( - {required this.timeline, - this.markAsRead, - this.onViewScrolled, - this.setEditingEvent, - this.setReplyingEvent, - this.onAttachedToBottom, - this.isThreadTimeline = false, - super.key}); + const RoomTimelineWidgetView({ + required this.timeline, + this.markAsRead, + this.onViewScrolled, + this.setEditingEvent, + this.setReplyingEvent, + this.onAttachedToBottom, + this.isThreadTimeline = false, + super.key, + }); final Timeline timeline; final Function(TimelineEvent event)? markAsRead; final Function(TimelineEvent? event)? setReplyingEvent; @@ -34,10 +35,12 @@ class RoomTimelineWidgetView extends StatefulWidget { final Function()? onAttachedToBottom; final bool isThreadTimeline; - final Function( - {required double offset, - required double maxScrollExtent, - required double minScrollExtent})? onViewScrolled; + final Function({ + required double offset, + required double maxScrollExtent, + required double minScrollExtent, + })? + onViewScrolled; @override State createState() => RoomTimelineWidgetViewState(); @@ -77,7 +80,7 @@ class RoomTimelineWidgetViewState extends State { bool get attachedToBottom => controller.hasClients ? controller.offset - controller.positions.first.minScrollExtent < 50 || - animatingToBottom + animatingToBottom : true; bool isLoadingFuture = false; @@ -115,8 +118,9 @@ class RoomTimelineWidgetViewState extends State { int? viewIndex = null; for (int i = index; i >= 1; i--) { - var eventType = - TimelineViewEntryState.eventToDisplayType(timeline.events[i - 1]); + var eventType = TimelineViewEntryState.eventToDisplayType( + timeline.events[i - 1], + ); if (eventType == TimelineEventWidgetDisplayType.message) { lastReadEventId = timeline.events[i - 1].eventId; @@ -157,9 +161,9 @@ class RoomTimelineWidgetViewState extends State { } eventKeys = List.from( - timeline.events - .map((e) => (GlobalKey(debugLabel: e.eventId), e.eventId)), - growable: true); + timeline.events.map((e) => (GlobalKey(debugLabel: e.eventId), e.eventId)), + growable: true, + ); } @override @@ -174,7 +178,7 @@ class RoomTimelineWidgetViewState extends State { void onEventAdded(int index, {bool cascade = true}) { eventKeys.insert(index, ( GlobalKey(debugLabel: timeline.events[index].eventId), - timeline.events[index].eventId + timeline.events[index].eventId, )); if (index == 0 || index < recentItemsCount) { @@ -217,9 +221,7 @@ class RoomTimelineWidgetViewState extends State { var existing = eventKeys[index]; eventKeys[index] = (existing.$1, event.eventId); - var key = eventKeys.firstWhere( - (element) => element.$2 == event.eventId, - ); + var key = eventKeys.firstWhere((element) => element.$2 == event.eventId); assert(event.eventId == key.$2); @@ -252,9 +254,11 @@ class RoomTimelineWidgetViewState extends State { void scrollToBottom() { WidgetsBinding.instance.addPostFrameCallback((_) { - controller.animateTo(controller.position.minScrollExtent, - duration: const Duration(milliseconds: 500), - curve: Curves.easeOutExpo); + controller.animateTo( + controller.position.minScrollExtent, + duration: const Duration(milliseconds: 500), + curve: Curves.easeOutExpo, + ); }); } @@ -293,9 +297,10 @@ class RoomTimelineWidgetViewState extends State { void onScroll() { widget.onViewScrolled?.call( - offset: controller.offset, - maxScrollExtent: controller.position.maxScrollExtent, - minScrollExtent: controller.position.minScrollExtent); + offset: controller.offset, + maxScrollExtent: controller.position.maxScrollExtent, + minScrollExtent: controller.position.minScrollExtent, + ); var overlayState = overlayKey.currentState as TimelineOverlayState?; overlayState?.setAttachedToBottom(attachedToBottom); @@ -347,15 +352,17 @@ class RoomTimelineWidgetViewState extends State { animatingToBottom = true; controller - .animateTo(controller.position.minScrollExtent, - duration: const Duration(milliseconds: 500), - curve: Curves.easeOutExpo) + .animateTo( + controller.position.minScrollExtent, + duration: const Duration(milliseconds: 500), + curve: Curves.easeOutExpo, + ) .then((_) { - setState(() { - controller.jumpTo(0); - animatingToBottom = false; - }); - }); + setState(() { + controller.jumpTo(0); + animatingToBottom = false; + }); + }); setState(() { recentItemsCount = 0; @@ -363,9 +370,7 @@ class RoomTimelineWidgetViewState extends State { } void eventHovered(String eventId) { - var key = eventKeys.firstWhere( - (element) => element.$2 == eventId, - ); + var key = eventKeys.firstWhere((element) => element.$2 == eventId); assert(eventId == key.$2); @@ -382,14 +387,16 @@ class RoomTimelineWidgetViewState extends State { var overlayState = overlayKey.currentState as TimelineOverlayState?; var event = timeline.tryGetEvent(eventId)!; - overlayState?.setMenu(TimelineEventMenu( - timeline: timeline, - context: context, - isThreadTimeline: widget.isThreadTimeline, - event: event, - setEditingEvent: (event) => widget.setEditingEvent?.call(event), - setReplyingEvent: (event) => widget.setReplyingEvent?.call(event), - )); + overlayState?.setMenu( + TimelineEventMenu( + timeline: timeline, + context: context, + isThreadTimeline: widget.isThreadTimeline, + event: event, + setEditingEvent: (event) => widget.setEditingEvent?.call(event), + setReplyingEvent: (event) => widget.setReplyingEvent?.call(event), + ), + ); } } else { Log.w("Failed to get selectable state"); @@ -424,15 +431,16 @@ class RoomTimelineWidgetViewState extends State { slivers: [ if (isLoadingFuture) SliverList( - delegate: SliverChildBuilderDelegate(childCount: 1, - (BuildContext context, int index) { - return const SizedBox( - height: 200, - child: Center( - child: CircularProgressIndicator(), - ), - ); - })), + delegate: SliverChildBuilderDelegate(childCount: 1, ( + BuildContext context, + int index, + ) { + return const SizedBox( + height: 200, + child: Center(child: CircularProgressIndicator()), + ); + }), + ), // The slivers are split into recent and history events and // are rendered separately. This prevents the timeline from // jumping around and allows jumping to specific indices @@ -453,37 +461,42 @@ class RoomTimelineWidgetViewState extends State { key = eventKeys[timelineIndex]; assert( - key.$2 == timeline.events[timelineIndex].eventId); + key.$2 == timeline.events[timelineIndex].eventId, + ); return Container( alignment: Alignment.center, - color: preferences.developerMode.value && + color: + preferences.developerMode.value && BuildConfig.DEBUG ? Colors.blue[200 + sliverIndex % 4 * 100]! - .withAlpha(30) + .withAlpha(30) : null, child: TimelineViewEntry( - key: key.$1, - timeline: timeline, - onEventHovered: eventHovered, - canCollapse: true, - setEditingEvent: widget.setEditingEvent, - setReplyingEvent: widget.setReplyingEvent, - isThreadTimeline: widget.isThreadTimeline, - highlightedEventId: highlightedEventId, - lastReadEventId: lastReadEventId, - previewMedia: - widget.timeline.room.shouldPreviewMedia, - jumpToEvent: jumpToEvent, - initialIndex: timelineIndex), + key: key.$1, + timeline: timeline, + onEventHovered: eventHovered, + canCollapse: true, + setEditingEvent: widget.setEditingEvent, + setReplyingEvent: widget.setReplyingEvent, + isThreadTimeline: widget.isThreadTimeline, + highlightedEventId: highlightedEventId, + lastReadEventId: lastReadEventId, + previewMedia: + widget.timeline.room.shouldPreviewMedia, + jumpToEvent: jumpToEvent, + initialIndex: timelineIndex, + ), ); }, findChildIndexCallback: (key) { - var timelineIndex = eventKeys - .indexWhere((element) => element.$1 == key); + var timelineIndex = eventKeys.indexWhere( + (element) => element.$1 == key, + ); if (timelineIndex == -1) { Log.w( - "Failed to get timeline index for key: $timelineIndex"); + "Failed to get timeline index for key: $timelineIndex", + ); return null; } @@ -507,37 +520,42 @@ class RoomTimelineWidgetViewState extends State { key = eventKeys[timelineIndex]; assert( - key.$2 == timeline.events[timelineIndex].eventId); + key.$2 == timeline.events[timelineIndex].eventId, + ); return Container( alignment: Alignment.center, - color: preferences.developerMode.value && + color: + preferences.developerMode.value && BuildConfig.DEBUG ? Colors.red[200 + sliverIndex % 4 * 100]! - .withAlpha(30) + .withAlpha(30) : null, child: TimelineViewEntry( - key: key.$1, - onEventHovered: eventHovered, - timeline: timeline, - canCollapse: true, - setEditingEvent: widget.setEditingEvent, - setReplyingEvent: widget.setReplyingEvent, - isThreadTimeline: widget.isThreadTimeline, - highlightedEventId: highlightedEventId, - previewMedia: - widget.timeline.room.shouldPreviewMedia, - lastReadEventId: lastReadEventId, - jumpToEvent: jumpToEvent, - initialIndex: timelineIndex), + key: key.$1, + onEventHovered: eventHovered, + timeline: timeline, + canCollapse: true, + setEditingEvent: widget.setEditingEvent, + setReplyingEvent: widget.setReplyingEvent, + isThreadTimeline: widget.isThreadTimeline, + highlightedEventId: highlightedEventId, + previewMedia: + widget.timeline.room.shouldPreviewMedia, + lastReadEventId: lastReadEventId, + jumpToEvent: jumpToEvent, + initialIndex: timelineIndex, + ), ); }, findChildIndexCallback: (key) { - var timelineIndex = eventKeys - .indexWhere((element) => element.$1 == key); + var timelineIndex = eventKeys.indexWhere( + (element) => element.$1 == key, + ); if (timelineIndex == -1) { Log.w( - "Failed to get timeline index for key: $timelineIndex"); + "Failed to get timeline index for key: $timelineIndex", + ); return null; } @@ -547,26 +565,28 @@ class RoomTimelineWidgetViewState extends State { ), if (isLoadingHistory) SliverList( - delegate: SliverChildBuilderDelegate(childCount: 1, - (BuildContext context, int index) { - return const SizedBox( - height: 200, - child: Center( - child: CircularProgressIndicator(), - ), - ); - })), + delegate: SliverChildBuilderDelegate(childCount: 1, ( + BuildContext context, + int index, + ) { + return const SizedBox( + height: 200, + child: Center(child: CircularProgressIndicator()), + ); + }), + ), ], ), ), TimelineOverlay( - key: overlayKey, - showMessageMenu: MediaQuery.of(context).desktop, - jumpToLatest: animateAndSnapToBottom, - onScrolled: (event) { - controller.jumpTo(controller.offset - event.scrollDelta.dy); - }, - link: selectedEventLayerLink), + key: overlayKey, + showMessageMenu: MediaQuery.of(context).desktop, + jumpToLatest: animateAndSnapToBottom, + onScrolled: (event) { + controller.jumpTo(controller.offset - event.scrollDelta.dy); + }, + link: selectedEventLayerLink, + ), if (highlightedEventOffstageIndex != null && highlightedEventOffstageKey != null) Offstage( @@ -588,8 +608,9 @@ class RoomTimelineWidgetViewState extends State { ), if (loading) Container( - color: Colors.black.withAlpha(50), - child: const Center(child: CircularProgressIndicator())) + color: Colors.black.withAlpha(50), + child: const Center(child: CircularProgressIndicator()), + ), ], ), ), @@ -608,11 +629,13 @@ class RoomTimelineWidgetViewState extends State { setState(() { loading = true; }); - var newTimeline = - await timeline.room.getTimeline(contextEventId: eventId); + var newTimeline = await timeline.room.getTimeline( + contextEventId: eventId, + ); - index = - newTimeline.events.indexWhere((event) => event.eventId == eventId); + index = newTimeline.events.indexWhere( + (event) => event.eventId == eventId, + ); if (index == -1) { return; @@ -644,9 +667,11 @@ class RoomTimelineWidgetViewState extends State { offset += eventHeight / 2; } - controller.animateTo(offset, - duration: const Duration(milliseconds: 300), - curve: Easing.emphasizedDecelerate); + controller.animateTo( + offset, + duration: const Duration(milliseconds: 300), + curve: Easing.emphasizedDecelerate, + ); if (mounted) { setState(() { @@ -675,9 +700,7 @@ class RoomTimelineWidgetViewState extends State { } void onReadReceiptUpdated(String event) { - var key = eventKeys.firstWhereOrNull( - (element) => element.$2 == event, - ); + var key = eventKeys.firstWhereOrNull((element) => element.$2 == event); if (key == null) return; diff --git a/commet/lib/ui/molecules/settings_entry_bool.dart b/commet/lib/ui/molecules/settings_entry_bool.dart index 06df9bfd0..fc5184a70 100644 --- a/commet/lib/ui/molecules/settings_entry_bool.dart +++ b/commet/lib/ui/molecules/settings_entry_bool.dart @@ -3,8 +3,13 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class SettingsEntryBool extends StatelessWidget { - const SettingsEntryBool(this.state, - {required this.title, this.description, this.onChanged, super.key}); + const SettingsEntryBool( + this.state, { + required this.title, + this.description, + this.onChanged, + super.key, + }); final bool state; final String title; final String? description; @@ -20,11 +25,11 @@ class SettingsEntryBool extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text.labelEmphasised(title), - if (description != null) tiamat.Text.labelLow(description!) + if (description != null) tiamat.Text.labelLow(description!), ], ), ), - tiamat.Switch(state: state, onChanged: onChanged) + tiamat.Switch(state: state, onChanged: onChanged), ], ); } diff --git a/commet/lib/ui/molecules/show_on_hover.dart b/commet/lib/ui/molecules/show_on_hover.dart index 116ada8f5..186355f87 100644 --- a/commet/lib/ui/molecules/show_on_hover.dart +++ b/commet/lib/ui/molecules/show_on_hover.dart @@ -67,9 +67,10 @@ class _ShowOnHoverState extends State { }, ), AnimatedOpacity( - duration: Duration(milliseconds: 100), - opacity: showing ? 1.0 : 0.0, - child: IgnorePointer(ignoring: !showing, child: widget.child)), + duration: Duration(milliseconds: 100), + opacity: showing ? 1.0 : 0.0, + child: IgnorePointer(ignoring: !showing, child: widget.child), + ), ], ), ); diff --git a/commet/lib/ui/molecules/space_group_widget.dart b/commet/lib/ui/molecules/space_group_widget.dart index fb88b8e9d..4aea2f8c1 100644 --- a/commet/lib/ui/molecules/space_group_widget.dart +++ b/commet/lib/ui/molecules/space_group_widget.dart @@ -11,20 +11,21 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class SpaceGroupWidget extends StatefulWidget { - const SpaceGroupWidget( - {required this.spaces, - this.onSelected, - required this.folderId, - this.width = 44, - this.onDragEnd, - this.onDragCompleted, - this.onDragStarted, - this.onDragUpdate, - this.dragPosition, - this.initiallyOpen = false, - this.onExpansionStateChanged, - this.shouldShowAvatarForSpace, - super.key}); + const SpaceGroupWidget({ + required this.spaces, + this.onSelected, + required this.folderId, + this.width = 44, + this.onDragEnd, + this.onDragCompleted, + this.onDragStarted, + this.onDragUpdate, + this.dragPosition, + this.initiallyOpen = false, + this.onExpansionStateChanged, + this.shouldShowAvatarForSpace, + super.key, + }); final List spaces; final double width; final String folderId; @@ -162,8 +163,9 @@ class _SpaceGroupWidgetState extends State { child: AnimatedContainer( alignment: AlignmentGeometry.topLeft, decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainerHigh, - borderRadius: radius), + color: ColorScheme.of(context).surfaceContainerHigh, + borderRadius: radius, + ), height: expanded ? expandedHeight : unexpandedHeight, clipBehavior: Clip.hardEdge, duration: animationDuration, @@ -172,18 +174,19 @@ class _SpaceGroupWidgetState extends State { opacity: expanded ? 1.0 : 0, duration: animationDuration, child: ClipRRect( - borderRadius: radius, - child: Material( - color: Colors.transparent, - child: GestureDetector( - onTap: toggleExpansion, - child: SizedBox( - width: widget.width, - height: widget.width - shrink, - child: Icon(Icons.folder), - ), + borderRadius: radius, + child: Material( + color: Colors.transparent, + child: GestureDetector( + onTap: toggleExpansion, + child: SizedBox( + width: widget.width, + height: widget.width - shrink, + child: Icon(Icons.folder), ), - )), + ), + ), + ), ), ), ), @@ -216,18 +219,19 @@ class _SpaceGroupWidgetState extends State { ), ), Align( - alignment: Alignment.topRight, - child: Padding( - padding: const EdgeInsets.all(2.0), - child: AnimatedScale( - scale: (expanded || highlightNotificationCount == 0) - ? 0.0 - : 1.0, - duration: Duration(milliseconds: 300), - curve: Curves.easeOutExpo, - child: NotificationBadge(highlightNotificationCount), - ), - )), + alignment: Alignment.topRight, + child: Padding( + padding: const EdgeInsets.all(2.0), + child: AnimatedScale( + scale: (expanded || highlightNotificationCount == 0) + ? 0.0 + : 1.0, + duration: Duration(milliseconds: 300), + curve: Curves.easeOutExpo, + child: NotificationBadge(highlightNotificationCount), + ), + ), + ), ], ), ), @@ -269,126 +273,132 @@ class _SpaceGroupWidgetState extends State { } return AnimatedPositioned( + duration: animationDuration, + curve: curve, + top: top, + left: left, + child: AnimatedScale( + scale: scale, + alignment: Alignment.center, duration: animationDuration, curve: curve, - top: top, - left: left, - child: AnimatedScale( - scale: scale, - alignment: Alignment.center, - duration: animationDuration, - curve: curve, - child: LongPressDraggable( - onDragCompleted: widget.onDragCompleted, - onDragEnd: widget.onDragEnd, - onDragUpdate: widget.onDragUpdate, - onDragStarted: widget.onDragStarted, - data: SidebarEntryDrag(space, i, currentFolder: widget.folderId), - feedback: Opacity( - opacity: 0.5, - child: SizedBox( + child: LongPressDraggable( + onDragCompleted: widget.onDragCompleted, + onDragEnd: widget.onDragEnd, + onDragUpdate: widget.onDragUpdate, + onDragStarted: widget.onDragStarted, + data: SidebarEntryDrag(space, i, currentFolder: widget.folderId), + feedback: Opacity( + opacity: 0.5, + child: SizedBox( + width: widget.width, + height: widget.width, + child: SpaceSelectorState.buildSpaceIcon( + displayName: space.space.displayName, width: widget.width, - height: widget.width, - child: SpaceSelectorState.buildSpaceIcon( - displayName: space.space.displayName, - width: widget.width, - space: space.space, - placeholderColor: space.space.color, - showAvatarForSpace: false, - avatar: space.space.avatar), + space: space.space, + placeholderColor: space.space.color, + showAvatarForSpace: false, + avatar: space.space.avatar, ), ), - childWhenDragging: Opacity( - opacity: 0.2, - child: SizedBox( + ), + childWhenDragging: Opacity( + opacity: 0.2, + child: SizedBox( + width: widget.width, + height: widget.width, + child: SpaceSelectorState.buildSpaceIcon( + displayName: space.space.displayName, width: widget.width, - height: widget.width, - child: SpaceSelectorState.buildSpaceIcon( - displayName: space.space.displayName, - width: widget.width, - space: space.space, - placeholderColor: space.space.color, - showAvatarForSpace: false, - avatar: space.space.avatar), + space: space.space, + placeholderColor: space.space.color, + showAvatarForSpace: false, + avatar: space.space.avatar, ), ), - child: Column( - children: [ - if (dragPosition != null && expanded) - SizedBox( - height: dragDropAreaSize, - child: Padding( - padding: EdgeInsets.fromLTRB(0, 8, 0, 0), - child: ExpandingDropTarget( - height: dragDropAreaSize, - distanceBasedHeight: false, - onWillAcceptWithDetails: (p0) { - if (p0 case SidebarEntryDrag data) { - return data.entry is SpaceSidebarEntry; - } - - return false; - }, - onAcceptWithDetails: (p0) { - if (p0 is DragTargetDetails) { - if (p0.data case SidebarEntryDrag data) { - if (data.entry case SpaceSidebarEntry space) { - var component = space.space.client - .getComponent(); - - int index = adjustIndex(i, space.space.localId); - - print( - "Adding ${space.space.displayName} to folder at index: $i"); - component!.addToFolder( - space.space, widget.folderId, index); - - component.save(); - } + ), + child: Column( + children: [ + if (dragPosition != null && expanded) + SizedBox( + height: dragDropAreaSize, + child: Padding( + padding: EdgeInsets.fromLTRB(0, 8, 0, 0), + child: ExpandingDropTarget( + height: dragDropAreaSize, + distanceBasedHeight: false, + onWillAcceptWithDetails: (p0) { + if (p0 case SidebarEntryDrag data) { + return data.entry is SpaceSidebarEntry; + } + + return false; + }, + onAcceptWithDetails: (p0) { + if (p0 is DragTargetDetails) { + if (p0.data case SidebarEntryDrag data) { + if (data.entry case SpaceSidebarEntry space) { + var component = space.space.client + .getComponent(); + + int index = adjustIndex(i, space.space.localId); + + print( + "Adding ${space.space.displayName} to folder at index: $i", + ); + component!.addToFolder( + space.space, + widget.folderId, + index, + ); + + component.save(); } } + } - //handleSpaceOrderDropped(p0, index); - }, - position: dragPosition, - ), + //handleSpaceOrderDropped(p0, index); + }, + position: dragPosition, ), ), - tiamat.Tooltip( - text: space.space.displayName, - preferredDirection: AxisDirection.right, - child: SizedBox( - width: size, - height: size, - child: SpaceSelectorState.buildSpaceIcon( - displayName: space.space.displayName, - width: widget.width, - space: space.space, - placeholderColor: space.space.color, - notificationCount: space.space.notificationCount, - onUpdate: space.space.onUpdate, - highlightedNotificationCount: - space.space.highlightedNotificationCount, - onSelected: widget.onSelected, - userAvatar: space.space.client.self?.avatar, - userColor: space.space.client.self?.defaultColor, - userDisplayName: space.space.client.self?.displayName, - showAvatarForSpace: widget.shouldShowAvatarForSpace - ?.call(space.space) ?? - false, - avatar: space.space.avatar), + ), + tiamat.Tooltip( + text: space.space.displayName, + preferredDirection: AxisDirection.right, + child: SizedBox( + width: size, + height: size, + child: SpaceSelectorState.buildSpaceIcon( + displayName: space.space.displayName, + width: widget.width, + space: space.space, + placeholderColor: space.space.color, + notificationCount: space.space.notificationCount, + onUpdate: space.space.onUpdate, + highlightedNotificationCount: + space.space.highlightedNotificationCount, + onSelected: widget.onSelected, + userAvatar: space.space.client.self?.avatar, + userColor: space.space.client.self?.defaultColor, + userDisplayName: space.space.client.self?.displayName, + showAvatarForSpace: + widget.shouldShowAvatarForSpace?.call(space.space) ?? + false, + avatar: space.space.avatar, ), ), - ], - ), + ), + ], ), - )); + ), + ), + ); } int adjustIndex(int targetIndex, String id) { - int currentIndex = entries.indexWhere( - (element) => element.id == id, - ); + int currentIndex = entries.indexWhere((element) => element.id == id); if (currentIndex == -1) return targetIndex; diff --git a/commet/lib/ui/molecules/space_selector.dart b/commet/lib/ui/molecules/space_selector.dart index 8a8257d14..bada7234b 100644 --- a/commet/lib/ui/molecules/space_selector.dart +++ b/commet/lib/ui/molecules/space_selector.dart @@ -13,17 +13,20 @@ import 'package:commet/utils/scaled_app.dart'; import 'package:tiamat/tiamat.dart' as tiamat; import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart'; + import '../atoms/space_icon.dart'; class SpaceSelector extends StatefulWidget { - const SpaceSelector(this.spaces, - {super.key, - this.onSelected, - this.clearSelection, - required this.width, - this.shouldShowAvatarForSpace, - this.header, - this.footer}); + const SpaceSelector( + this.spaces, { + super.key, + this.onSelected, + this.clearSelection, + required this.width, + this.shouldShowAvatarForSpace, + this.header, + this.footer, + }); final List spaces; final double width; final Widget? header; @@ -77,14 +80,19 @@ class SpaceSelectorState extends State { children: [ Flexible( child: ScrollConfiguration( - behavior: - ScrollConfiguration.of(context).copyWith(scrollbars: false), + behavior: ScrollConfiguration.of(context) + .copyWith(scrollbars: false), child: SingleChildScrollView( - physics: - BuildConfig.ANDROID ? const BouncingScrollPhysics() : null, + physics: BuildConfig.ANDROID + ? const BouncingScrollPhysics() + : null, child: Padding( padding: EdgeInsets.fromLTRB( - 0, MediaQuery.of(context).scale().padding.top, 0, 0), + 0, + MediaQuery.of(context).scale().padding.top, + 0, + 0, + ), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -146,9 +154,7 @@ class SpaceSelectorState extends State { } int adjustIndex(int targetIndex, String id) { - int currentIndex = items.indexWhere( - (element) => element.id == id, - ); + int currentIndex = items.indexWhere((element) => element.id == id); if (currentIndex == -1) return targetIndex; @@ -188,12 +194,13 @@ class SpaceSelectorState extends State { childWhenDragging: Opacity( opacity: 0.1, child: buildSpaceIcon( - width: widget.width, - space: i.space, - displayName: i.space.displayName, - placeholderColor: i.space.color, - onUpdate: i.space.onUpdate, - avatar: i.space.avatar), + width: widget.width, + space: i.space, + displayName: i.space.displayName, + placeholderColor: i.space.color, + onUpdate: i.space.onUpdate, + avatar: i.space.avatar, + ), ), feedback: SizedBox( width: widget.width, @@ -201,112 +208,127 @@ class SpaceSelectorState extends State { child: Opacity( opacity: 0.5, child: buildSpaceIcon( - width: widget.width, - space: i.space, - placeholderColor: i.space.color, - displayName: i.space.displayName, - onUpdate: i.space.onUpdate, - avatar: i.space.avatar), + width: widget.width, + space: i.space, + placeholderColor: i.space.color, + displayName: i.space.displayName, + onUpdate: i.space.onUpdate, + avatar: i.space.avatar, + ), ), ), hitTestBehavior: HitTestBehavior.opaque, - child: DragTarget(onWillAcceptWithDetails: (details) { - return details.data.entry is SpaceSidebarEntry; - }, onAcceptWithDetails: (details) { - print( - "Create folder: ${(details.data.entry as SpaceSidebarEntry).space.displayName} --> ${i.space.displayName}"); + child: DragTarget( + onWillAcceptWithDetails: (details) { + return details.data.entry is SpaceSidebarEntry; + }, + onAcceptWithDetails: (details) { + print( + "Create folder: ${(details.data.entry as SpaceSidebarEntry).space.displayName} --> ${i.space.displayName}", + ); - var componentA = - i.space.client.getComponent()!; + var componentA = i.space.client + .getComponent()!; - var folderId = componentA.createFolder(i.space); + var folderId = componentA.createFolder(i.space); - var space = (details.data.entry as SpaceSidebarEntry).space; - var componentB = - space.client.getComponent()!; - - componentB.addToFolder(space, folderId, 1); - - componentA.save(); - componentB.save(); - }, builder: (context, candidateData, rejectedData) { - return tiamat.Tooltip( - text: i.space.displayName, - preferredDirection: AxisDirection.right, - child: SizedBox( - width: widget.width, - child: buildSpaceIcon( - space: i.space, - displayName: i.space.displayName, - onUpdate: i.space.onUpdate, - avatar: i.space.avatar, - notificationCount: i.space.displayNotificationCount, - highlightedNotificationCount: - i.space.displayHighlightedNotificationCount, - showAvatarForSpace: - widget.shouldShowAvatarForSpace?.call(i.space) ?? false, - userAvatar: i.space.client.self!.avatar, - userColor: i.space.client.self!.defaultColor, - userDisplayName: i.space.client.self!.displayName, + var space = (details.data.entry as SpaceSidebarEntry).space; + var componentB = space.client + .getComponent()!; + + componentB.addToFolder(space, folderId, 1); + + componentA.save(); + componentB.save(); + }, + builder: (context, candidateData, rejectedData) { + return tiamat.Tooltip( + text: i.space.displayName, + preferredDirection: AxisDirection.right, + child: SizedBox( width: widget.width, - onSelected: widget.onSelected, - placeholderColor: i.space.color, + child: buildSpaceIcon( + space: i.space, + displayName: i.space.displayName, + onUpdate: i.space.onUpdate, + avatar: i.space.avatar, + notificationCount: i.space.displayNotificationCount, + highlightedNotificationCount: + i.space.displayHighlightedNotificationCount, + showAvatarForSpace: + widget.shouldShowAvatarForSpace?.call(i.space) ?? false, + userAvatar: i.space.client.self!.avatar, + userColor: i.space.client.self!.defaultColor, + userDisplayName: i.space.client.self!.displayName, + width: widget.width, + onSelected: widget.onSelected, + placeholderColor: i.space.color, + ), ), - ), - ); - }), + ); + }, + ), ); } if (data case SpaceGroupSidebarEntry i) { return DragTarget( - key: ValueKey("space-group-${i.groupId}"), - onWillAcceptWithDetails: (details) { - if (preferences.expandedSpaceGroups.value.contains(i.groupId)) { - return false; - } + key: ValueKey("space-group-${i.groupId}"), + onWillAcceptWithDetails: (details) { + if (preferences.expandedSpaceGroups.value.contains(i.groupId)) { + return false; + } - Log.i("Folder will accept drag: $details"); - return details.data.entry is SpaceSidebarEntry; - }, - onAcceptWithDetails: (details) { - Log.i("Folder accepted drag: $details"); - var space = (details.data.entry as SpaceSidebarEntry).space; - var component = - space.client.getComponent()!; - component.addToFolder(space, i.id, 0); - component.save(); - }, - builder: (BuildContext context, List candidateData, - List rejectedData) { - return SpaceGroupWidget( - spaces: i.spaces, - width: widget.width, - folderId: i.groupId, - initiallyOpen: - preferences.expandedSpaceGroups.value.contains(i.groupId), - onExpansionStateChanged: (expanded) { - if (expanded && - !preferences.expandedSpaceGroups.value - .contains(i.groupId)) { - preferences.expandedSpaceGroups.add(i.groupId); - } else { - preferences.expandedSpaceGroups.remove(i.groupId); - } - }, - onSelected: widget.onSelected, - onDragStarted: onDragStarted, - onDragUpdate: onDragUpdate, - dragPosition: dragPosition, - onDragEnd: onDragEnd, - shouldShowAvatarForSpace: (space) => - widget.shouldShowAvatarForSpace?.call(space) ?? false, - ); - }); + Log.i("Folder will accept drag: $details"); + return details.data.entry is SpaceSidebarEntry; + }, + onAcceptWithDetails: (details) { + Log.i("Folder accepted drag: $details"); + var space = (details.data.entry as SpaceSidebarEntry).space; + var component = space.client.getComponent()!; + component.addToFolder(space, i.id, 0); + component.save(); + }, + builder: + ( + BuildContext context, + List candidateData, + List rejectedData, + ) { + return SpaceGroupWidget( + spaces: i.spaces, + width: widget.width, + folderId: i.groupId, + initiallyOpen: preferences.expandedSpaceGroups.value.contains( + i.groupId, + ), + onExpansionStateChanged: (expanded) { + if (expanded && + !preferences.expandedSpaceGroups.value.contains( + i.groupId, + )) { + preferences.expandedSpaceGroups.add(i.groupId); + } else { + preferences.expandedSpaceGroups.remove(i.groupId); + } + }, + onSelected: widget.onSelected, + onDragStarted: onDragStarted, + onDragUpdate: onDragUpdate, + dragPosition: dragPosition, + onDragEnd: onDragEnd, + shouldShowAvatarForSpace: (space) => + widget.shouldShowAvatarForSpace?.call(space) ?? false, + ); + }, + ); } return SizedBox( - width: widget.width, height: widget.width, child: Placeholder()); + width: widget.width, + height: widget.width, + child: Placeholder(), + ); } void onDragEnd(details) { @@ -328,47 +350,49 @@ class SpaceSelectorState extends State { }); } - static Widget buildSpaceIcon( - {required String displayName, - Stream? onUpdate, - ImageProvider? avatar, - ImageProvider? userAvatar, - Color? userColor, - String? userDisplayName, - Color? placeholderColor, - required double width, - void Function(Space space)? onSelected, - bool showAvatarForSpace = false, - int highlightedNotificationCount = 0, - int notificationCount = 0, - required Space space}) { + static Widget buildSpaceIcon({ + required String displayName, + Stream? onUpdate, + ImageProvider? avatar, + ImageProvider? userAvatar, + Color? userColor, + String? userDisplayName, + Color? placeholderColor, + required double width, + void Function(Space space)? onSelected, + bool showAvatarForSpace = false, + int highlightedNotificationCount = 0, + int notificationCount = 0, + required Space space, + }) { return Stack( alignment: Alignment.centerLeft, children: [ Padding( - padding: SpaceSelector.padding, - child: Padding( - padding: const EdgeInsets.fromLTRB(0, 2, 0, 2), - child: SpaceIcon( - displayName: displayName, - onUpdate: onUpdate, - avatar: avatar, - userAvatar: userAvatar, - spaceId: space.identifier, - clientId: space.client.identifier, - userColor: userColor, - userDisplayName: userDisplayName, - highlightedNotificationCount: highlightedNotificationCount, - notificationCount: notificationCount, - width: width, - placeholderColor: placeholderColor, - onTap: () { - onSelected?.call(space); - }, - showUser: showAvatarForSpace, - ), - )), - if (notificationCount > 0) messageOverlay() + padding: SpaceSelector.padding, + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 2, 0, 2), + child: SpaceIcon( + displayName: displayName, + onUpdate: onUpdate, + avatar: avatar, + userAvatar: userAvatar, + spaceId: space.identifier, + clientId: space.client.identifier, + userColor: userColor, + userDisplayName: userDisplayName, + highlightedNotificationCount: highlightedNotificationCount, + notificationCount: notificationCount, + width: width, + placeholderColor: placeholderColor, + onTap: () { + onSelected?.call(space); + }, + showUser: showAvatarForSpace, + ), + ), + ), + if (notificationCount > 0) messageOverlay(), ], ); } diff --git a/commet/lib/ui/molecules/space_viewer.dart b/commet/lib/ui/molecules/space_viewer.dart index ef8c27039..6fba017d7 100644 --- a/commet/lib/ui/molecules/space_viewer.dart +++ b/commet/lib/ui/molecules/space_viewer.dart @@ -4,11 +4,7 @@ import 'package:flutter/material.dart'; import '../../client/client.dart'; class SpaceViewer extends StatefulWidget { - const SpaceViewer( - this.space, { - super.key, - this.onRoomSelected, - }); + const SpaceViewer(this.space, {super.key, this.onRoomSelected}); final Space space; final void Function(Room, {bool bypassSpecialRoomType})? onRoomSelected; @@ -22,11 +18,9 @@ class _SpaceViewerState extends State { return Material( color: Colors.transparent, child: Padding( - padding: const EdgeInsets.all(8.0), - child: SpaceList( - widget.space, - onRoomSelected: widget.onRoomSelected, - )), + padding: const EdgeInsets.all(8.0), + child: SpaceList(widget.space, onRoomSelected: widget.onRoomSelected), + ), ); } } diff --git a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_attachments.dart b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_attachments.dart index ee31de7d8..814307f0e 100644 --- a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_attachments.dart +++ b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_attachments.dart @@ -3,8 +3,11 @@ import 'package:commet/ui/atoms/message_attachment.dart'; import 'package:flutter/material.dart'; class TimelineEventViewAttachments extends StatelessWidget { - const TimelineEventViewAttachments( - {required this.attachments, this.previewMedia = false, super.key}); + const TimelineEventViewAttachments({ + required this.attachments, + this.previewMedia = false, + super.key, + }); final List attachments; final bool previewMedia; @@ -12,15 +15,14 @@ class TimelineEventViewAttachments extends StatelessWidget { Widget build(BuildContext context) { return Wrap( children: attachments - .map((e) => Padding( - padding: const EdgeInsets.fromLTRB(0, 2, 2, 2), - child: RepaintBoundary( - child: MessageAttachment( - e, - previewMedia: previewMedia, - ), - ), - )) + .map( + (e) => Padding( + padding: const EdgeInsets.fromLTRB(0, 2, 2, 2), + child: RepaintBoundary( + child: MessageAttachment(e, previewMedia: previewMedia), + ), + ), + ) .toList(), ); } diff --git a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_generic.dart b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_generic.dart index f51d28e8d..7f82fc7bc 100644 --- a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_generic.dart +++ b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_generic.dart @@ -14,14 +14,15 @@ import 'package:tiamat/tiamat.dart' as tiamat; import 'package:tiamat/atoms/avatar.dart'; class TimelineEventViewGeneric extends StatefulWidget { - const TimelineEventViewGeneric( - {this.timeline, - this.initialEvent, - required this.initialIndex, - this.room, - this.onReadReceiptsTapped, - this.readReceipts = const [], - super.key}); + const TimelineEventViewGeneric({ + this.timeline, + this.initialEvent, + required this.initialIndex, + this.room, + this.onReadReceiptsTapped, + this.readReceipts = const [], + super.key, + }); final Timeline? timeline; final int initialIndex; final Room? room; @@ -39,22 +40,25 @@ class _TimelineEventViewGenericState extends State IconData? icon; ImageProvider? senderAvatar; - String messagePlaceholderSticker(String user) => - Intl.message("$user sent a sticker", - desc: "Message body for when a user sends a sticker", - args: [user], - name: "messagePlaceholderSticker"); - - String messagePlaceholderUserCreatedRoom(String user) => - Intl.message("$user created the room!", - desc: "Message body for when a user created the room", - args: [user], - name: "messagePlaceholderUserCreatedRoom"); - - String get errorMessageFailedToSend => Intl.message("Failed to send", - desc: - "Text that is placed below a message when the message fails to send", - name: "errorMessageFailedToSend"); + String messagePlaceholderSticker(String user) => Intl.message( + "$user sent a sticker", + desc: "Message body for when a user sends a sticker", + args: [user], + name: "messagePlaceholderSticker", + ); + + String messagePlaceholderUserCreatedRoom(String user) => Intl.message( + "$user created the room!", + desc: "Message body for when a user created the room", + args: [user], + name: "messagePlaceholderUserCreatedRoom", + ); + + String get errorMessageFailedToSend => Intl.message( + "Failed to send", + desc: "Text that is placed below a message when the message fails to send", + name: "errorMessageFailedToSend", + ); @override void initState() { @@ -99,10 +103,7 @@ class _TimelineEventViewGenericState extends State if (senderAvatar != null) Padding( padding: const EdgeInsets.fromLTRB(44, 0, 8, 0), - child: Avatar( - image: senderAvatar, - radius: 10, - ), + child: Avatar(image: senderAvatar, radius: 10), ), Flexible( child: Row( @@ -110,7 +111,7 @@ class _TimelineEventViewGenericState extends State Flexible(child: tiamat.Text.labelLow(text!)), ], ), - ) + ), ], ), ), @@ -128,7 +129,7 @@ class _TimelineEventViewGenericState extends State onTap: widget.onReadReceiptsTapped, ), ), - ) + ), ], ), ); diff --git a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_message.dart b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_message.dart index 082cca509..4ea37f314 100644 --- a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_message.dart +++ b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_message.dart @@ -32,20 +32,21 @@ import 'package:intl/intl.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class TimelineEventViewMessage extends StatefulWidget { - const TimelineEventViewMessage( - {super.key, - this.timeline, - this.room, - this.initialEvent, - this.isThreadTimeline = false, - this.overrideShowSender = false, - this.jumpToEvent, - this.readReceipts = const [], - this.onReadReceiptsTapped, - this.onDoubleTapMessage, - this.detailed = false, - this.previewMedia = false, - required this.initialIndex}); + const TimelineEventViewMessage({ + super.key, + this.timeline, + this.room, + this.initialEvent, + this.isThreadTimeline = false, + this.overrideShowSender = false, + this.jumpToEvent, + this.readReceipts = const [], + this.onReadReceiptsTapped, + this.onDoubleTapMessage, + this.detailed = false, + this.previewMedia = false, + required this.initialIndex, + }); final Function(String eventId)? jumpToEvent; @@ -76,9 +77,11 @@ class _TimelineEventViewMessageState extends State late bool mentionsRoom; late List mentions; - String get messageFailedToDecrypt => Intl.message("Failed to decrypt event", - desc: "Placeholde text for when a message fails to decrypt", - name: "messageFailedToDecrypt"); + String get messageFailedToDecrypt => Intl.message( + "Failed to decrypt event", + desc: "Placeholde text for when a message fails to decrypt", + name: "messageFailedToDecrypt", + ); GlobalKey reactionsKey = GlobalKey(); GlobalKey urlPreviewsKey = GlobalKey(); @@ -151,12 +154,14 @@ class _TimelineEventViewMessageState extends State var room = widget.room ?? widget.timeline?.room; if (room != null) { - return RoomMemberList.userContextMenu(context, - userId: senderId, - userDisplayName: senderName, - room: room, - child: child, - isSelf: senderId == room.client.self!.identifier); + return RoomMemberList.userContextMenu( + context, + userId: senderId, + userDisplayName: senderName, + room: room, + child: child, + isSelf: senderId == room.client.self!.identifier, + ); } return child; @@ -194,25 +199,30 @@ class _TimelineEventViewMessageState extends State ? TimelineEventViewReactions( key: reactionsKey, timeline: widget.timeline!, - initialIndex: index) + initialIndex: index, + ) : null, urlPreviews: previewComponent != null && doUrlPreview && widget.timeline != null - ? TimelineEventViewUrlPreviews( - initialIndex: index, - timeline: widget.timeline!, - component: previewComponent!, - key: urlPreviewsKey, - ) - : null, + ? TimelineEventViewUrlPreviews( + initialIndex: index, + timeline: widget.timeline!, + component: previewComponent!, + key: urlPreviewsKey, + ) + : null, thread: isHeadOfThread && widget.timeline != null ? TimelineEventViewThread( initialIndex: index, timeline: widget.timeline!, - component: threadComponent!) + component: threadComponent!, + ) : null, - onAvatarTapped: () => UserProfile.show(context, - client: widget.timeline!.client, userId: senderId), + onAvatarTapped: () => UserProfile.show( + context, + client: widget.timeline!.client, + userId: senderId, + ), ); } @@ -265,8 +275,7 @@ class _TimelineEventViewMessageState extends State sentTime = event.originServerTs; - var gifs = (widget.room ?? widget.timeline?.room) - ?.client + var gifs = (widget.room ?? widget.timeline?.room)?.client .getComponent(); isGif = gifs?.isGif(event) == true; @@ -275,8 +284,9 @@ class _TimelineEventViewMessageState extends State if (widget.timeline != null) { if (event is TimelineEventFeatureReactions) { - hasReactions = (event as TimelineEventFeatureReactions) - .hasReactions(widget.timeline!); + hasReactions = (event as TimelineEventFeatureReactions).hasReactions( + widget.timeline!, + ); } isHeadOfThread = @@ -296,7 +306,8 @@ class _TimelineEventViewMessageState extends State body = event.plainTextBody; } - isInResponse = event is TimelineEventFeatureRelated && + isInResponse = + event is TimelineEventFeatureRelated && (event as TimelineEventFeatureRelated).relationshipType == EventRelationshipType.reply; @@ -320,9 +331,12 @@ class _TimelineEventViewMessageState extends State attachments = event.attachments; - doUrlPreview = widget.timeline != null && + doUrlPreview = + widget.timeline != null && previewComponent?.shouldGetPreviewDataForTimelineEvent( - widget.timeline!, event) == + widget.timeline!, + event, + ) == true && event.getLinks(timeline: widget.timeline!)?.isEmpty == false; } @@ -449,7 +463,9 @@ class _TimelineEventViewMessageState extends State if (widget.isThreadTimeline == false && threadComponent?.isEventInResponseToThread( - prevEvent, widget.timeline!) == + prevEvent, + widget.timeline!, + ) == true) { return true; } @@ -457,7 +473,8 @@ class _TimelineEventViewMessageState extends State if (thisEvent.originServerTs .difference(prevEvent.originServerTs) .inMinutes > - 1) return true; + 1) + return true; if (thisEvent.senderId != prevEvent.senderId) { return true; @@ -468,12 +485,9 @@ class _TimelineEventViewMessageState extends State } markGifAsFavorite(bool favorite) async { - print( - "Marking gif as favorite: $favorite", - ); + print("Marking gif as favorite: $favorite"); - var gif = (widget.room ?? widget.timeline?.room) - ?.client + var gif = (widget.room ?? widget.timeline?.room)?.client .getComponent(); var event = widget.timeline!.events[index]; diff --git a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_poll.dart b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_poll.dart index 971667f0a..72caec095 100644 --- a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_poll.dart +++ b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_poll.dart @@ -13,8 +13,11 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class TimelineEventViewPoll extends StatefulWidget { - const TimelineEventViewPoll( - {required this.initialIndex, required this.timeline, super.key}); + const TimelineEventViewPoll({ + required this.initialIndex, + required this.timeline, + super.key, + }); final int initialIndex; final Timeline timeline; @@ -64,7 +67,8 @@ class _TimelineEventViewPollState extends State showSender: true, formattedContent: ConstrainedBox( constraints: BoxConstraints( - maxWidth: MediaQuery.of(context).desktop ? 500 : double.infinity), + maxWidth: MediaQuery.of(context).desktop ? 500 : double.infinity, + ), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -82,12 +86,13 @@ class _TimelineEventViewPollState extends State children: [ if (!showResults) tiamat.Text.labelLow( - "Results will be visible once the poll has ended"), - if (isFinished) tiamat.Text.labelLow("This poll has ended") + "Results will be visible once the poll has ended", + ), + if (isFinished) tiamat.Text.labelLow("This poll has ended"), ], ), ], - ) + ), ], ), ), @@ -150,9 +155,10 @@ class _TimelineEventViewPollState extends State itemBuilder: (context, index) { final id = responses!.elementAt(index); return UserPanel( - userId: id, - contextRoom: widget.timeline.room, - client: widget.timeline.client); + userId: id, + contextRoom: widget.timeline.room, + client: widget.timeline.client, + ); }, ), ), @@ -168,10 +174,13 @@ class _TimelineEventViewPollState extends State if (maxSelections > 1) { selectedAnswer = allowedAnswers - .where((i) => - pollResponses[i.id]?.contains( - widget.timeline.client.self!.identifier) == - true) + .where( + (i) => + pollResponses[i.id]?.contains( + widget.timeline.client.self!.identifier, + ) == + true, + ) .toList(growable: true); if (isOurResponse) { @@ -193,13 +202,15 @@ class _TimelineEventViewPollState extends State }, child: Container( decoration: BoxDecoration( - border: BoxBorder.all( - color: isOurResponse - ? ColorScheme.of(context).onSurface.withAlpha(150) - : Colors.transparent, - strokeAlign: BorderSide.strokeAlignInside, - width: 1.5), - borderRadius: BorderRadius.circular(8)), + border: BoxBorder.all( + color: isOurResponse + ? ColorScheme.of(context).onSurface.withAlpha(150) + : Colors.transparent, + strokeAlign: BorderSide.strokeAlignInside, + width: 1.5, + ), + borderRadius: BorderRadius.circular(8), + ), child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -209,9 +220,7 @@ class _TimelineEventViewPollState extends State spacing: 8, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - tiamat.Text( - answer.answer, - ), + tiamat.Text(answer.answer), if (showResults) Row( spacing: 8, @@ -219,15 +228,14 @@ class _TimelineEventViewPollState extends State SizedBox( width: 50, child: ReadIndicator( - spacing: 10, - room: widget.timeline.room, - users: responses ?? {}), + spacing: 10, + room: widget.timeline.room, + users: responses ?? {}, + ), ), - tiamat.Text( - (responses?.length ?? 0).toString(), - ) + tiamat.Text((responses?.length ?? 0).toString()), ], - ) + ), ], ), if (showResults) diff --git a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_reactions.dart b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_reactions.dart index b9a957224..48da48354 100644 --- a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_reactions.dart +++ b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_reactions.dart @@ -12,8 +12,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/material.dart' as material; class TimelineEventViewReactions extends StatefulWidget { - const TimelineEventViewReactions( - {required this.initialIndex, required this.timeline, super.key}); + const TimelineEventViewReactions({ + required this.initialIndex, + required this.timeline, + super.key, + }); final int initialIndex; final Timeline timeline; @@ -45,51 +48,51 @@ class _TimelineEventViewReactionsState extends State } return Wrap( - spacing: 3, - runSpacing: 3, - direction: material.Axis.horizontal, - children: reactions!.keys.map((key) { - var value = reactions![key]!; + spacing: 3, + runSpacing: 3, + direction: material.Axis.horizontal, + children: reactions!.keys.map((key) { + var value = reactions![key]!; - return EmojiReaction( - emoji: key, - onTapped: onReactionTapped, - onLongPressed: (emote) { - AdaptiveDialog.show( - context, - scrollable: false, - builder: (context) => SizedBox( - height: 400, - width: 400, - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: EmojiWidget( - key, - height: 40, - ), - ), - Expanded( - child: ListView.builder( - itemCount: value.length, - itemBuilder: (context, index) { - final id = value.elementAt(index % value.length); - return UserPanel( - userId: id, - contextRoom: widget.timeline.room, - client: widget.timeline.client); - }, - ), - ), - ], + return EmojiReaction( + emoji: key, + onTapped: onReactionTapped, + onLongPressed: (emote) { + AdaptiveDialog.show( + context, + scrollable: false, + builder: (context) => SizedBox( + height: 400, + width: 400, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: EmojiWidget(key, height: 40), ), - ), - ); - }, - numReactions: value.length, - highlighted: value.contains(currentUserIdentifier)); - }).toList()); + Expanded( + child: ListView.builder( + itemCount: value.length, + itemBuilder: (context, index) { + final id = value.elementAt(index % value.length); + return UserPanel( + userId: id, + contextRoom: widget.timeline.room, + client: widget.timeline.client, + ); + }, + ), + ), + ], + ), + ), + ); + }, + numReactions: value.length, + highlighted: value.contains(currentUserIdentifier), + ); + }).toList(), + ); } void onReactionTapped(Emoticon emote) { @@ -113,8 +116,9 @@ class _TimelineEventViewReactionsState extends State setState(() { final event = widget.timeline.events[index]; if (event is TimelineEventFeatureReactions) { - reactions = (event as TimelineEventFeatureReactions) - .getReactions(widget.timeline); + reactions = (event as TimelineEventFeatureReactions).getReactions( + widget.timeline, + ); } }); } diff --git a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_reply.dart b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_reply.dart index 3d258bd5c..a3092f046 100644 --- a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_reply.dart +++ b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_reply.dart @@ -8,12 +8,13 @@ import 'package:tiamat/tiamat.dart' as tiamat; import 'package:flutter/material.dart' as material; class TimelineEventViewReply extends StatefulWidget { - const TimelineEventViewReply( - {super.key, - required this.timeline, - required this.index, - this.jumpToEvent, - this.avatarSize = 32}); + const TimelineEventViewReply({ + super.key, + required this.timeline, + required this.index, + this.jumpToEvent, + this.avatarSize = 32, + }); final Timeline timeline; final Function(String eventId)? jumpToEvent; final int index; @@ -93,63 +94,73 @@ class _TimelineEventViewReplyState extends State { child: InkWell( onTap: () => widget.jumpToEvent?.call(replyEventId!), child: IntrinsicHeight( - child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - width: 45, - child: SizedBox.expand( - child: CustomPaint( - painter: ReplyLinePainter2( - pathColor: - material.Theme.of(context).colorScheme.secondary, - avatarSize: widget.avatarSize), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 45, + child: SizedBox.expand( + child: CustomPaint( + painter: ReplyLinePainter2( + pathColor: material.Theme.of(context) + .colorScheme + .secondary, + avatarSize: widget.avatarSize, + ), + ), ), ), - ), - Flexible( - child: RichText( + Flexible( + child: RichText( overflow: TextOverflow.ellipsis, maxLines: 2, - text: TextSpan(children: [ - TextSpan( + text: TextSpan( + children: [ + TextSpan( text: "${senderName ?? "Loading"} ", - style: Theme.of(context) - .textTheme - .bodyMedium + style: Theme.of(context).textTheme.bodyMedium ?.copyWith( - color: tiamat.Text.adjustColor( - context, senderColor ?? Colors.white))), - TextSpan( + color: tiamat.Text.adjustColor( + context, + senderColor ?? Colors.white, + ), + ), + ), + TextSpan( text: body ?? "Unknown", - style: Theme.of(context) - .textTheme - .bodySmall + style: Theme.of(context).textTheme.bodySmall ?.copyWith( - color: material.Theme.of(context) - .colorScheme - .secondary)), - ])), - ) - // Column( - // children: [ - // tiamat.Text( - // senderName ?? "Loading", - // color: senderColor, - // autoAdjustBrightness: true, - // ), - // ], - // ), - // Flexible( - // child: Padding( - // padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), - // child: tiamat.Text( - // body ?? "Unknown", - // maxLines: 2, - // overflow: TextOverflow.ellipsis, - // color: material.Theme.of(context).colorScheme.secondary, - // ), - // ), - // ), - ]), + color: material.Theme.of(context) + .colorScheme + .secondary, + ), + ), + ], + ), + ), + ), + // Column( + // children: [ + // tiamat.Text( + // senderName ?? "Loading", + // color: senderColor, + // autoAdjustBrightness: true, + // ), + // ], + // ), + // Flexible( + // child: Padding( + // padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), + // child: tiamat.Text( + // body ?? "Unknown", + // maxLines: 2, + // overflow: TextOverflow.ellipsis, + // color: material.Theme.of(context).colorScheme.secondary, + // ), + // ), + // ), + ], + ), ), ), ), @@ -163,12 +174,13 @@ class ReplyLinePainter2 extends CustomPainter { double radius; double padding; double avatarSize; - ReplyLinePainter2( - {this.pathColor = Colors.white, - this.strokeWidth = 1.5, - this.radius = 5, - this.avatarSize = 32, - this.padding = 4}) { + ReplyLinePainter2({ + this.pathColor = Colors.white, + this.strokeWidth = 1.5, + this.radius = 5, + this.avatarSize = 32, + this.padding = 4, + }) { _paint = Paint() ..color = pathColor ..style = PaintingStyle.stroke @@ -183,8 +195,10 @@ class ReplyLinePainter2 extends CustomPainter { Path path = Path(); path.moveTo(avatarSize / 2, size.height - padding); path.relativeLineTo(0, (-size.height + 9 + padding) + radius); - path.relativeArcToPoint(Offset(radius, -radius), - radius: Radius.circular(radius)); + path.relativeArcToPoint( + Offset(radius, -radius), + radius: Radius.circular(radius), + ); path.relativeLineTo(size.width - (avatarSize / 2) - radius - padding, 0); canvas.drawPath(path, _paint); } diff --git a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_sticker.dart b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_sticker.dart index 6cb9c7b6a..813cda58f 100644 --- a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_sticker.dart +++ b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_sticker.dart @@ -4,13 +4,15 @@ import 'package:intl/intl.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class TimelineEventViewSticker extends StatefulWidget { - const TimelineEventViewSticker(this.image, - {this.previewMedia = false, - this.stickerName, - this.isGif = false, - this.isFavoriteGif = false, - this.markAsFavorite, - super.key}); + const TimelineEventViewSticker( + this.image, { + this.previewMedia = false, + this.stickerName, + this.isGif = false, + this.isFavoriteGif = false, + this.markAsFavorite, + super.key, + }); final bool previewMedia; final String? stickerName; final ImageProvider image; @@ -29,11 +31,10 @@ class _TimelineEventViewStickerState extends State { bool isFavorite = false; static String get promptShowSticker => Intl.message( - "Show sticker", - name: "promptShowSticker", - desc: - "Prompt to display a sticker, shown when media previews are disabled", - ); + "Show sticker", + name: "promptShowSticker", + desc: "Prompt to display a sticker, shown when media previews are disabled", + ); @override void initState() { @@ -75,8 +76,8 @@ class _TimelineEventViewStickerState extends State { GestureDetector( onTap: widget.previewMedia == false ? () => setState(() { - showSticker = !showSticker; - }) + showSticker = !showSticker; + }) : null, child: Image( image: widget.image, @@ -88,24 +89,24 @@ class _TimelineEventViewStickerState extends State { Padding( padding: const EdgeInsets.all(2.0), child: SizedBox( - width: 30, - height: 30, - child: tiamat.CircleButton( - icon: isFavorite - ? Icons.star_rounded - : Icons.star_outline_rounded, - radius: 20, - color: ColorScheme.of(context) - .surfaceContainer - .withAlpha(80), - iconColor: isFavorite - ? ColorScheme.of(context).primary - : ColorScheme.of(context).onSurface, - onPressed: () { - widget.markAsFavorite?.call(!isFavorite); - }, - )), - ) + width: 30, + height: 30, + child: tiamat.CircleButton( + icon: isFavorite + ? Icons.star_rounded + : Icons.star_outline_rounded, + radius: 20, + color: ColorScheme.of(context).surfaceContainer + .withAlpha(80), + iconColor: isFavorite + ? ColorScheme.of(context).primary + : ColorScheme.of(context).onSurface, + onPressed: () { + widget.markAsFavorite?.call(!isFavorite); + }, + ), + ), + ), ], ), ) @@ -118,17 +119,18 @@ class _TimelineEventViewStickerState extends State { showSticker = !showSticker; }), child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - tiamat.Text.label(promptShowSticker), - if (widget.stickerName != null) - tiamat.Text.labelLow(widget.stickerName!) - ], + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + tiamat.Text.label(promptShowSticker), + if (widget.stickerName != null) + tiamat.Text.labelLow(widget.stickerName!), + ], + ), ), - )), + ), ), ), ), diff --git a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_thread.dart b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_thread.dart index b173e8e33..f01cd2b20 100644 --- a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_thread.dart +++ b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_thread.dart @@ -8,11 +8,12 @@ import 'package:commet/utils/event_bus.dart'; import 'package:flutter/material.dart'; class TimelineEventViewThread extends StatefulWidget { - const TimelineEventViewThread( - {super.key, - required this.initialIndex, - required this.timeline, - required this.component}); + const TimelineEventViewThread({ + super.key, + required this.initialIndex, + required this.timeline, + required this.component, + }); final int initialIndex; final Timeline timeline; @@ -40,8 +41,10 @@ class _TimelineEventViewThreadState extends State { void getStateFromIndex(int index) { var event = widget.timeline.events[index]; threadEventId = event.eventId; - var threadEvent = - widget.component.getFirstReplyToThread(event, widget.timeline); + var threadEvent = widget.component.getFirstReplyToThread( + event, + widget.timeline, + ); if (threadEvent == null) { return; } @@ -85,7 +88,7 @@ class _TimelineEventViewThreadState extends State { onTap: () => EventBus.openThread.add(( widget.timeline.client.identifier, widget.timeline.room.identifier, - threadEventId + threadEventId, )), ); } diff --git a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_url_previews.dart b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_url_previews.dart index a1c853ffc..9aa9a0825 100644 --- a/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_url_previews.dart +++ b/commet/lib/ui/molecules/timeline_events/events/timeline_event_view_url_previews.dart @@ -7,11 +7,12 @@ import 'package:commet/utils/links/link_utils.dart'; import 'package:flutter/material.dart'; class TimelineEventViewUrlPreviews extends StatefulWidget { - const TimelineEventViewUrlPreviews( - {required this.initialIndex, - required this.timeline, - required this.component, - super.key}); + const TimelineEventViewUrlPreviews({ + required this.initialIndex, + required this.timeline, + required this.component, + super.key, + }); final int initialIndex; final Timeline timeline; @@ -37,14 +38,15 @@ class _TimelineEventViewUrlPreviewsState if (data == UrlPreviewComponent.invalidPreviewData) return Container(); return Padding( - padding: const EdgeInsets.fromLTRB(0, 2, 40, 2), - child: UrlPreviewWidget( - key: key, - data, - onTap: () { - LinkUtils.open(data!.uri, context: context); - }, - )); + padding: const EdgeInsets.fromLTRB(0, 2, 40, 2), + child: UrlPreviewWidget( + key: key, + data, + onTap: () { + LinkUtils.open(data!.uri, context: context); + }, + ), + ); } @override @@ -74,25 +76,23 @@ class _TimelineEventViewUrlPreviewsState }); if (event.status == TimelineEventStatus.synced) { - widget.component.getPreview(widget.timeline, event).then( - (value) async { - if (mounted) { - final image = value?.image; - if (image != null) { - if (context.mounted) { - await precacheImage(image, context); - } + widget.component.getPreview(widget.timeline, event).then((value) async { + if (mounted) { + final image = value?.image; + if (image != null) { + if (context.mounted) { + await precacheImage(image, context); } - - if (mounted) - setState(() { - loading = false; - data = value; - key = GlobalKey(); - }); } - }, - ); + + if (mounted) + setState(() { + loading = false; + data = value; + key = GlobalKey(); + }); + } + }); } } } diff --git a/commet/lib/ui/molecules/timeline_events/layouts/timeline_event_layout_message.dart b/commet/lib/ui/molecules/timeline_events/layouts/timeline_event_layout_message.dart index d0a31a07e..77f05475a 100644 --- a/commet/lib/ui/molecules/timeline_events/layouts/timeline_event_layout_message.dart +++ b/commet/lib/ui/molecules/timeline_events/layouts/timeline_event_layout_message.dart @@ -4,28 +4,29 @@ import 'package:intl/intl.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class TimelineEventLayoutMessage extends StatelessWidget { - const TimelineEventLayoutMessage( - {super.key, - required this.senderName, - required this.senderColor, - this.viaSenderName, - this.senderAvatar, - this.formattedContent, - this.attachments, - this.inResponseTo, - this.reactions, - this.timestamp, - this.sticker, - this.thread, - this.urlPreviews, - this.readReceipts, - this.onAvatarTapped, - this.edited = false, - this.isMentioningSelf = false, - this.avatarSize = 32, - this.avatarBuilder, - this.showSender = true, - this.onDoubleTapMessage}); + const TimelineEventLayoutMessage({ + super.key, + required this.senderName, + required this.senderColor, + this.viaSenderName, + this.senderAvatar, + this.formattedContent, + this.attachments, + this.inResponseTo, + this.reactions, + this.timestamp, + this.sticker, + this.thread, + this.urlPreviews, + this.readReceipts, + this.onAvatarTapped, + this.edited = false, + this.isMentioningSelf = false, + this.avatarSize = 32, + this.avatarBuilder, + this.showSender = true, + this.onDoubleTapMessage, + }); final String senderName; final Color senderColor; final String? viaSenderName; @@ -48,15 +49,18 @@ class TimelineEventLayoutMessage extends StatelessWidget { final double avatarSize; - String get messageEditedMarker => Intl.message("(Edited)", - name: "messageEditedMarker", - desc: "Short text to mark that a message has been edited"); + String get messageEditedMarker => Intl.message( + "(Edited)", + name: "messageEditedMarker", + desc: "Short text to mark that a message has been edited", + ); - String messageSentViaProfile(String sender) => Intl.message("via $sender", - name: "messageSentViaProfile", - desc: - "Shows the real name of the account which sent a message with a per message profile", - args: [sender]); + String messageSentViaProfile(String sender) => Intl.message( + "via $sender", + name: "messageSentViaProfile", + desc: "Shows the real name of the account which sent a message with a per message profile", + args: [sender], + ); @override Widget build(BuildContext context) { @@ -109,24 +113,25 @@ class TimelineEventLayoutMessage extends StatelessWidget { if (urlPreviews != null) urlPreviews!, if (reactions != null) Padding( - padding: - const EdgeInsets.fromLTRB(0, 4, 0, 0), + padding: const EdgeInsets.fromLTRB( + 0, + 4, + 0, + 0, + ), child: reactions!, ), ], ), ), ), - SizedBox( - width: 35, - child: readReceipts, - ) + SizedBox(width: 35, child: readReceipts), ], - ) + ), ], ), ), - ) + ), ], ), if (thread != null) thread!, @@ -137,12 +142,14 @@ class TimelineEventLayoutMessage extends StatelessWidget { if (isMentioningSelf) result = Container( decoration: BoxDecoration( - border: Border( - left: BorderSide( - color: Theme.of(context).colorScheme.tertiary, - width: mentionHighlightSize)), - color: - Theme.of(context).colorScheme.tertiaryContainer.withAlpha(30)), + border: Border( + left: BorderSide( + color: Theme.of(context).colorScheme.tertiary, + width: mentionHighlightSize, + ), + ), + color: Theme.of(context).colorScheme.tertiaryContainer.withAlpha(30), + ), child: Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), child: result, @@ -157,10 +164,7 @@ class TimelineEventLayoutMessage extends StatelessWidget { cursor: SystemMouseCursors.click, child: GestureDetector( onTap: onAvatarTapped, - child: tiamat.Text.name( - senderName, - color: senderColor, - ), + child: tiamat.Text.name(senderName, color: senderColor), ), ); diff --git a/commet/lib/ui/molecules/timeline_events/timeline_event_date_time_marker.dart b/commet/lib/ui/molecules/timeline_events/timeline_event_date_time_marker.dart index 5dd3de649..687c67bc8 100644 --- a/commet/lib/ui/molecules/timeline_events/timeline_event_date_time_marker.dart +++ b/commet/lib/ui/molecules/timeline_events/timeline_event_date_time_marker.dart @@ -17,10 +17,7 @@ class TimelineEventDateTimeMarker extends StatelessWidget { Expanded( child: Opacity( opacity: 0.1, - child: Divider( - height: 1, - color: color, - ), + child: Divider(height: 1, color: color), ), ), Padding( @@ -33,10 +30,7 @@ class TimelineEventDateTimeMarker extends StatelessWidget { Expanded( child: Opacity( opacity: 0.1, - child: Divider( - height: 1, - color: color, - ), + child: Divider(height: 1, color: color), ), ), ], diff --git a/commet/lib/ui/molecules/timeline_events/timeline_event_menu.dart b/commet/lib/ui/molecules/timeline_events/timeline_event_menu.dart index f9c70acc3..c9768c429 100644 --- a/commet/lib/ui/molecules/timeline_events/timeline_event_menu.dart +++ b/commet/lib/ui/molecules/timeline_events/timeline_event_menu.dart @@ -49,61 +49,58 @@ class TimelineEventMenu { final bool isThreadTimeline; String get promptPinMessage => Intl.message( - "Pin Message", - desc: "Label for the menu option to pin a message", - name: "promptPinMessage", - ); + "Pin Message", + desc: "Label for the menu option to pin a message", + name: "promptPinMessage", + ); String get promptUnpinMessage => Intl.message( - "Unpin Message", - desc: "Label for the menu option to unpin a message", - name: "promptUnpinMessage", - ); + "Unpin Message", + desc: "Label for the menu option to unpin a message", + name: "promptUnpinMessage", + ); String get promptReplyInThread => Intl.message( - "Reply In Thread", - desc: "Label for the menu option to reply to a message inside a thread", - name: "promptReplyInThread", - ); + "Reply In Thread", + desc: "Label for the menu option to reply to a message inside a thread", + name: "promptReplyInThread", + ); String get promptShowSource => Intl.message( - "Show Source", - desc: "Label for the menu option to view the JSON source of an event", - name: "promptShowSource", - ); + "Show Source", + desc: "Label for the menu option to view the JSON source of an event", + name: "promptShowSource", + ); String get promptReplayMessageEffect => Intl.message( - "Replay Effect", - desc: - "If a message was sent with an effect, this prompts to replay the effect", - name: "promptReplayMessageEffect", - ); + "Replay Effect", + desc: "If a message was sent with an effect, this prompts to replay the effect", + name: "promptReplayMessageEffect", + ); String get promptCancelEventSend => Intl.message( - "Cancel", - desc: - "When a message failed to send, this prompts to cancel sending the event", - name: "promptCancelEventSend", - ); + "Cancel", + desc: "When a message failed to send, this prompts to cancel sending the event", + name: "promptCancelEventSend", + ); String get promptRetryEventSend => Intl.message( - "Retry", - desc: - "When a message failed to send, this prompts to retry sending the event", - name: "promptRetryEventSend", - ); + "Retry", + desc: "When a message failed to send, this prompts to retry sending the event", + name: "promptRetryEventSend", + ); String get promptEndPoll => Intl.message( - "End Poll", - desc: "Prompt the user to end a poll", - name: "promptEndPoll", - ); + "End Poll", + desc: "Prompt the user to end a poll", + name: "promptEndPoll", + ); String get promptFavoriteGif => Intl.message( - "Favorite GIF", - desc: "Prompt the user to mark a gif as a favorite", - name: "promptFavoriteGif", - ); + "Favorite GIF", + desc: "Prompt the user to mark a gif as a favorite", + name: "promptFavoriteGif", + ); TimelineEventMenu({ required this.timeline, @@ -142,15 +139,18 @@ class TimelineEventMenu { List? links; if (event.status == TimelineEventStatus.synced) { - canEditEvent = event is TimelineEventMessage && + canEditEvent = + event is TimelineEventMessage && timeline.room.permissions.canUserEditMessages && event.senderId == timeline.room.client.self!.identifier && setEditingEvent != null; - canDeleteEvent = timeline.canDeleteEvent(event) && + canDeleteEvent = + timeline.canDeleteEvent(event) && event.status == TimelineEventStatus.synced; - canReply = event is TimelineEventMessage || + canReply = + event is TimelineEventMessage || event is TimelineEventSticker || event is TimelineEventEmote; @@ -173,7 +173,7 @@ class TimelineEventMenu { canAddReaction = (event is TimelineEventMessage || event is TimelineEventSticker) && - emoticons != null; + emoticons != null; canReplyInThread = !isThreadTimeline && event is TimelineEventMessage; @@ -184,7 +184,8 @@ class TimelineEventMenu { canEndPoll = true; } - canEditPinState = pins?.canPinMessages == true && + canEditPinState = + pins?.canPinMessages == true && (event is TimelineEventMessage || event is TimelineEventSticker || event is TimelineEventEmote); @@ -197,8 +198,8 @@ class TimelineEventMenu { hasEffect = effects?.hasEffect(event) == true; } - var reactions = - timeline.room.client.getComponent(); + var reactions = timeline.room.client + .getComponent(); if (reactions != null && canAddReaction) { recentReactions = reactions.getRecentReactionEmoticon(timeline.room); } else { @@ -214,30 +215,36 @@ class TimelineEventMenu { if (recent != null && recent.isNotEmpty) { availableEmoji.insert( - 0, - DynamicEmoticonPack( - identifier: "dynamic_pack_frequently_used_reactions", - displayName: "Frequently Used", - icon: Icons.schedule, - emoticons: recent, - usage: EmoticonUsage.all)); + 0, + DynamicEmoticonPack( + identifier: "dynamic_pack_frequently_used_reactions", + displayName: "Frequently Used", + icon: Icons.schedule, + emoticons: recent, + usage: EmoticonUsage.all, + ), + ); } addReactionAction = TimelineEventMenuEntry( name: CommonStrings.promptAddReaction, icon: Icons.add_reaction, secondaryMenuBuilder: (context, dismissSecondaryMenu) { - return EmojiPicker(availableEmoji, - searchDelegate: (search) => AutofillUtils.searchEmoticon(search, - client: timeline.client, room: timeline.room, limit: 50) - .whereType() - .toList(), - preferredTooltipDirection: AxisDirection.left, - onEmoticonPressed: (emote) async { - timeline.room.addReaction(event, emote); - await Future.delayed(const Duration(milliseconds: 100)); - dismissSecondaryMenu(); - }); + return EmojiPicker( + availableEmoji, + searchDelegate: (search) => AutofillUtils.searchEmoticon( + search, + client: timeline.client, + room: timeline.room, + limit: 50, + ).whereType().toList(), + preferredTooltipDirection: AxisDirection.left, + onEmoticonPressed: (emote) async { + timeline.room.addReaction(event, emote); + await Future.delayed(const Duration(milliseconds: 100)); + dismissSecondaryMenu(); + }, + ); }, ); } @@ -268,10 +275,13 @@ class TimelineEventMenu { name: promptEndPoll, icon: Icons.poll, action: (context) async { - if (await AdaptiveDialog.confirmation(context, - title: promptEndPoll, - prompt: "Are you sure you want to end the poll?") == - true) polls?.endPoll(timeline.room, event); + if (await AdaptiveDialog.confirmation( + context, + title: promptEndPoll, + prompt: "Are you sure you want to end the poll?", + ) == + true) + polls?.endPoll(timeline.room, event); onActionFinished?.call(); }, @@ -337,16 +347,17 @@ class TimelineEventMenu { ), if (canSaveAttachment) TimelineEventMenuEntry( - name: CommonStrings.promptDownload, - icon: Icons.download, - action: (BuildContext context) { - var attachment = - (event as TimelineEventMessage).attachments?.firstOrNull; - if (attachment != null) { - DownloadUtils.downloadAttachment(attachment); - } - onActionFinished?.call(); - }), + name: CommonStrings.promptDownload, + icon: Icons.download, + action: (BuildContext context) { + var attachment = + (event as TimelineEventMessage).attachments?.firstOrNull; + if (attachment != null) { + DownloadUtils.downloadAttachment(attachment); + } + onActionFinished?.call(); + }, + ), if (canDeleteEvent) TimelineEventMenuEntry( name: CommonStrings.promptDelete, @@ -401,50 +412,49 @@ class TimelineEventMenu { ), if (canCopy) TimelineEventMenuEntry( - name: CommonStrings.promptCopy, - icon: Icons.copy, - action: (context) { - Clipboard.setData(ClipboardData( + name: CommonStrings.promptCopy, + icon: Icons.copy, + action: (context) { + Clipboard.setData( + ClipboardData( text: (event as TimelineEventMessage).plainTextBody, - )); - }), + ), + ); + }, + ), if (links?.isNotEmpty == true) TimelineEventMenuEntry( - name: "Copy Link", - icon: Icons.link, - action: (context) async { - if (links!.length > 1) { - var selected = await AdaptiveDialog.pickOne( - context, - items: links, - itemBuilder: (context, item, callback) => SizedBox( - height: 50, - child: tiamat.TextButton( - item.toString(), - icon: Icons.link, - onTap: () { - callback(); - - if (MediaQuery.of(context).layout == - LayoutType.mobile) { - Navigator.of(context).pop(); - } - }, - ), + name: "Copy Link", + icon: Icons.link, + action: (context) async { + if (links!.length > 1) { + var selected = await AdaptiveDialog.pickOne( + context, + items: links, + itemBuilder: (context, item, callback) => SizedBox( + height: 50, + child: tiamat.TextButton( + item.toString(), + icon: Icons.link, + onTap: () { + callback(); + + if (MediaQuery.of(context).layout == LayoutType.mobile) { + Navigator.of(context).pop(); + } + }, ), - ); + ), + ); - if (selected != null) { - Clipboard.setData(ClipboardData( - text: selected.toString(), - )); - } - } else { - Clipboard.setData(ClipboardData( - text: links.first.toString(), - )); + if (selected != null) { + Clipboard.setData(ClipboardData(text: selected.toString())); } - }), + } else { + Clipboard.setData(ClipboardData(text: links.first.toString())); + } + }, + ), TimelineEventMenuEntry( name: promptShowSource, icon: Icons.code, @@ -459,7 +469,10 @@ class TimelineEventMenu { width: 1000, child: SelectionArea( child: ExpandableCodeBlock( - expanded: true, text: event.source, language: "json"), + expanded: true, + text: event.source, + language: "json", + ), ), ); }, @@ -490,12 +503,14 @@ class TimelineEventMenu { name: "Diagnose Notification", icon: Icons.notification_important, action: (BuildContext context) async { - AdaptiveDialog.show(context, - builder: (context) => NotificationDebugger( - event: event, - client: timeline.client, - room: timeline.room, - )); + AdaptiveDialog.show( + context, + builder: (context) => NotificationDebugger( + event: event, + client: timeline.client, + room: timeline.room, + ), + ); }, ), ]; @@ -508,7 +523,7 @@ class TimelineEventMenuEntry { final IconData icon; final Widget Function(BuildContext context, Function() dismissMenu)? - secondaryMenuBuilder; + secondaryMenuBuilder; TimelineEventMenuEntry({ required this.name, diff --git a/commet/lib/ui/molecules/timeline_events/timeline_event_menu_dialog.dart b/commet/lib/ui/molecules/timeline_events/timeline_event_menu_dialog.dart index fc5372bcc..dfdd24b89 100644 --- a/commet/lib/ui/molecules/timeline_events/timeline_event_menu_dialog.dart +++ b/commet/lib/ui/molecules/timeline_events/timeline_event_menu_dialog.dart @@ -9,11 +9,12 @@ import 'package:tiamat/atoms/seperator.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class TimelineEventMenuDialog extends StatelessWidget { - const TimelineEventMenuDialog( - {required this.event, - required this.timeline, - required this.menu, - super.key}); + const TimelineEventMenuDialog({ + required this.event, + required this.timeline, + required this.menu, + super.key, + }); final TimelineEvent event; final Timeline timeline; @@ -49,10 +50,7 @@ class TimelineEventMenuDialog extends StatelessWidget { return const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, - colors: [ - Colors.white, - Colors.transparent, - ], + colors: [Colors.white, Colors.transparent], stops: [0.80, 1.0], ).createShader(bounds); }, @@ -74,9 +72,7 @@ class TimelineEventMenuDialog extends StatelessWidget { ), ), ), - SizedBox( - height: 10, - ), + SizedBox(height: 10), if (menu.addReactionAction != null) Row( mainAxisAlignment: MainAxisAlignment.spaceAround, @@ -95,10 +91,7 @@ class TimelineEventMenuDialog extends StatelessWidget { }, child: Padding( padding: const EdgeInsets.all(8.0), - child: EmojiWidget( - emote, - height: emojiSize, - ), + child: EmojiWidget(emote, height: emojiSize), ), ), ), @@ -113,21 +106,27 @@ class TimelineEventMenuDialog extends StatelessWidget { doAction(menu.addReactionAction!, context); }, ), - ) + ), ], ), for (var action in menu.primaryActions) SizedBox( height: 50, - child: tiamat.TextButton(action.name, - icon: action.icon, onTap: () => doAction(action, context)), + child: tiamat.TextButton( + action.name, + icon: action.icon, + onTap: () => doAction(action, context), + ), ), const Seperator(), for (var action in menu.secondaryActions) SizedBox( height: 50, - child: tiamat.TextButton(action.name, - icon: action.icon, onTap: () => doAction(action, context)), + child: tiamat.TextButton( + action.name, + icon: action.icon, + onTap: () => doAction(action, context), + ), ), ], ), diff --git a/commet/lib/ui/molecules/timeline_events/timeline_event_view_single.dart b/commet/lib/ui/molecules/timeline_events/timeline_event_view_single.dart index 02b9156d7..ba3b71c8f 100644 --- a/commet/lib/ui/molecules/timeline_events/timeline_event_view_single.dart +++ b/commet/lib/ui/molecules/timeline_events/timeline_event_view_single.dart @@ -6,8 +6,11 @@ import 'package:commet/ui/molecules/timeline_events/timeline_view_entry.dart'; import 'package:flutter/material.dart'; class TimelineEventViewSingle extends StatelessWidget { - const TimelineEventViewSingle( - {required this.room, required this.event, super.key}); + const TimelineEventViewSingle({ + required this.room, + required this.event, + super.key, + }); final TimelineEvent event; final Room room; diff --git a/commet/lib/ui/molecules/timeline_events/timeline_view_entry.dart b/commet/lib/ui/molecules/timeline_events/timeline_view_entry.dart index fa0079daa..143506602 100644 --- a/commet/lib/ui/molecules/timeline_events/timeline_view_entry.dart +++ b/commet/lib/ui/molecules/timeline_events/timeline_view_entry.dart @@ -31,21 +31,22 @@ import 'package:tiamat/atoms/text.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class TimelineViewEntry extends StatefulWidget { - const TimelineViewEntry( - {required this.timeline, - required this.initialIndex, - this.onEventHovered, - this.setEditingEvent, - this.setReplyingEvent, - this.jumpToEvent, - this.showDetailed = false, - this.singleEvent = false, - this.isThreadTimeline = false, - this.previewMedia = false, - this.lastReadEventId, - this.highlightedEventId, - this.canCollapse = false, - super.key}); + const TimelineViewEntry({ + required this.timeline, + required this.initialIndex, + this.onEventHovered, + this.setEditingEvent, + this.setReplyingEvent, + this.jumpToEvent, + this.showDetailed = false, + this.singleEvent = false, + this.isThreadTimeline = false, + this.previewMedia = false, + this.lastReadEventId, + this.highlightedEventId, + this.canCollapse = false, + super.key, + }); final Timeline timeline; final int initialIndex; final Function(String eventId)? onEventHovered; @@ -80,10 +81,7 @@ enum TimelineEventWidgetDisplayType { hidden, } -enum TimelineEventWidgetCollapseType { - root, - child, -} +enum TimelineEventWidgetCollapseType { root, child } class TimelineViewEntryState extends State implements TimelineEventViewWidget, SelectableEventViewWidget { @@ -116,17 +114,22 @@ class TimelineViewEntryState extends State List readReceipts = []; - String get labelTimelineNewMessagesMarker => Intl.message("New messages", - desc: "Text that is shown below the last read message", - name: "labelTimelineNewMessagesMarker"); + String get labelTimelineNewMessagesMarker => Intl.message( + "New messages", + desc: "Text that is shown below the last read message", + name: "labelTimelineNewMessagesMarker", + ); @override void initState() { threads = widget.timeline.room.client.getComponent(); polls = widget.timeline.client.getComponent(); - isThreadReply = threads?.isEventInResponseToThread( - widget.timeline.events[widget.initialIndex], widget.timeline) ?? + isThreadReply = + threads?.isEventInResponseToThread( + widget.timeline.events[widget.initialIndex], + widget.timeline, + ) ?? false; loadState(widget.initialIndex); @@ -197,14 +200,16 @@ class TimelineViewEntryState extends State bool isEventTypeCollapsible(TimelineEventWidgetDisplayType eventType) { const collapsibleTypes = [ TimelineEventWidgetDisplayType.generic, - TimelineEventWidgetDisplayType.hidden + TimelineEventWidgetDisplayType.hidden, ]; return collapsibleTypes.contains(eventType); } - static TimelineEventWidgetDisplayType eventToDisplayType(TimelineEvent event, - {PollComponent? polls}) { + static TimelineEventWidgetDisplayType eventToDisplayType( + TimelineEvent event, { + PollComponent? polls, + }) { if (event is TimelineEventMessage || event is TimelineEventSticker || event is TimelineEventEncrypted) { @@ -241,7 +246,9 @@ class TimelineViewEntryState extends State if (widget.isThreadTimeline) { if (threads?.isHeadOfThread( - widget.timeline.events[index], widget.timeline) == + widget.timeline.events[index], + widget.timeline, + ) == true) { return true; } @@ -268,7 +275,8 @@ class TimelineViewEntryState extends State if (widget.timeline.events[index].originServerTs .difference(widget.timeline.events[offsetIndex].originServerTs) .inHours > - 2) return true; + 2) + return true; return false; } @@ -302,7 +310,8 @@ class TimelineViewEntryState extends State if (collapse != null && preferences.showStateEvents.value == false && - preferences.developerMode.value == false) return Container(); + preferences.developerMode.value == false) + return Container(); var result = buildEvent(); @@ -359,9 +368,9 @@ class TimelineViewEntryState extends State canCollapse: false, highlightedEventId: widget.highlightedEventId, onEventHovered: widget.onEventHovered, - ) + ), ], - ) + ), ], ); } @@ -372,10 +381,7 @@ class TimelineViewEntryState extends State if (status == TimelineEventStatus.sending || status == TimelineEventStatus.error) { - result = Opacity( - opacity: 0.5, - child: result, - ); + result = Opacity(opacity: 0.5, child: result); } if (status == TimelineEventStatus.error) { @@ -411,23 +417,24 @@ class TimelineViewEntryState extends State } showModalBottomSheet( - showDragHandle: true, - isScrollControlled: true, - elevation: 0, - context: context, - builder: (context) => TimelineEventMenuDialog( - event: event, - timeline: widget.timeline, - menu: TimelineEventMenu( - timeline: widget.timeline, - isThreadTimeline: widget.isThreadTimeline, - event: event, - context: context, - setEditingEvent: widget.setEditingEvent, - setReplyingEvent: widget.setReplyingEvent, - onActionFinished: () => Navigator.of(context).pop(), - ), - )); + showDragHandle: true, + isScrollControlled: true, + elevation: 0, + context: context, + builder: (context) => TimelineEventMenuDialog( + event: event, + timeline: widget.timeline, + menu: TimelineEventMenu( + timeline: widget.timeline, + isThreadTimeline: widget.isThreadTimeline, + event: event, + context: context, + setEditingEvent: widget.setEditingEvent, + setReplyingEvent: widget.setReplyingEvent, + onActionFinished: () => Navigator.of(context).pop(), + ), + ), + ); }, child: result, ); @@ -437,73 +444,84 @@ class TimelineViewEntryState extends State var event = widget.timeline.tryGetEvent(eventId); if (event != null) { var menu = TimelineEventMenu( - timeline: widget.timeline, - event: event, - context: context, - setEditingEvent: widget.setEditingEvent, - setReplyingEvent: widget.setReplyingEvent); - result = AdaptiveContextMenu(items: [ - if (menu.addReactionAction != null) - ContextMenuItem( - text: "Add Reaction", - customBuilder: (context, onClick, {closeMenu}) => Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - for (var i = 0; + timeline: widget.timeline, + event: event, + context: context, + setEditingEvent: widget.setEditingEvent, + setReplyingEvent: widget.setReplyingEvent, + ); + result = AdaptiveContextMenu( + items: [ + if (menu.addReactionAction != null) + ContextMenuItem( + text: "Add Reaction", + customBuilder: (context, onClick, {closeMenu}) => Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + for ( + var i = 0; i < 3 && i < menu.recentReactions.length; - i++) - InkWell( + i++ + ) + InkWell( onTap: () { - widget.timeline.room - .addReaction(event, menu.recentReactions[i]); + widget.timeline.room.addReaction( + event, + menu.recentReactions[i], + ); onClick(); }, child: SizedBox( - height: 30, - width: 30, - child: EmojiWidget(menu.recentReactions[i]))), - tiamat.IconButton( - icon: Icons.add_reaction, - size: 24, - onPressed: () { - onClick(); - - AdaptiveDialog.show( - context, - builder: (newContext) { - return SizedBox( + height: 30, + width: 30, + child: EmojiWidget(menu.recentReactions[i]), + ), + ), + tiamat.IconButton( + icon: Icons.add_reaction, + size: 24, + onPressed: () { + onClick(); + + AdaptiveDialog.show( + context, + builder: (newContext) { + return SizedBox( width: 500, height: 500, child: menu - .addReactionAction!.secondaryMenuBuilder! - .call( - newContext, - () { - Navigator.of(newContext).pop(); - }, - )); - }, - ); - menu.addReactionAction?.action?.call(context); - }, - ) - ], + .addReactionAction! + .secondaryMenuBuilder! + .call(newContext, () { + Navigator.of(newContext).pop(); + }), + ); + }, + ); + menu.addReactionAction?.action?.call(context); + }, + ), + ], + ), ), ), - ), - for (var i in menu.primaryActions) - ContextMenuItem( + for (var i in menu.primaryActions) + ContextMenuItem( text: i.name, icon: i.icon, - onPressed: () => i.action?.call(context)), - for (var i in menu.secondaryActions) - ContextMenuItem( + onPressed: () => i.action?.call(context), + ), + for (var i in menu.secondaryActions) + ContextMenuItem( text: i.name, icon: i.icon, - onPressed: () => i.action?.call(context)) - ], child: result); + onPressed: () => i.action?.call(context), + ), + ], + child: result, + ); } } @@ -517,10 +535,14 @@ class TimelineViewEntryState extends State if (highlighted) { result = Container( decoration: BoxDecoration( - border: Border( - left: BorderSide( - color: Theme.of(context).colorScheme.primary, width: 3)), - color: Theme.of(context).colorScheme.surfaceContainer), + border: Border( + left: BorderSide( + color: Theme.of(context).colorScheme.primary, + width: 3, + ), + ), + color: Theme.of(context).colorScheme.surfaceContainer, + ), child: Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), child: result, @@ -533,21 +555,23 @@ class TimelineViewEntryState extends State alignment: Alignment.topRight, children: [ CompositedTransformTarget( - link: timelineLayerLink!, child: const SizedBox()), - result + link: timelineLayerLink!, + child: const SizedBox(), + ), + result, ], ); } if (showUnreadMarker) { - result = Column(children: [ - buildNewMessagesMarker(), - result, - ]); + result = Column(children: [buildNewMessagesMarker(), result]); } else { if (showDateSeperator) { result = Column( - children: [TimelineEventDateTimeMarker(time: time), result], + children: [ + TimelineEventDateTimeMarker(time: time), + result, + ], ); } } @@ -562,15 +586,12 @@ class TimelineViewEntryState extends State child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Expanded( - child: Divider( - color: color, - thickness: 1.0, - )), + Expanded(child: Divider(color: color, thickness: 1.0)), DecoratedBox( decoration: BoxDecoration( - color: Colors.transparent, - borderRadius: BorderRadius.circular(12)), + color: Colors.transparent, + borderRadius: BorderRadius.circular(12), + ), child: Padding( padding: EdgeInsets.symmetric(horizontal: 15, vertical: 3), child: tiamat.Text( @@ -580,11 +601,7 @@ class TimelineViewEntryState extends State ), ), ), - Expanded( - child: Divider( - color: color, - thickness: 1.0, - )), + Expanded(child: Divider(color: color, thickness: 1.0)), ], ), ); @@ -603,17 +620,18 @@ class TimelineViewEntryState extends State if (_widgetType == TimelineEventWidgetDisplayType.message) return TimelineEventViewMessage( - key: eventKey, - timeline: widget.timeline, - isThreadTimeline: widget.isThreadTimeline, - detailed: widget.showDetailed || selected, - onReadReceiptsTapped: onReadReceiptsTapped, - readReceipts: readReceipts, - overrideShowSender: - widget.singleEvent || showDateSeperator || showUnreadMarker, - jumpToEvent: widget.jumpToEvent, - previewMedia: widget.previewMedia, - initialIndex: widget.initialIndex); + key: eventKey, + timeline: widget.timeline, + isThreadTimeline: widget.isThreadTimeline, + detailed: widget.showDetailed || selected, + onReadReceiptsTapped: onReadReceiptsTapped, + readReceipts: readReceipts, + overrideShowSender: + widget.singleEvent || showDateSeperator || showUnreadMarker, + jumpToEvent: widget.jumpToEvent, + previewMedia: widget.previewMedia, + initialIndex: widget.initialIndex, + ); if (_widgetType == TimelineEventWidgetDisplayType.generic && (preferences.showStateEvents.value || preferences.developerMode.value)) @@ -659,9 +677,7 @@ class TimelineViewEntryState extends State onReadReceiptsTapped: onReadReceiptsTapped, readReceipts: readReceipts, ) - : Container( - key: eventKey, - ); + : Container(key: eventKey); } @override @@ -690,16 +706,23 @@ class TimelineViewEntryState extends State } onReadReceiptsTapped() { - AdaptiveDialog.show(context, title: "Read Receipts", builder: (context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: readReceipts - .map((i) => UserPanel( - userId: i, - client: widget.timeline.client, - contextRoom: widget.timeline.room)) - .toList(), - ); - }); + AdaptiveDialog.show( + context, + title: "Read Receipts", + builder: (context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: readReceipts + .map( + (i) => UserPanel( + userId: i, + client: widget.timeline.client, + contextRoom: widget.timeline.room, + ), + ) + .toList(), + ); + }, + ); } } diff --git a/commet/lib/ui/molecules/typing_indicators_widget.dart b/commet/lib/ui/molecules/typing_indicators_widget.dart index 82864ae65..da034ab5d 100644 --- a/commet/lib/ui/molecules/typing_indicators_widget.dart +++ b/commet/lib/ui/molecules/typing_indicators_widget.dart @@ -24,14 +24,16 @@ class _TypingIndicatorsWidgetState extends State { late String currentText = ""; String typingUsers(int howMany, String user1, String user2, String user3) => - Intl.plural(howMany, - one: "$user1 is typing...", - two: "$user1 and $user2 are typing...", - few: "$user1, $user2, and $user3 are typing...", - other: "Several people are typing...", - desc: "Text to display which users are currently typing", - name: "typingUsers", - args: [howMany, user1, user2, user3]); + Intl.plural( + howMany, + one: "$user1 is typing...", + two: "$user1 and $user2 are typing...", + few: "$user1, $user2, and $user3 are typing...", + other: "Several people are typing...", + desc: "Text to display which users are currently typing", + name: "typingUsers", + args: [howMany, user1, user2, user3], + ); @override void initState() { @@ -61,37 +63,47 @@ class _TypingIndicatorsWidgetState extends State { @override Widget build(BuildContext context) { return SizedBox( - height: 23, - child: ClipRect( - child: AnimatedSlide( - duration: Durations.medium3, - curve: Curves.easeInOutExpo, - offset: typingMembers.isEmpty ? const Offset(0, 1) : Offset.zero, - child: Row(children: [ - Padding( - padding: const EdgeInsets.fromLTRB(4, 0, 4, 0), - child: TypingIndicatorAnimation( - playing: typingMembers.isNotEmpty, - ), + height: 23, + child: ClipRect( + child: AnimatedSlide( + duration: Durations.medium3, + curve: Curves.easeInOutExpo, + offset: typingMembers.isEmpty ? const Offset(0, 1) : Offset.zero, + child: Row( + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(4, 0, 4, 0), + child: TypingIndicatorAnimation( + playing: typingMembers.isNotEmpty, ), - tiamat.Text.labelLow(currentText) - ])), - )); + ), + tiamat.Text.labelLow(currentText), + ], + ), + ), + ), + ); } String getTypingText() { String user1 = typingMembers[0].displayName; - String user2 = - typingMembers.length >= 2 ? typingMembers[1].displayName : ""; - String user3 = - typingMembers.length >= 3 ? typingMembers[2].displayName : ""; + String user2 = typingMembers.length >= 2 + ? typingMembers[1].displayName + : ""; + String user3 = typingMembers.length >= 3 + ? typingMembers[2].displayName + : ""; return typingUsers(typingMembers.length, user1, user2, user3); } } class SingleTypingIndicatorBlob extends StatefulWidget { - const SingleTypingIndicatorBlob( - {this.color, this.border, super.key, this.playing = true}); + const SingleTypingIndicatorBlob({ + this.color, + this.border, + super.key, + this.playing = true, + }); final Color? color; final BoxBorder? border; final bool playing; @@ -103,7 +115,10 @@ class SingleTypingIndicatorBlob extends StatefulWidget { class SingleTypingIndicatorBlobState extends State with TickerProviderStateMixin { late AnimationController controller = AnimationController( - duration: const Duration(milliseconds: 200), vsync: this, value: 1); + duration: const Duration(milliseconds: 200), + vsync: this, + value: 1, + ); @override void initState() { @@ -155,10 +170,12 @@ class SingleTypingIndicatorBlobState extends State heightFactor: alpha, child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: widget.border, - color: widget.color ?? - Theme.of(context).colorScheme.secondary), + borderRadius: BorderRadius.circular(8), + border: widget.border, + color: + widget.color ?? + Theme.of(context).colorScheme.secondary, + ), ), ), ), @@ -180,11 +197,7 @@ class TypingIndicatorAnimation extends StatefulWidget { } class _TypingIndicatorAnimationState extends State { - late List blobKeys = [ - GlobalKey(), - GlobalKey(), - GlobalKey(), - ]; + late List blobKeys = [GlobalKey(), GlobalKey(), GlobalKey()]; Timer? timer; int prevIndex = 0; @@ -248,19 +261,12 @@ class _TypingIndicatorAnimationState extends State { @override Widget build(BuildContext context) { - return Row(children: [ - SingleTypingIndicatorBlob( - key: blobKeys[0], - playing: playing, - ), - SingleTypingIndicatorBlob( - key: blobKeys[1], - playing: playing, - ), - SingleTypingIndicatorBlob( - key: blobKeys[2], - playing: playing, - ), - ]); + return Row( + children: [ + SingleTypingIndicatorBlob(key: blobKeys[0], playing: playing), + SingleTypingIndicatorBlob(key: blobKeys[1], playing: playing), + SingleTypingIndicatorBlob(key: blobKeys[2], playing: playing), + ], + ); } } diff --git a/commet/lib/ui/molecules/url_preview_widget.dart b/commet/lib/ui/molecules/url_preview_widget.dart index fb21ad092..13da02cf2 100644 --- a/commet/lib/ui/molecules/url_preview_widget.dart +++ b/commet/lib/ui/molecules/url_preview_widget.dart @@ -50,41 +50,42 @@ class _UrlPreviewWidgetState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - ConstrainedBox( - constraints: - const BoxConstraints(maxWidth: 300, maxHeight: 240), - child: widget.data == null - ? buildLoadingDisplay() - : Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Align( - alignment: Alignment.topLeft, - child: body(context)), - if (hasBody) - const SizedBox( - width: 10, - height: 10, - ), - if (widget.data!.image != null && - widget.data?.video == null) - Flexible(child: image()), - if (widget.data!.video != null) - MessageAttachment( - previewMedia: true, - widget.data!.video!, - constrainSize: false, - ) - ], - ), - ) - ]), + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 300, + maxHeight: 240, + ), + child: widget.data == null + ? buildLoadingDisplay() + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Align( + alignment: Alignment.topLeft, + child: body(context), + ), + if (hasBody) + const SizedBox(width: 10, height: 10), + if (widget.data!.image != null && + widget.data?.video == null) + Flexible(child: image()), + if (widget.data!.video != null) + MessageAttachment( + previewMedia: true, + widget.data!.video!, + constrainSize: false, + ), + ], + ), + ), + ], + ), ), ), ), @@ -110,40 +111,42 @@ class _UrlPreviewWidgetState extends State { height: 14, width: titleWidth, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), color: color), - ), - const SizedBox( - height: 8, + borderRadius: BorderRadius.circular(4), + color: color, + ), ), + const SizedBox(height: 8), Container( height: 10, width: bodyWidth1, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), color: color), - ), - const SizedBox( - height: 5, + borderRadius: BorderRadius.circular(4), + color: color, + ), ), + const SizedBox(height: 5), Container( height: 10, width: bodyWidth2, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), color: color), - ), - SizedBox( - height: 8, + borderRadius: BorderRadius.circular(4), + color: color, + ), ), + SizedBox(height: 8), ClipRRect( - borderRadius: BorderRadius.circular(4), - child: ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 180, maxWidth: 300), - child: Container( - color: color, - ))), + borderRadius: BorderRadius.circular(4), + child: ConstrainedBox( + constraints: const BoxConstraints( + maxHeight: 180, + maxWidth: 300, + ), + child: Container(color: color), + ), + ), ], ), - ) + ), ], ), ), @@ -201,9 +204,9 @@ class _UrlPreviewWidgetState extends State { maxLines: 2, color: Theme.of(context).colorScheme.secondary, overflow: TextOverflow.ellipsis, - ) + ), ], - ) + ), ], ); } diff --git a/commet/lib/ui/molecules/user_list.dart b/commet/lib/ui/molecules/user_list.dart index d49397693..97cba8ff4 100644 --- a/commet/lib/ui/molecules/user_list.dart +++ b/commet/lib/ui/molecules/user_list.dart @@ -15,6 +15,7 @@ import 'package:commet/utils/error_utils.dart'; import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; + import '../../client/room.dart'; class RoomMemberList extends StatefulWidget { @@ -24,77 +25,86 @@ class RoomMemberList extends StatefulWidget { @override State createState() => _RoomMemberListState(); - static AdaptiveContextMenu userContextMenu(BuildContext context, - {required String userId, - required String userDisplayName, - required Room room, - required Widget child, - required bool isSelf, - Function? onUserKicked, - Function? onUserBanned, - Function? onUserRoleChanged}) { + static AdaptiveContextMenu userContextMenu( + BuildContext context, { + required String userId, + required String userDisplayName, + required Room room, + required Widget child, + required bool isSelf, + Function? onUserKicked, + Function? onUserBanned, + Function? onUserRoleChanged, + }) { return AdaptiveContextMenu( items: [ if (room.permissions.canChangeRoles) tiamat.ContextMenuItem( - text: "Set Role", - icon: Icons.shield, - onPressed: () async { - ErrorUtils.tryRun(context, () async { - var role = await AdaptiveDialog.pickOne( - context, - title: "Pick Role for $userDisplayName", - items: room.availableRoles, - itemBuilder: (context, item, callback) { - return SizedBox( - height: 50, - child: tiamat.TextButton( - item.name, - icon: item.icon, - onTap: callback, - ), - ); - }, - ); - - if (role != null) { - await room.setMemberRole(userId, role); - onUserRoleChanged?.call(); - } - }); - }), + text: "Set Role", + icon: Icons.shield, + onPressed: () async { + ErrorUtils.tryRun(context, () async { + var role = await AdaptiveDialog.pickOne( + context, + title: "Pick Role for $userDisplayName", + items: room.availableRoles, + itemBuilder: (context, item, callback) { + return SizedBox( + height: 50, + child: tiamat.TextButton( + item.name, + icon: item.icon, + onTap: callback, + ), + ); + }, + ); + + if (role != null) { + await room.setMemberRole(userId, role); + onUserRoleChanged?.call(); + } + }); + }, + ), if (room.permissions.canKick && !isSelf) tiamat.ContextMenuItem( - text: "Kick", - icon: Icons.subdirectory_arrow_left_rounded, - color: ColorScheme.of(context).error, - onPressed: () async { - if (await AdaptiveDialog.confirmation(context, - prompt: - "Are you sure you want to kick $userDisplayName from the room?") == - true) { - ErrorUtils.tryRun(context, () async { - await room.kickUser(userId); - onUserKicked?.call(); - }); - } - }), + text: "Kick", + icon: Icons.subdirectory_arrow_left_rounded, + color: ColorScheme.of(context).error, + onPressed: () async { + if (await AdaptiveDialog.confirmation( + context, + prompt: + "Are you sure you want to kick $userDisplayName from the room?", + ) == + true) { + ErrorUtils.tryRun(context, () async { + await room.kickUser(userId); + onUserKicked?.call(); + }); + } + }, + ), if (room.permissions.canBan && !isSelf) tiamat.ContextMenuItem( - text: "Ban", - icon: Icons.shield, - color: ColorScheme.of(context).error, - onPressed: () async { - if (await AdaptiveDialog.confirmation(context, - prompt: - "Are you sure you want to ban $userDisplayName from the room?") == - true) { - ErrorUtils.tryRun(context, () async { - await room.banUser(userId); - onUserBanned?.call(); - }); - } - }), + text: "Ban", + icon: Icons.shield, + color: ColorScheme.of(context).error, + onPressed: () async { + if (await AdaptiveDialog.confirmation( + context, + prompt: + "Are you sure you want to ban $userDisplayName from the room?", + ) == + true) { + ErrorUtils.tryRun(context, () async { + await room.banUser(userId); + onUserBanned?.call(); + }); + } + }, + ), ], child: child, ); @@ -114,7 +124,8 @@ class _RoomMemberListState extends State { @override void initState() { getInitialUsers(); - isDirectMessageRoom = widget.room.client + isDirectMessageRoom = + widget.room.client .getComponent() ?.isRoomDirectMessage(widget.room) ?? false; @@ -130,8 +141,9 @@ class _RoomMemberListState extends State { var users = widget.room.membersList(); var important = widget.room.importantMembers(); - users.removeWhere((element) => - important.any((i) => i.$1.identifier == element.identifier)); + users.removeWhere( + (element) => important.any((i) => i.$1.identifier == element.identifier), + ); roomMembers = users; importantMembers = important; @@ -237,9 +249,7 @@ class _RoomMemberListState extends State { if (isDirectMessageRoom) { if (member.identifier == widget.room.client.self?.identifier) - return SizedBox( - height: 0, - ); + return SizedBox(height: 0); result = Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), child: UserProfile( @@ -254,23 +264,30 @@ class _RoomMemberListState extends State { ); } - result = RoomMemberList.userContextMenu(context, - userId: member.identifier, - room: widget.room, - userDisplayName: member.displayName, - isSelf: member.identifier == widget.room.client.self!.identifier, - child: result, - onUserBanned: () => roomMembers - .removeWhere((i) => i.identifier == member.identifier), - onUserKicked: () => roomMembers - .removeWhere((i) => i.identifier == member.identifier), - onUserRoleChanged: () => loadAllUsers()); + result = RoomMemberList.userContextMenu( + context, + userId: member.identifier, + room: widget.room, + userDisplayName: member.displayName, + isSelf: member.identifier == widget.room.client.self!.identifier, + child: result, + onUserBanned: () => roomMembers.removeWhere( + (i) => i.identifier == member.identifier, + ), + onUserKicked: () => roomMembers.removeWhere( + (i) => i.identifier == member.identifier, + ), + onUserRoleChanged: () => loadAllUsers(), + ); var role = getDisplayRole(index); if (role != null) { result = Column( crossAxisAlignment: CrossAxisAlignment.stretch, - children: [RoleView(name: role.name, icon: role.icon), result], + children: [ + RoleView(name: role.name, icon: role.icon), + result, + ], ); } @@ -314,7 +331,7 @@ class _RoomMemberListState extends State { shimmer: true, random: Random(i).nextDouble(), ), - ) + ), ], ), ); diff --git a/commet/lib/ui/molecules/user_panel.dart b/commet/lib/ui/molecules/user_panel.dart index c53b14479..d89066e54 100644 --- a/commet/lib/ui/molecules/user_panel.dart +++ b/commet/lib/ui/molecules/user_panel.dart @@ -11,14 +11,15 @@ import 'package:tiamat/tiamat.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class UserPanel extends material.StatefulWidget { - const UserPanel( - {super.key, - required this.userId, - required this.client, - required this.contextRoom, - this.initialMember, - this.isDirectMessage = false, - this.onTap}); + const UserPanel({ + super.key, + required this.userId, + required this.client, + required this.contextRoom, + this.initialMember, + this.isDirectMessage = false, + this.onTap, + }); final String userId; final Client client; final Member? initialMember; @@ -57,7 +58,8 @@ class _UserPanelState extends material.State { return; } - final member = widget.initialMember ?? + final member = + widget.initialMember ?? widget.contextRoom.getMemberOrFallback(widget.userId); displayName = member.displayName; color = member.defaultColor; @@ -78,8 +80,8 @@ class _UserPanelState extends material.State { } initPresence() async { - final presenceComponent = - widget.client.getComponent(); + final presenceComponent = widget.client + .getComponent(); if (presenceComponent == null) { return; @@ -106,13 +108,9 @@ class _UserPanelState extends material.State { style = currentStyle?.copyWith(fontSize: 10); if (presence.message != null) { - style = style?.copyWith( - fontWeight: FontWeight.w500, - ); + style = style?.copyWith(fontWeight: FontWeight.w500); } else { - style = style?.copyWith( - color: Theme.of(context).colorScheme.secondary, - ); + style = style?.copyWith(color: Theme.of(context).colorScheme.secondary); } return UserPanelView( @@ -143,21 +141,22 @@ class _UserPanelState extends material.State { } class UserPanelView extends material.StatelessWidget { - const UserPanelView( - {super.key, - this.avatar, - required this.displayName, - this.color, - this.avatarColor, - this.nameColor, - this.detail, - this.padding, - this.shimmer = false, - this.random = 0, - this.detailStringStyle, - this.presence, - this.avatarSize = 15, - this.onClicked}); + const UserPanelView({ + super.key, + this.avatar, + required this.displayName, + this.color, + this.avatarColor, + this.nameColor, + this.detail, + this.padding, + this.shimmer = false, + this.random = 0, + this.detailStringStyle, + this.presence, + this.avatarSize = 15, + this.onClicked, + }); final ImageProvider? avatar; final String displayName; final double avatarSize; @@ -216,8 +215,9 @@ class UserPanelView extends material.StatelessWidget { height: 10, width: (random * 50) + 50, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: shimmerColor), + borderRadius: BorderRadius.circular(4), + color: shimmerColor, + ), ), if (shimmer) material.Padding( @@ -226,8 +226,9 @@ class UserPanelView extends material.StatelessWidget { height: 8, width: (random * 20) + 20, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: shimmerColor), + borderRadius: BorderRadius.circular(4), + color: shimmerColor, + ), ), ), if (!shimmer) @@ -245,23 +246,29 @@ class UserPanelView extends material.StatelessWidget { if (presence!.message?.messageType == PresenceMessageType.userCustom) material.Padding( - padding: - const EdgeInsets.fromLTRB(0, 0, 4, 0), - child: Icon( - Icons.chat_bubble, - size: 10, + padding: const EdgeInsets.fromLTRB( + 0, + 0, + 4, + 0, ), + child: Icon(Icons.chat_bubble, size: 10), ), Flexible( child: material.Padding( - padding: - const EdgeInsets.fromLTRB(0, 0, 0, 2), - child: material.Text( - presence!.message!.message, - overflow: TextOverflow.ellipsis, - maxLines: 1, - style: detailStringStyle, - )), + padding: const EdgeInsets.fromLTRB( + 0, + 0, + 0, + 2, + ), + child: material.Text( + presence!.message!.message, + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: detailStringStyle, + ), + ), ), ], ), @@ -272,8 +279,12 @@ class UserPanelView extends material.StatelessWidget { children: [ Flexible( child: material.Padding( - padding: - const EdgeInsets.fromLTRB(0, 0, 0, 2), + padding: const EdgeInsets.fromLTRB( + 0, + 0, + 0, + 2, + ), child: buildDetailString(), ), ), @@ -283,7 +294,7 @@ class UserPanelView extends material.StatelessWidget { ), ), ), - ) + ), ], ), ), @@ -299,7 +310,9 @@ class UserPanelView extends material.StatelessWidget { } static material.DecoratedBox createPresenceIcon( - BuildContext context, UserPresenceStatus status) { + BuildContext context, + UserPresenceStatus status, + ) { var scheme = Theme.of(context).colorScheme; var backgroundColor = scheme.surfaceContainer; @@ -311,14 +324,12 @@ class UserPanelView extends material.StatelessWidget { color: color, shape: BoxShape.circle, border: Border.all( - width: 2, - strokeAlign: BorderSide.strokeAlignOutside, - color: backgroundColor), - ), - child: SizedBox( - width: 8, - height: 8, + width: 2, + strokeAlign: BorderSide.strokeAlignOutside, + color: backgroundColor, + ), ), + child: SizedBox(width: 8, height: 8), ); } @@ -331,9 +342,7 @@ class UserPanelView extends material.StatelessWidget { detail!, overflow: TextOverflow.ellipsis, maxLines: 1, - style: detailStringStyle?.copyWith( - fontFamily: "Code", - ), + style: detailStringStyle?.copyWith(fontFamily: "Code"), ); } } diff --git a/commet/lib/ui/molecules/user_panel_settings.dart b/commet/lib/ui/molecules/user_panel_settings.dart index c49eb8195..6a3938c95 100644 --- a/commet/lib/ui/molecules/user_panel_settings.dart +++ b/commet/lib/ui/molecules/user_panel_settings.dart @@ -43,15 +43,16 @@ class _UserPanelSettingsState extends State { child: Row( children: [ SizedBox( - width: height, - height: height, - child: tiamat.IconButton( - icon: Icons.settings, - size: iconHeight, - onPressed: () { - NavigationUtils.navigateTo(context, const AppSettingsPage()); - }, - )) + width: height, + height: height, + child: tiamat.IconButton( + icon: Icons.settings, + size: iconHeight, + onPressed: () { + NavigationUtils.navigateTo(context, const AppSettingsPage()); + }, + ), + ), ], ), ); diff --git a/commet/lib/ui/molecules/video_player/video_player.dart b/commet/lib/ui/molecules/video_player/video_player.dart index 0fee443d9..06a046308 100644 --- a/commet/lib/ui/molecules/video_player/video_player.dart +++ b/commet/lib/ui/molecules/video_player/video_player.dart @@ -10,23 +10,26 @@ import 'package:commet/main.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; + import '../../atoms/gradient_background.dart'; import 'video_player_controller.dart'; import '../../atoms/icon_button.dart' as i; class VideoPlayer extends StatefulWidget { - const VideoPlayer(this.videoFile, - {this.thumbnail, - this.fileName, - super.key, - this.canGoFullscreen = false, - this.onFullscreen, - this.streamUrl, - this.decodeFirstFrame = false, - this.controller, - this.doThumbnail = true, - this.showProgressBar = true}); + const VideoPlayer( + this.videoFile, { + this.thumbnail, + this.fileName, + super.key, + this.canGoFullscreen = false, + this.onFullscreen, + this.streamUrl, + this.decodeFirstFrame = false, + this.controller, + this.doThumbnail = true, + this.showProgressBar = true, + }); final FileProvider videoFile; final ImageProvider? thumbnail; final Uri? streamUrl; @@ -102,14 +105,15 @@ class VideoPlayerState extends State { if (updateSlider) { setState(() { videoProgress = clampDouble( - event.inMilliseconds.toDouble() / - length.inMilliseconds.toDouble(), - 0, - 1); + event.inMilliseconds.toDouble() / + length.inMilliseconds.toDouble(), + 0, + 1, + ); }); } }), - controller.onVolumeChanged.listen(onVolumeChanged) + controller.onVolumeChanged.listen(onVolumeChanged), ]; super.initState(); @@ -132,7 +136,7 @@ class VideoPlayerState extends State { if (widget.decodeFirstFrame || inited) pickPlayer(), if (showThumbnail) thumbnail(), if (buffering) bufferingWidget(), - controls() + controls(), ], ); } @@ -152,19 +156,17 @@ class VideoPlayerState extends State { SizedBox( width: 50, height: 50, - child: CircularProgressIndicator( - value: progress, - ), + child: CircularProgressIndicator(value: progress), ), if (download != null) Padding( padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), child: TinyPill( - background: Theme.of(context).colorScheme.secondaryContainer, - foreground: - Theme.of(context).colorScheme.onSecondaryContainer, - "${TextUtils.readableFileSize(download.downloaded)} / ${TextUtils.readableFileSize(download.total)}"), - ) + background: Theme.of(context).colorScheme.secondaryContainer, + foreground: Theme.of(context).colorScheme.onSecondaryContainer, + "${TextUtils.readableFileSize(download.downloaded)} / ${TextUtils.readableFileSize(download.total)}", + ), + ), ], ), ); @@ -172,13 +174,8 @@ class VideoPlayerState extends State { Widget thumbnail() { return widget.thumbnail != null - ? Image( - fit: BoxFit.cover, - image: widget.thumbnail!, - ) - : Container( - color: Colors.black, - ); + ? Image(fit: BoxFit.cover, image: widget.thumbnail!) + : Container(color: Colors.black); } Widget controls() { @@ -217,8 +214,8 @@ class VideoPlayerState extends State { icon: isCompleted ? Icons.replay : playing - ? Icons.pause_rounded - : Icons.play_arrow_rounded, + ? Icons.pause_rounded + : Icons.play_arrow_rounded, onPressed: () { if (isCompleted) return replay(); if (playing) return pause(); @@ -277,14 +274,14 @@ class VideoPlayerState extends State { parentAlignment: Alignment.topCenter, onHoverStateChanged: (hovered) => setState(() { - showingVolumeSlider = hovered; - }), + showingVolumeSlider = hovered; + }), child: tiamat.IconButton( icon: isMuted ? Icons.volume_mute : appliedVolume == 0 - ? Icons.volume_off - : Icons.volume_up, + ? Icons.volume_off + : Icons.volume_up, onPressed: (() { toggleIsMuted(); preferences.isPlayerMuted.set(isMuted); @@ -292,26 +289,29 @@ class VideoPlayerState extends State { ), builder: (context) { return RotatedBox( - quarterTurns: 3, - child: Container( - decoration: BoxDecoration( - color: ColorScheme.of(context) - .surfaceContainer, - borderRadius: - BorderRadius.circular(8)), - child: SizedBox( - width: 200, - height: 50, - child: tiamat.Slider( - value: appliedVolume / 100, - onChanged: (value) => - setVolume(value * 100), - onChangeEnd: (value) => - preferences.playerVolume - .set(volume), - ), + quarterTurns: 3, + child: Container( + decoration: BoxDecoration( + color: ColorScheme.of(context) + .surfaceContainer, + borderRadius: BorderRadius.circular( + 8, ), - )); + ), + child: SizedBox( + width: 200, + height: 50, + child: tiamat.Slider( + value: appliedVolume / 100, + onChanged: (value) => + setVolume(value * 100), + onChangeEnd: (value) => preferences + .playerVolume + .set(volume), + ), + ), + ), + ); }, ), ), @@ -326,12 +326,12 @@ class VideoPlayerState extends State { widget.onFullscreen?.call(); }, ), - ) + ), ], ), ), ), - ) + ), ], ), ), diff --git a/commet/lib/ui/molecules/video_player/video_player_controller.dart b/commet/lib/ui/molecules/video_player/video_player_controller.dart index 5381c9495..38be435af 100644 --- a/commet/lib/ui/molecules/video_player/video_player_controller.dart +++ b/commet/lib/ui/molecules/video_player/video_player_controller.dart @@ -45,16 +45,17 @@ class VideoPlayerController { Stream get onDownloadProgressed => _downloadProgress.stream; - void attach( - {required Future Function() pause, - required Future Function() play, - required Future Function() replay, - required Future Function() getLength, - required Future Function() getSize, - required Future Function() getVolume, - Future Function()? screenshot, - required Future Function(Duration percent) seekTo, - required Future Function(double volume) setVolume}) { + void attach({ + required Future Function() pause, + required Future Function() play, + required Future Function() replay, + required Future Function() getLength, + required Future Function() getSize, + required Future Function() getVolume, + Future Function()? screenshot, + required Future Function(Duration percent) seekTo, + required Future Function(double volume) setVolume, + }) { _onPause = pause; _onPlay = play; _onReplay = replay; diff --git a/commet/lib/ui/molecules/video_player/video_player_implementation.dart b/commet/lib/ui/molecules/video_player/video_player_implementation.dart index c49f6c5bd..db201ddfe 100644 --- a/commet/lib/ui/molecules/video_player/video_player_implementation.dart +++ b/commet/lib/ui/molecules/video_player/video_player_implementation.dart @@ -10,14 +10,15 @@ import 'package:media_kit_video/media_kit_video.dart'; import 'video_player_controller.dart'; class VideoPlayerImplementation extends StatefulWidget { - const VideoPlayerImplementation( - {required this.controller, - required this.videoFile, - this.decodeFirstFrame = false, - this.streamUrl, - this.width = 640, - this.height = 340, - super.key}); + const VideoPlayerImplementation({ + required this.controller, + required this.videoFile, + this.decodeFirstFrame = false, + this.streamUrl, + this.width = 640, + this.height = 340, + super.key, + }); final FileProvider videoFile; final Uri? streamUrl; final int width; @@ -48,25 +49,24 @@ class _VideoPlayerImplementationState extends State { } widget.controller.attach( - pause: pause, - play: play, - replay: replay, - screenshot: screenshot, - getSize: getSize, - getVolume: getVolume, - seekTo: seekTo, - getLength: getLength, - setVolume: setVolume); + pause: pause, + play: play, + replay: replay, + screenshot: screenshot, + getSize: getSize, + getVolume: getVolume, + seekTo: seekTo, + getLength: getLength, + setVolume: setVolume, + ); player.stream.position.listen((event) { widget.controller.setProgress(event); }); - player.stream.completed.listen( - (completed) { - widget.controller.setCompleted(completed); - }, - ); + player.stream.completed.listen((completed) { + widget.controller.setCompleted(completed); + }); player.stream.volume.listen(widget.controller.handleInternalVolumeChange); @@ -82,8 +82,10 @@ class _VideoPlayerImplementationState extends State { sub?.cancel(); - await player.open(Playlist([Media(file.toString())]), - play: !widget.decodeFirstFrame); + await player.open( + Playlist([Media(file.toString())]), + play: !widget.decodeFirstFrame, + ); widget.controller.setBuffering(false); setState(() { @@ -99,19 +101,23 @@ class _VideoPlayerImplementationState extends State { bool allowed = preferences.allowedRemoteVideoHosts.value.contains(host); if (!allowed) { - bool? confirmation = await AdaptiveDialog.confirmation(context, - dangerous: true, - title: "Stream Remote Video", - prompt: - "Do you want to allow connections to `${widget.streamUrl!.host}` to stream this video?"); + bool? confirmation = await AdaptiveDialog.confirmation( + context, + dangerous: true, + title: "Stream Remote Video", + prompt: + "Do you want to allow connections to `${widget.streamUrl!.host}` to stream this video?", + ); allowed = confirmation == true; preferences.allowedRemoteVideoHosts.add(host); } if (allowed) { - await player.open(Playlist([Media(widget.streamUrl!.toString())]), - play: !widget.decodeFirstFrame); + await player.open( + Playlist([Media(widget.streamUrl!.toString())]), + play: !widget.decodeFirstFrame, + ); } widget.controller.setBuffering(false); @@ -176,7 +182,9 @@ class _VideoPlayerImplementationState extends State { } return Size( - player.state.width!.toDouble(), player.state.height!.toDouble()); + player.state.width!.toDouble(), + player.state.height!.toDouble(), + ); } Future getVolume() async { diff --git a/commet/lib/ui/molecules/widget_debug_view.dart b/commet/lib/ui/molecules/widget_debug_view.dart index 69fba95ee..b5281b8d0 100644 --- a/commet/lib/ui/molecules/widget_debug_view.dart +++ b/commet/lib/ui/molecules/widget_debug_view.dart @@ -24,15 +24,9 @@ class WidgetDebugView extends StatelessWidget { automaticallyImplyLeading: false, bottom: TabBar( tabs: [ - Tab( - text: "Messages", - ), - Tab( - text: "Capabilities", - ), - Tab( - text: "Logs", - ), + Tab(text: "Messages"), + Tab(text: "Capabilities"), + Tab(text: "Logs"), ], ), ), @@ -40,7 +34,7 @@ class WidgetDebugView extends StatelessWidget { children: [ WidgetMessageDebugView(runner), WidgetCapabilitiesDebugView(runner), - LogPage(runner.logs) + LogPage(runner.logs), ], ), ), @@ -64,8 +58,9 @@ class _WidgetCapabilitiesDebugViewState list: widget.runner.capabilities.grantedCapabilityNames, itemBuilder: (context, value) { return Padding( - padding: EdgeInsetsGeometry.fromLTRB(0, 8, 0, 0), - child: tiamat.Text.labelLow(value)); + padding: EdgeInsetsGeometry.fromLTRB(0, 8, 0, 0), + child: tiamat.Text.labelLow(value), + ); }, ); } @@ -100,48 +95,49 @@ class _WidgetMessageDebugViewState extends State { var id = item.$2.tryGet("requestId")!; - var emote = - emoji.characters.elementAt(id.hashCode % emoji.characters.length); + var emote = emoji.characters.elementAt( + id.hashCode % emoji.characters.length, + ); return Container( - color: (isError - ? m.Colors.red - : item.$1 == WidgetMessageDirection.incoming - ? m.Colors.blueAccent - : m.Colors.greenAccent) - .withAlpha(20), - child: m.ExpansionTile( - title: Row( - spacing: 8, - children: [ - Icon(item.$1 == WidgetMessageDirection.incoming - ? m.Icons.arrow_back - : m.Icons.arrow_forward), - tiamat.Text.tiny(emote), - if (isResponse) Icon(m.Icons.reply), - if (isError) - Icon( - m.Icons.error, - color: m.Colors.redAccent, - ), - tiamat.Text(item.$2["action"]), - if (type != null) tiamat.Text.labelLow(type) - ], - ), + color: + (isError + ? m.Colors.red + : item.$1 == WidgetMessageDirection.incoming + ? m.Colors.blueAccent + : m.Colors.greenAccent) + .withAlpha(20), + child: m.ExpansionTile( + title: Row( + spacing: 8, children: [ - Scrollbar( + Icon( + item.$1 == WidgetMessageDirection.incoming + ? m.Icons.arrow_back + : m.Icons.arrow_forward, + ), + tiamat.Text.tiny(emote), + if (isResponse) Icon(m.Icons.reply), + if (isError) Icon(m.Icons.error, color: m.Colors.redAccent), + tiamat.Text(item.$2["action"]), + if (type != null) tiamat.Text.labelLow(type), + ], + ), + children: [ + Scrollbar( + controller: controller, + child: SingleChildScrollView( controller: controller, - child: SingleChildScrollView( - controller: controller, - scrollDirection: Axis.horizontal, - child: Codeblock( - text: JsonEncoder.withIndent(" ").convert(item.$2), - language: "json", - ), + scrollDirection: Axis.horizontal, + child: Codeblock( + text: JsonEncoder.withIndent(" ").convert(item.$2), + language: "json", ), - ) - ], - )); + ), + ), + ], + ), + ); }, ); } diff --git a/commet/lib/ui/molecules/widget_sessions_panel.dart b/commet/lib/ui/molecules/widget_sessions_panel.dart index 56db049c2..ea19cd799 100644 --- a/commet/lib/ui/molecules/widget_sessions_panel.dart +++ b/commet/lib/ui/molecules/widget_sessions_panel.dart @@ -36,8 +36,10 @@ class _WidgetSessionsPanelState extends State { Iterable widgets = WidgetComponent.currentSessions; if (preferences.widgetDeveloperMode.value == false) { - widgets = WidgetComponent.currentSessions.where((i) => - (i is MatrixUserWidgetSubprocessRunner && i.hidden) ? false : true); + widgets = WidgetComponent.currentSessions.where( + (i) => + (i is MatrixUserWidgetSubprocessRunner && i.hidden) ? false : true, + ); } var first = widgets.firstOrNull; @@ -50,20 +52,21 @@ class _WidgetSessionsPanelState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, spacing: 4, - children: [ - for (var entry in widgets) buildEntry(context, entry), - ], + children: [for (var entry in widgets) buildEntry(context, entry)], ); } Widget buildEntry( - BuildContext context, WidgetRunner entry) { + BuildContext context, + WidgetRunner entry, + ) { return SizedBox( height: widget.height, child: Container( decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceTint.withAlpha(10), - borderRadius: BorderRadius.circular(8)), + color: ColorScheme.of(context).surfaceTint.withAlpha(10), + borderRadius: BorderRadius.circular(8), + ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -71,18 +74,17 @@ class _WidgetSessionsPanelState extends State { Row( children: [ SizedBox( - height: widget.height, - width: widget.height, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: entry.info.icon.build(context), - )), + height: widget.height, + width: widget.height, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: entry.info.icon.build(context), + ), + ), Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, - children: [ - tiamat.Text(entry.info.name), - ], + children: [tiamat.Text(entry.info.name)], ), ], ), @@ -99,10 +101,12 @@ class _WidgetSessionsPanelState extends State { context, builder: (context) { return SizedBox( - width: 700, - height: 700, - child: WidgetDebugView( - entry as MatrixWidgetRunner)); + width: 700, + height: 700, + child: WidgetDebugView( + entry as MatrixWidgetRunner, + ), + ); }, ); }, diff --git a/commet/lib/ui/navigation/adaptive_dialog.dart b/commet/lib/ui/navigation/adaptive_dialog.dart index c2eee50dc..e756963d6 100644 --- a/commet/lib/ui/navigation/adaptive_dialog.dart +++ b/commet/lib/ui/navigation/adaptive_dialog.dart @@ -23,20 +23,26 @@ class AdaptiveDialog { BuildContext context, { required List items, required Widget Function(BuildContext context, T item, Function() callback) - itemBuilder, + itemBuilder, String? title, bool scrollable = true, bool dismissible = true, double initialHeightMobile = 0.5, }) { - return AdaptiveDialog.show(context, title: title, builder: (context) { - return Column( - children: items - .map((i) => - itemBuilder(context, i, () => Navigator.of(context).pop(i))) - .toList(), - ); - }); + return AdaptiveDialog.show( + context, + title: title, + builder: (context) { + return Column( + children: items + .map( + (i) => + itemBuilder(context, i, () => Navigator.of(context).pop(i)), + ) + .toList(), + ); + }, + ); } static Future?> pickMultiple( @@ -111,15 +117,18 @@ class AdaptiveDialog { } static Future showError( - BuildContext context, Object exception, StackTrace trace, - {String title = "Error"}) { - return show(context, builder: (context) { - return Column( - children: [ - tiamat.Text.body(exception.toString()), - ], - ); - }, title: title); + BuildContext context, + Object exception, + StackTrace trace, { + String title = "Error", + }) { + return show( + context, + builder: (context) { + return Column(children: [tiamat.Text.body(exception.toString())]); + }, + title: title, + ); } static Future show( @@ -132,13 +141,15 @@ class AdaptiveDialog { double initialHeightMobile = 0.5, }) async { if (MediaQuery.of(context).desktop) { - return PopupDialog.show(context, - content: scrollable - ? SingleChildScrollView(child: builder(context)) - : builder(context), - title: title, - contentPadding: contentPadding, - barrierDismissible: dismissible); + return PopupDialog.show( + context, + content: scrollable + ? SingleChildScrollView(child: builder(context)) + : builder(context), + title: title, + contentPadding: contentPadding, + barrierDismissible: dismissible, + ); } return m.showModalBottomSheet( @@ -150,129 +161,149 @@ class AdaptiveDialog { backgroundColor: m.Theme.of(context).colorScheme.surfaceContainerLow, builder: (context) { return SingleChildScrollView( - child: Container( - padding: - EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), - child: ScaledSafeArea( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (title != null) - Padding( - padding: const EdgeInsets.all(12.0), - child: tiamat.Text( - title, - type: TextType.largeTitle, - color: Theme.of(context).colorScheme.onSurface, + child: Container( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + child: ScaledSafeArea( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (title != null) + Padding( + padding: const EdgeInsets.all(12.0), + child: tiamat.Text( + title, + type: TextType.largeTitle, + color: Theme.of(context).colorScheme.onSurface, + ), ), - ), - Center(child: builder(context)), - ], + Center(child: builder(context)), + ], + ), ), ), ), - )); + ); }, ); } - static String get labelDialogConfirmation => Intl.message("Confirmation", - name: "labelDialogConfirmation", - desc: "label for the dialog which asks the user to confirm some action"); + static String get labelDialogConfirmation => Intl.message( + "Confirmation", + name: "labelDialogConfirmation", + desc: "label for the dialog which asks the user to confirm some action", + ); - static Future confirmation(BuildContext context, - {String prompt = "Are you sure?", - String title = "Confirmation", - String confirmationText = "Yes", - String cancelText = "No", - Widget Function(BuildContext)? customBuilder, - bool dangerous = false}) async { - var value = await show?>(context, builder: (context) { - return ConfirmationDialogWidget( - prompt: prompt, - title: title, - confirmationText: confirmationText, - cancelText: cancelText, - customBuilder: customBuilder, - dangerous: dangerous, - ); - }, title: title == "Confirmation" ? labelDialogConfirmation : title); + static Future confirmation( + BuildContext context, { + String prompt = "Are you sure?", + String title = "Confirmation", + String confirmationText = "Yes", + String cancelText = "No", + Widget Function(BuildContext)? customBuilder, + bool dangerous = false, + }) async { + var value = await show?>( + context, + builder: (context) { + return ConfirmationDialogWidget( + prompt: prompt, + title: title, + confirmationText: confirmationText, + cancelText: cancelText, + customBuilder: customBuilder, + dangerous: dangerous, + ); + }, + title: title == "Confirmation" ? labelDialogConfirmation : title, + ); return value?.value; } static Future?> confirmationWithOptions( - BuildContext context, - {String prompt = "Are you sure?", - String title = "Confirmation", - String confirmationText = "Yes", - String cancelText = "No", - Widget Function(BuildContext)? customBuilder, - bool showRememberChoice = false, - bool defaultRememberSetting = false, - bool dangerous = false}) { - var value = show?>(context, builder: (context) { - return ConfirmationDialogWidget( - prompt: prompt, - title: title, - confirmationText: confirmationText, - cancelText: cancelText, - customBuilder: customBuilder, - showRememberChoice: showRememberChoice, - defaultRememberSetting: defaultRememberSetting, - dangerous: dangerous, - ); - }, title: title == "Confirmation" ? labelDialogConfirmation : title); + BuildContext context, { + String prompt = "Are you sure?", + String title = "Confirmation", + String confirmationText = "Yes", + String cancelText = "No", + Widget Function(BuildContext)? customBuilder, + bool showRememberChoice = false, + bool defaultRememberSetting = false, + bool dangerous = false, + }) { + var value = show?>( + context, + builder: (context) { + return ConfirmationDialogWidget( + prompt: prompt, + title: title, + confirmationText: confirmationText, + cancelText: cancelText, + customBuilder: customBuilder, + showRememberChoice: showRememberChoice, + defaultRememberSetting: defaultRememberSetting, + dangerous: dangerous, + ); + }, + title: title == "Confirmation" ? labelDialogConfirmation : title, + ); return value; } - static Future textPrompt(BuildContext context, - {String title = "Enter Text", - String submitText = "Submit", - String? hintText, - String? initialText, - bool multiline = false, - bool dangerous = false}) { - return show(context, builder: (context) { - String result = ""; - TextEditingController controller = - TextEditingController(text: initialText); + static Future textPrompt( + BuildContext context, { + String title = "Enter Text", + String submitText = "Submit", + String? hintText, + String? initialText, + bool multiline = false, + bool dangerous = false, + }) { + return show( + context, + builder: (context) { + String result = ""; + TextEditingController controller = TextEditingController( + text: initialText, + ); - return SizedBox( - width: MediaQuery.of(context).desktop ? 500 : null, - child: Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisSize: MainAxisSize.min, - children: [ - TextField( - controller: controller, - maxLines: multiline ? null : 1, - decoration: InputDecoration(hintText: hintText), - onChanged: (value) => result = value, - ), - SizedBox( - height: 10, - ), - tiamat.Button( - text: submitText == "Submit" - ? CommonStrings.promptSubmit - : submitText, - onTap: () { - print(result); - Navigator.of(context).pop(result); - }, - ) - ], + return SizedBox( + width: MediaQuery.of(context).desktop ? 500 : null, + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + controller: controller, + maxLines: multiline ? null : 1, + decoration: InputDecoration(hintText: hintText), + onChanged: (value) => result = value, + ), + SizedBox(height: 10), + tiamat.Button( + text: submitText == "Submit" + ? CommonStrings.promptSubmit + : submitText, + onTap: () { + print(result); + Navigator.of(context).pop(result); + }, + ), + ], + ), ), - ), - ); - }, title: title); + ); + }, + title: title, + ); } } @@ -329,11 +360,13 @@ class _ConfirmationDialogWidgetState extends State { shrinkWrap: true, styleSheet: MarkdownStyleSheet.fromTheme(Theme.of(context)) .copyWith( - codeblockPadding: EdgeInsets.all(8), - code: TextTheme.of(context).bodySmall!.copyWith( - fontFamily: "Code", - backgroundColor: ColorScheme.of(context) - .surfaceContainerLowest)), + codeblockPadding: EdgeInsets.all(8), + code: TextTheme.of(context).bodySmall!.copyWith( + fontFamily: "Code", + backgroundColor: ColorScheme.of(context) + .surfaceContainerLowest, + ), + ), data: widget.prompt, ), ), @@ -342,20 +375,21 @@ class _ConfirmationDialogWidgetState extends State { Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - tiamat.Text.labelLow("Remember choice: "), - tiamat.Switch( - state: rememberChoice, - onChanged: (value) { - setState(() { - rememberChoice = value; - }); - }, - ), - ], - )), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + tiamat.Text.labelLow("Remember choice: "), + tiamat.Switch( + state: rememberChoice, + onChanged: (value) { + setState(() { + rememberChoice = value; + }); + }, + ), + ], + ), + ), ), SizedBox( height: 40, @@ -365,19 +399,21 @@ class _ConfirmationDialogWidgetState extends State { ? CommonStrings.promptYes : widget.confirmationText, onTap: () => Navigator.pop( - context, DialogResult(true, remember: rememberChoice)), + context, + DialogResult(true, remember: rememberChoice), + ), ), ), - const SizedBox( - height: 5, - ), + const SizedBox(height: 5), tiamat.Button.secondary( text: widget.cancelText == "No" ? CommonStrings.promptNo : widget.cancelText, onTap: () => Navigator.pop( - context, DialogResult(false, remember: rememberChoice)), - ) + context, + DialogResult(false, remember: rememberChoice), + ), + ), ], ), ), @@ -386,11 +422,12 @@ class _ConfirmationDialogWidgetState extends State { } class _SelectMultipleView extends StatefulWidget { - const _SelectMultipleView( - {required this.itemBuilder, - required this.items, - this.initialSelection = const [], - super.key}); + const _SelectMultipleView({ + required this.itemBuilder, + required this.items, + this.initialSelection = const [], + super.key, + }); final List items; final List initialSelection; final Widget Function(BuildContext context, T item) itemBuilder; @@ -410,54 +447,58 @@ class __SelectMultipleViewState extends State<_SelectMultipleView> { @override Widget build(BuildContext context) { return Column( - spacing: 8, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - ...widget.items - .map((i) => Material( - clipBehavior: Clip.antiAlias, - borderRadius: BorderRadius.circular(8), - color: Colors.transparent, - child: InkWell( - onTap: () { - setState(() { - if (selection.contains(i)) { - selection.remove(i); - } else { - selection.add(i); - } - }); - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Checkbox( - value: selection.contains(i), - onChanged: (v) { - if (v == true) { - setState(() { - selection.add(i); - }); - } else { - setState(() { - selection.remove(i); - }); - } + spacing: 8, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ...widget.items + .map( + (i) => Material( + clipBehavior: Clip.antiAlias, + borderRadius: BorderRadius.circular(8), + color: Colors.transparent, + child: InkWell( + onTap: () { + setState(() { + if (selection.contains(i)) { + selection.remove(i); + } else { + selection.add(i); + } + }); + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Checkbox( + value: selection.contains(i), + onChanged: (v) { + if (v == true) { + setState(() { + selection.add(i); + }); + } else { + setState(() { + selection.remove(i); + }); + } - print(selection); - }), - widget.itemBuilder(context, i) - ], + print(selection); + }, ), - ), + widget.itemBuilder(context, i), + ], ), - )) - .toList(), - tiamat.Button( - text: CommonStrings.promptSubmit, - onTap: () => Navigator.of(context).pop(selection), - ) - ]); + ), + ), + ), + ) + .toList(), + tiamat.Button( + text: CommonStrings.promptSubmit, + onTap: () => Navigator.of(context).pop(selection), + ), + ], + ); } } diff --git a/commet/lib/ui/navigation/adaptive_text_dialog.dart b/commet/lib/ui/navigation/adaptive_text_dialog.dart index 7029f26b0..009ccfdd8 100644 --- a/commet/lib/ui/navigation/adaptive_text_dialog.dart +++ b/commet/lib/ui/navigation/adaptive_text_dialog.dart @@ -14,22 +14,29 @@ class AdaptiveTextDialog { bool dismissible = true, double initialHeightMobile = 0.5, }) async { - final result = await AdaptiveDialog.show(context, title: title, - builder: (context) { - return AdaptiveTextDialogWidget( - description: description, - defaultText: defaultText, - placeholder: placeholder, - ); - }); + final result = await AdaptiveDialog.show( + context, + title: title, + builder: (context) { + return AdaptiveTextDialogWidget( + description: description, + defaultText: defaultText, + placeholder: placeholder, + ); + }, + ); return result; } } class AdaptiveTextDialogWidget extends StatefulWidget { - const AdaptiveTextDialogWidget( - {super.key, this.placeholder, this.description, this.defaultText}); + const AdaptiveTextDialogWidget({ + super.key, + this.placeholder, + this.description, + this.defaultText, + }); final String? placeholder; final String? defaultText; final String? description; @@ -59,24 +66,18 @@ class _AdaptiveTextDialogWidgetState extends State { if (widget.description != null) SizedBox( width: 400, - child: tiamat.Text.labelLow( - widget.description!, - ), + child: tiamat.Text.labelLow(widget.description!), ), - SizedBox( - height: 10, - ), + SizedBox(height: 10), tiamat.TextInput( placeholder: widget.placeholder, controller: controller, ), - SizedBox( - height: 10, - ), + SizedBox(height: 10), tiamat.Button( text: CommonStrings.promptSubmit, onTap: () => Navigator.of(context).pop(controller.text), - ) + ), ], ), ), diff --git a/commet/lib/ui/navigation/navigation_utils.dart b/commet/lib/ui/navigation/navigation_utils.dart index b9f7a2a56..d73e0d652 100644 --- a/commet/lib/ui/navigation/navigation_utils.dart +++ b/commet/lib/ui/navigation/navigation_utils.dart @@ -3,16 +3,18 @@ import 'package:flutter/material.dart'; class NavigationUtils { static Future navigateTo(BuildContext context, Widget page) { return Navigator.push( - context, - PageRouteBuilder( - pageBuilder: (_, __, ___) => page, - transitionDuration: const Duration(milliseconds: 500), - transitionsBuilder: (_, animation, __, child) => SlideTransition( - position: Tween( - begin: const Offset(0, 1.5), - end: Offset.zero, - ).animate(CurvedAnimation( - parent: animation, curve: Curves.easeOutCubic)), - child: child))); + context, + PageRouteBuilder( + pageBuilder: (_, __, ___) => page, + transitionDuration: const Duration(milliseconds: 500), + transitionsBuilder: (_, animation, __, child) => SlideTransition( + position: Tween(begin: const Offset(0, 1.5), end: Offset.zero) + .animate( + CurvedAnimation(parent: animation, curve: Curves.easeOutCubic), + ), + child: child, + ), + ), + ); } } diff --git a/commet/lib/ui/navigation/quick_switcher.dart b/commet/lib/ui/navigation/quick_switcher.dart index 2b6a3e897..1944cdb6e 100644 --- a/commet/lib/ui/navigation/quick_switcher.dart +++ b/commet/lib/ui/navigation/quick_switcher.dart @@ -93,8 +93,9 @@ class _QuickSwitcherState extends State { for (var room in client.rooms) { if (dm?.isRoomDirectMessage(room) == true) { var partner = dm!.getDirectMessagePartnerId(room); - items.add(QuickSwitcherSearchItemRoom(room, - id: partner ?? room.identifier)); + items.add( + QuickSwitcherSearchItemRoom(room, id: partner ?? room.identifier), + ); } else { items.add(QuickSwitcherSearchItemRoom(room, id: room.identifier)); } @@ -135,7 +136,7 @@ class _QuickSwitcherState extends State { ], ), ), - ) + ), ], ), ); @@ -152,63 +153,74 @@ class _QuickSwitcherState extends State { child: Row( spacing: 8, children: [ - for (var room in clientManager! - .directMessages.directMessageRooms - .sorted((a, b) => - b.lastEventTimestamp.compareTo(a.lastEventTimestamp))) + for (var room + in clientManager!.directMessages.directMessageRooms.sorted( + (a, b) => + b.lastEventTimestamp.compareTo(a.lastEventTimestamp), + )) Material( color: Colors.transparent, child: InkWell( onTap: () { - EventBus.doOpenRoom(room.identifier, - clientId: room.client.identifier); + EventBus.doOpenRoom( + room.identifier, + clientId: room.client.identifier, + ); Navigator.of(context).pop(); }, child: tiamat.Avatar( - image: room.avatar, - placeholderColor: room.defaultColor, - placeholderText: room.displayName), + image: room.avatar, + placeholderColor: room.defaultColor, + placeholderText: room.displayName, + ), ), - ) + ), ], ), ), ), tiamat.Panel( - mode: TileType.surfaceContainerLow, - header: "Recent Activity", - child: Column( - spacing: 0, - children: [ - for (var room in clientManager!.rooms - .sorted((a, b) => - b.lastEventTimestamp.compareTo(a.lastEventTimestamp)) - .sublist(0, clientManager!.rooms.length.clamp(0, 4))) - RoomPanelView( - onTap: () { - EventBus.doOpenRoom(room.identifier, - clientId: room.client.identifier); - - Navigator.of(context).pop(); - }, - displayName: room.displayName, - color: room.defaultColor, - avatar: room.avatar, - recentEventSender: room.lastMessage != null - ? room + mode: TileType.surfaceContainerLow, + header: "Recent Activity", + child: Column( + spacing: 0, + children: [ + for (var room + in clientManager!.rooms + .sorted( + (a, b) => b.lastEventTimestamp.compareTo( + a.lastEventTimestamp, + ), + ) + .sublist(0, clientManager!.rooms.length.clamp(0, 4))) + RoomPanelView( + onTap: () { + EventBus.doOpenRoom( + room.identifier, + clientId: room.client.identifier, + ); + + Navigator.of(context).pop(); + }, + displayName: room.displayName, + color: room.defaultColor, + avatar: room.avatar, + recentEventSender: room.lastMessage != null + ? room .getMemberOrFallback(room.lastMessage!.senderId) .displayName - : null, - recentEventSenderColor: room.lastMessage != null - ? room + : null, + recentEventSenderColor: room.lastMessage != null + ? room .getMemberOrFallback(room.lastMessage!.senderId) .defaultColor - : null, - body: room.lastMessage?.plainTextBody, - ) - ], - )) + : null, + body: room.lastMessage?.plainTextBody, + ), + ], + ), + ), ], ); } @@ -228,21 +240,27 @@ class _QuickSwitcherState extends State { searchItems = items.where((i) => i.id.startsWith("@")).toList(); } - var fuzzy = Fuzzy(searchItems, - options: FuzzyOptions(keys: [ + var fuzzy = Fuzzy( + searchItems, + options: FuzzyOptions( + keys: [ WeightedKey( - name: "searchEntry", - getter: (result) { - return result.searchEntry; - }, - weight: 1), + name: "searchEntry", + getter: (result) { + return result.searchEntry; + }, + weight: 1, + ), WeightedKey( - name: "id", - getter: (result) { - return result.id; - }, - weight: 1) - ])); + name: "id", + getter: (result) { + return result.id; + }, + weight: 1, + ), + ], + ), + ); var results = fuzzy.search(searchText, 5).map((e) => e.item).toList(); setState(() { diff --git a/commet/lib/ui/organisms/add_widget_dialog/add_widget_dialog.dart b/commet/lib/ui/organisms/add_widget_dialog/add_widget_dialog.dart index 8b84b60b2..0583b5f0a 100644 --- a/commet/lib/ui/organisms/add_widget_dialog/add_widget_dialog.dart +++ b/commet/lib/ui/organisms/add_widget_dialog/add_widget_dialog.dart @@ -44,15 +44,18 @@ class _AddWidgetDialogState extends State { width: 30, height: 30, child: Image( - fit: BoxFit.cover, - image: MatrixMxcImage( - Uri.parse(widget.widgetUri.widgetAvatarMxc!), - doThumbnail: false, - doFullres: true, - (widget.room.client as MatrixClient).matrixClient)), + fit: BoxFit.cover, + image: MatrixMxcImage( + Uri.parse(widget.widgetUri.widgetAvatarMxc!), + doThumbnail: false, + doFullres: true, + (widget.room.client as MatrixClient).matrixClient, + ), + ), ), tiamat.Text.label( - "Add the widget '${widget.widgetUri.widgetName ?? "Custom"}' to ${widget.room.displayName}?"), + "Add the widget '${widget.widgetUri.widgetName ?? "Custom"}' to ${widget.room.displayName}?", + ), ], ), ), @@ -65,12 +68,14 @@ class _AddWidgetDialogState extends State { child: SizedBox( height: 300, child: Image( - fit: BoxFit.cover, - image: MatrixMxcImage( - Uri.parse(widget.widgetUri.previewMxc!), - doThumbnail: false, - doFullres: true, - (widget.room.client as MatrixClient).matrixClient)), + fit: BoxFit.cover, + image: MatrixMxcImage( + Uri.parse(widget.widgetUri.previewMxc!), + doThumbnail: false, + doFullres: true, + (widget.room.client as MatrixClient).matrixClient, + ), + ), ), ), ), @@ -86,13 +91,14 @@ class _AddWidgetDialogState extends State { await ErrorUtils.tryRun(context, () async { await comp.addWidget( - url: Uri.parse(widget.widgetUri.widgetUrl), - room: widget.room, - iconImageUrl: widget.widgetUri.widgetAvatarMxc != null - ? Uri.tryParse(widget.widgetUri.widgetAvatarMxc!) - : null, - widgetName: widget.widgetUri.widgetName ?? "Custom", - widgetType: widget.widgetUri.widgetType); + url: Uri.parse(widget.widgetUri.widgetUrl), + room: widget.room, + iconImageUrl: widget.widgetUri.widgetAvatarMxc != null + ? Uri.tryParse(widget.widgetUri.widgetAvatarMxc!) + : null, + widgetName: widget.widgetUri.widgetName ?? "Custom", + widgetType: widget.widgetUri.widgetType, + ); }); Navigator.of(context).pop(); @@ -104,7 +110,8 @@ class _AddWidgetDialogState extends State { onTap: () => Navigator.of(context).pop(), ), tiamat.Text.error( - "Widgets are hosted on external websites, and the code can be changed without notice. Do not use the widget if you do not trust the host.") + "Widgets are hosted on external websites, and the code can be changed without notice. Do not use the widget if you do not trust the host.", + ), ], ), ); diff --git a/commet/lib/ui/organisms/attachment_processor/attachment_processor.dart b/commet/lib/ui/organisms/attachment_processor/attachment_processor.dart index 7f1b38130..4a69f20b6 100644 --- a/commet/lib/ui/organisms/attachment_processor/attachment_processor.dart +++ b/commet/lib/ui/organisms/attachment_processor/attachment_processor.dart @@ -24,16 +24,16 @@ class AttachmentProcessor extends StatefulWidget { class _AttachmentProcessorState extends State { String get promptAttachmentProcessingSendOriginal => Intl.message( - "Send Original", - name: "promptAttachmentProcessingSendOriginal", - desc: - "Prompt text for the option to send a file in its original state, without any further processing such as removing metadata"); + "Send Original", + name: "promptAttachmentProcessingSendOriginal", + desc: "Prompt text for the option to send a file in its original state, without any further processing such as removing metadata", + ); String get labelImageContainsLocationInfo => Intl.message( - "Warning: This image contains location metadata", - name: "labelImageContainsLocationInfo", - desc: - "Prompt text for the option to send a file in its original state, without any further processing such as removing metadata"); + "Warning: This image contains location metadata", + name: "labelImageContainsLocationInfo", + desc: "Prompt text for the option to send a file in its original state, without any further processing such as removing metadata", + ); Map? exifData; late IconData icon; @@ -128,8 +128,9 @@ class _AttachmentProcessorState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: ConstrainedBox( - constraints: - BoxConstraints.loose(const Size(500, 500)), + constraints: BoxConstraints.loose( + const Size(500, 500), + ), child: ClipRRect( borderRadius: BorderRadius.circular(8), child: FilePreview( @@ -155,7 +156,7 @@ class _AttachmentProcessorState extends State { ), ), ), - if (processing) const CircularProgressIndicator() + if (processing) const CircularProgressIndicator(), ], ), ); @@ -179,16 +180,13 @@ class _AttachmentProcessorState extends State { Widget buildMetadataDisplay() { return Column( children: [ - if (containsGpsData) tiamat.Text.error(labelImageContainsLocationInfo) + if (containsGpsData) tiamat.Text.error(labelImageContainsLocationInfo), ], ); } Widget buildConfirmButton() { - return tiamat.Button( - text: "Add File", - onTap: submit, - ); + return tiamat.Button(text: "Add File", onTap: submit); } void submit() async { @@ -252,10 +250,11 @@ class _AttachmentProcessorState extends State { } return PendingFileAttachment( - name: name, - data: processedData, - size: processedData.lengthInBytes, - mimeType: mime); + name: name, + data: processedData, + size: processedData.lengthInBytes, + mimeType: mime, + ); }, widget.attachment); } diff --git a/commet/lib/ui/organisms/background_task_view/background_task_view.dart b/commet/lib/ui/organisms/background_task_view/background_task_view.dart index bd2dd1c02..d32abae27 100644 --- a/commet/lib/ui/organisms/background_task_view/background_task_view.dart +++ b/commet/lib/ui/organisms/background_task_view/background_task_view.dart @@ -33,10 +33,11 @@ class _BackgroundTaskViewState extends State { padding: const EdgeInsets.all(4.0), child: DecoratedBox( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - boxShadow: [ - BoxShadow(blurRadius: 4, color: Theme.of(context).shadowColor) - ]), + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow(blurRadius: 4, color: Theme.of(context).shadowColor), + ], + ), child: ClipRRect( borderRadius: BorderRadius.circular(8), child: Container( @@ -46,10 +47,12 @@ class _BackgroundTaskViewState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: widget.manager.tasks - .map((e) => _SingleBackgroundTaskView( - e, - key: ValueKey("task-display${e.hashCode}"), - )) + .map( + (e) => _SingleBackgroundTaskView( + e, + key: ValueKey("task-display${e.hashCode}"), + ), + ) .toList(), ), ), @@ -111,8 +114,9 @@ class __SingleBackgroundTaskViewState extends State<_SingleBackgroundTaskView> { return Material( color: Colors.transparent, child: InkWell( - onTap: - widget.task.canCallAction ? () => widget.task.action?.call() : null, + onTap: widget.task.canCallAction + ? () => widget.task.action?.call() + : null, child: Padding( padding: const EdgeInsets.all(8.0), child: Row( @@ -122,26 +126,27 @@ class __SingleBackgroundTaskViewState extends State<_SingleBackgroundTaskView> { Padding( padding: const EdgeInsets.fromLTRB(0, 0, 8, 0), child: SizedBox( - width: 10, - height: 10, - child: status == BackgroundTaskStatus.completed - ? const Icon( - Icons.check, - color: Colors.greenAccent, - size: 10, - ) - : status == BackgroundTaskStatus.failed - ? Icon( - Icons.error, - color: Theme.of(context).colorScheme.error, - size: 10, - ) - : CircularProgressIndicator( - strokeWidth: 2, - value: progress, - )), + width: 10, + height: 10, + child: status == BackgroundTaskStatus.completed + ? const Icon( + Icons.check, + color: Colors.greenAccent, + size: 10, + ) + : status == BackgroundTaskStatus.failed + ? Icon( + Icons.error, + color: Theme.of(context).colorScheme.error, + size: 10, + ) + : CircularProgressIndicator( + strokeWidth: 2, + value: progress, + ), + ), ), - tiamat.Text.tiny(widget.task.label) + tiamat.Text.tiny(widget.task.label), ], ), ), diff --git a/commet/lib/ui/organisms/background_task_view/background_task_view_container.dart b/commet/lib/ui/organisms/background_task_view/background_task_view_container.dart index d953f29f3..b7adbc084 100644 --- a/commet/lib/ui/organisms/background_task_view/background_task_view_container.dart +++ b/commet/lib/ui/organisms/background_task_view/background_task_view_container.dart @@ -37,8 +37,6 @@ class _BackgroundTaskViewContainerState return Container(); } - return FloatingTile( - child: BackgroundTaskView(backgroundTaskManager), - ); + return FloatingTile(child: BackgroundTaskView(backgroundTaskManager)); } } diff --git a/commet/lib/ui/organisms/call_view/call_view.dart b/commet/lib/ui/organisms/call_view/call_view.dart index 573939193..db2210fbf 100644 --- a/commet/lib/ui/organisms/call_view/call_view.dart +++ b/commet/lib/ui/organisms/call_view/call_view.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:commet/client/components/voip/voip_session.dart'; import 'package:commet/client/components/voip/voip_stream.dart'; import 'package:commet/client/room.dart'; @@ -81,7 +82,7 @@ class _CallViewState extends State { VoipState.connecting => callOutgoingView(), VoipState.ended => callEndedView(), VoipState.incoming => callIncomingView(), - _ => const Placeholder() + _ => const Placeholder(), }, ); } @@ -96,20 +97,22 @@ class _CallViewState extends State { color: Theme.of(context).colorScheme.primary, repeat: true, child: Avatar.large( - image: room.avatar, - placeholderColor: room.defaultColor, - placeholderText: room.displayName), + image: room.avatar, + placeholderColor: room.defaultColor, + placeholderText: room.displayName, + ), ), ), ); } - Widget callButtons( - {bool canMute = false, - bool canScreenshare = false, - bool canHangUp = false, - bool canToggleCamera = false, - required Widget child}) { + Widget callButtons({ + bool canMute = false, + bool canScreenshare = false, + bool canHangUp = false, + bool canToggleCamera = false, + required Widget child, + }) { final buttonRadius = MediaQuery.of(context).mobile ? 24.0 : 18.0; return MouseRegion( onEnter: (event) { @@ -136,9 +139,10 @@ class _CallViewState extends State { children: [ if (canScreenshare) tiamat.CircleButton( - radius: buttonRadius, - icon: Icons.screen_share_outlined, - onPressed: widget.pickScreenshareSource), + radius: buttonRadius, + icon: Icons.screen_share_outlined, + onPressed: widget.pickScreenshareSource, + ), if (widget.currentSession.isSharingScreen && canScreenshare) tiamat.CircleButton( radius: buttonRadius, @@ -152,8 +156,9 @@ class _CallViewState extends State { ? Icons.mic_off : Icons.mic, onPressed: () async { - await widget.setMicrophoneMute - ?.call(!widget.currentSession.isMicrophoneMuted); + await widget.setMicrophoneMute?.call( + !widget.currentSession.isMicrophoneMuted, + ); setState(() {}); }, ), @@ -176,11 +181,11 @@ class _CallViewState extends State { await widget.hangUp?.call(); setState(() {}); }, - ) + ), ], ), ), - ) + ), ], ), ); @@ -188,21 +193,22 @@ class _CallViewState extends State { Widget callConnectedView() { return callButtons( - canMute: true, - canHangUp: true, - canScreenshare: true, - canToggleCamera: true, - child: LayoutBuilder( - builder: (context, constraints) { - var ratio = constraints.maxWidth / constraints.maxHeight; + canMute: true, + canHangUp: true, + canScreenshare: true, + canToggleCamera: true, + child: LayoutBuilder( + builder: (context, constraints) { + var ratio = constraints.maxWidth / constraints.maxHeight; - if (ratio > 1 && mainStream == null) { - return Row(children: generateLayout()); - } else { - return Column(children: generateLayout()); - } - }, - )); + if (ratio > 1 && mainStream == null) { + return Row(children: generateLayout()); + } else { + return Column(children: generateLayout()); + } + }, + ), + ); } Iterable get visibleStreams => widget.currentSession.streams @@ -234,26 +240,27 @@ class _CallViewState extends State { PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => Scaffold( - backgroundColor: Colors.black, - body: VoipFullscreenStreamView( - session: widget.currentSession, - stream: mainStream!, - ), - ), + backgroundColor: Colors.black, + body: VoipFullscreenStreamView( + session: widget.currentSession, + stream: mainStream!, + ), + ), transitionsBuilder: (context, animation, secondaryAnimation, child) { - return FadeTransition( - opacity: animation, - child: child, - ); - }, + return FadeTransition( + opacity: animation, + child: child, + ); + }, fullscreenDialog: true, ), ); }, fit: BoxFit.contain, key: ValueKey( - "callView_mainStreamView_${mainStream!.streamId}"), + "callView_mainStreamView_${mainStream!.streamId}", + ), ), ), ), @@ -264,46 +271,53 @@ class _CallViewState extends State { fit: FlexFit.tight, flex: mainStream == null ? 75 : 50, child: Center( - child: BentoLayout(visibleStreams - .where((element) => element != mainStream) - .map((e) => GestureDetector( - onTap: () { - setState(() { - mainStream = e; - }); - }, - child: VoipStreamView( - key: ValueKey("callView__${e.streamId}"), - e, - fit: e.type == VoipStreamType.screenshare - ? BoxFit.contain - : BoxFit.cover, - widget.currentSession, - onFullscreen: () { - NavigationUtils.navigateTo( - context, - Scaffold( - backgroundColor: Colors.black, - body: VoipFullscreenStreamView( - session: widget.currentSession, - stream: e, - ), - ), - ); + child: BentoLayout( + visibleStreams + .where((element) => element != mainStream) + .map( + (e) => GestureDetector( + onTap: () { + setState(() { + mainStream = e; + }); }, - ))) - .toList()), + child: VoipStreamView( + key: ValueKey("callView__${e.streamId}"), + e, + fit: e.type == VoipStreamType.screenshare + ? BoxFit.contain + : BoxFit.cover, + widget.currentSession, + onFullscreen: () { + NavigationUtils.navigateTo( + context, + Scaffold( + backgroundColor: Colors.black, + body: VoipFullscreenStreamView( + session: widget.currentSession, + stream: e, + ), + ), + ); + }, + ), + ), + ) + .toList(), + ), ), - ) + ), ]; } bool shouldShowAudioStream(VoipStream element, List streams) { if (element.type == VoipStreamType.audio) { - if (streams.any((i) => - i.participantId == element.participantId && - (i.type == VoipStreamType.screenshare || - i.type == VoipStreamType.video))) { + if (streams.any( + (i) => + i.participantId == element.participantId && + (i.type == VoipStreamType.screenshare || + i.type == VoipStreamType.video), + )) { { return false; } @@ -326,9 +340,10 @@ class _CallViewState extends State { Center( child: RingShakerAnimation( child: Avatar.large( - image: room.avatar, - placeholderColor: room.defaultColor, - placeholderText: room.displayName), + image: room.avatar, + placeholderColor: room.defaultColor, + placeholderText: room.displayName, + ), ), ), Padding( @@ -349,7 +364,7 @@ class _CallViewState extends State { await widget.declineCall?.call(); setState(() {}); }, - ) + ), ], ), ), diff --git a/commet/lib/ui/organisms/call_view/screen_capture_source_dialog.dart b/commet/lib/ui/organisms/call_view/screen_capture_source_dialog.dart index 5b29cecb3..33de29ea1 100644 --- a/commet/lib/ui/organisms/call_view/screen_capture_source_dialog.dart +++ b/commet/lib/ui/organisms/call_view/screen_capture_source_dialog.dart @@ -7,8 +7,11 @@ import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class ScreenCaptureSourceDialog extends StatefulWidget { - const ScreenCaptureSourceDialog(this.sources, this.onThumbnailChanged, - {super.key}); + const ScreenCaptureSourceDialog( + this.sources, + this.onThumbnailChanged, { + super.key, + }); final List sources; final Stream onThumbnailChanged; @@ -23,10 +26,12 @@ class _ScreenCaptureSourceDialogState extends State { @override void initState() { - this.screenSources = - widget.sources.where((i) => i.type == SourceType.Screen).toList(); - this.windowSources = - widget.sources.where((i) => i.type == SourceType.Window).toList(); + this.screenSources = widget.sources + .where((i) => i.type == SourceType.Screen) + .toList(); + this.windowSources = widget.sources + .where((i) => i.type == SourceType.Window) + .toList(); super.initState(); } @@ -59,9 +64,7 @@ class _ScreenCaptureSourceDialogState extends State { ); }, ), - SizedBox( - height: 32, - ) + SizedBox(height: 32), ], if (screenSources.isNotEmpty) ...[ tiamat.Text.largeTitle("Screens:"), @@ -82,7 +85,7 @@ class _ScreenCaptureSourceDialogState extends State { ); }, ), - ] + ], ], ), ), diff --git a/commet/lib/ui/organisms/call_view/screen_capture_source_widget.dart b/commet/lib/ui/organisms/call_view/screen_capture_source_widget.dart index e00bafaf4..006e74a2d 100644 --- a/commet/lib/ui/organisms/call_view/screen_capture_source_widget.dart +++ b/commet/lib/ui/organisms/call_view/screen_capture_source_widget.dart @@ -7,8 +7,12 @@ import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class ScreenCaptureSourceWidget extends StatefulWidget { - const ScreenCaptureSourceWidget(this.source, this.onThumbnailChanged, - {this.onTap, super.key}); + const ScreenCaptureSourceWidget( + this.source, + this.onThumbnailChanged, { + this.onTap, + super.key, + }); final DesktopCapturerSource source; final Stream onThumbnailChanged; final Function()? onTap; @@ -40,7 +44,7 @@ class _ScreenCaptureSourceWidgetState extends State { thumbnailData ??= source.thumbnail; }); } - }) + }), ]; } @@ -66,13 +70,14 @@ class _ScreenCaptureSourceWidgetState extends State { Padding( padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), child: ClipRRect( - borderRadius: BorderRadius.circular(8), - child: buildImage()), + borderRadius: BorderRadius.circular(8), + child: buildImage(), + ), ), Padding( padding: const EdgeInsets.all(8.0), child: tiamat.Text.labelLow(widget.source.name), - ) + ), ], ), ), @@ -88,9 +93,7 @@ class _ScreenCaptureSourceWidgetState extends State { return const SizedBox( width: 200, height: 200, - child: Center( - child: CircularProgressIndicator(), - ), + child: Center(child: CircularProgressIndicator()), ); } } diff --git a/commet/lib/ui/organisms/call_view/voip_fullscreen_stream_view.dart b/commet/lib/ui/organisms/call_view/voip_fullscreen_stream_view.dart index 5265488c9..3d63e27ab 100644 --- a/commet/lib/ui/organisms/call_view/voip_fullscreen_stream_view.dart +++ b/commet/lib/ui/organisms/call_view/voip_fullscreen_stream_view.dart @@ -7,8 +7,11 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class VoipFullscreenStreamView extends StatefulWidget { - const VoipFullscreenStreamView( - {required this.stream, required this.session, super.key}); + const VoipFullscreenStreamView({ + required this.stream, + required this.session, + super.key, + }); final VoipStream stream; final VoipSession session; @@ -22,8 +25,8 @@ class _VoipFullscreenStreamViewState extends State { RTCScreenShareAnnotationComponent? component; @override void initState() { - component = - widget.session.client.getComponent(); + component = widget.session.client + .getComponent(); annotationSession = component?.getExistingSession(widget.session); super.initState(); @@ -52,7 +55,10 @@ class _VoipFullscreenStreamViewState extends State { if (annotationSession != null) { annotationSession?.setCursorPosition( - streamId: widget.stream.streamId, x: x, y: y); + streamId: widget.stream.streamId, + x: x, + y: y, + ); } }, ); @@ -60,20 +66,24 @@ class _VoipFullscreenStreamViewState extends State { ), Padding( padding: const EdgeInsets.all(8), - child: Wrap(spacing: 5, children: [ - if (component != null) - tiamat.CircleButton( - icon: Icons.mouse, - onPressed: () async { - var session = - await component?.getOrCreateSession(widget.session); - setState(() { - annotationSession = session; - }); - }, - ) - ]), - ) + child: Wrap( + spacing: 5, + children: [ + if (component != null) + tiamat.CircleButton( + icon: Icons.mouse, + onPressed: () async { + var session = await component?.getOrCreateSession( + widget.session, + ); + setState(() { + annotationSession = session; + }); + }, + ), + ], + ), + ), ], ); } diff --git a/commet/lib/ui/organisms/call_view/voip_stream_view.dart b/commet/lib/ui/organisms/call_view/voip_stream_view.dart index a908774b3..23463bd44 100644 --- a/commet/lib/ui/organisms/call_view/voip_stream_view.dart +++ b/commet/lib/ui/organisms/call_view/voip_stream_view.dart @@ -14,12 +14,15 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class VoipStreamView extends StatefulWidget { - const VoipStreamView(this.stream, this.session, - {super.key, - this.fit = BoxFit.cover, - this.borderColor, - this.canFullscreen = true, - this.onFullscreen}); + const VoipStreamView( + this.stream, + this.session, { + super.key, + this.fit = BoxFit.cover, + this.borderColor, + this.canFullscreen = true, + this.onFullscreen, + }); final VoipStream stream; final VoipSession session; final BoxFit fit; @@ -51,7 +54,9 @@ class _VoipStreamViewState extends State user = room.getMemberOrFallback(widget.stream.streamUserId); audioLevel = AnimationController( - vsync: this, duration: CallView.volumeAnimationDuration); + vsync: this, + duration: CallView.volumeAnimationDuration, + ); super.initState(); } @@ -69,75 +74,90 @@ class _VoipStreamViewState extends State @override Widget build(BuildContext context) { return AnimatedBuilder( - animation: audioLevel, - builder: (context, child) { - return Material( - color: Colors.transparent, - child: Stack( - alignment: Alignment.topRight, - children: [ - AdaptiveContextMenu( - items: streamContextMenuItems(widget.stream.participantId, - user, widget.session.streams), - child: Container( - clipBehavior: Clip.antiAlias, - foregroundDecoration: widget.borderColor != null - ? BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: widget.borderColor!, - width: 2, - strokeAlign: BorderSide.strokeAlignCenter)) - : null, - decoration: - BoxDecoration(borderRadius: BorderRadius.circular(8)), - child: buildDefault()), + animation: audioLevel, + builder: (context, child) { + return Material( + color: Colors.transparent, + child: Stack( + alignment: Alignment.topRight, + children: [ + AdaptiveContextMenu( + items: streamContextMenuItems( + widget.stream.participantId, + user, + widget.session.streams, ), - if (preferences.developerMode.value) - Align( - alignment: AlignmentGeometry.topLeft, - child: Container( - decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainer, - borderRadius: BorderRadius.circular(8), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: tiamat.Text.labelLow(widget.stream.stats), - ), - ), + child: Container( + clipBehavior: Clip.antiAlias, + foregroundDecoration: widget.borderColor != null + ? BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: widget.borderColor!, + width: 2, + strokeAlign: BorderSide.strokeAlignCenter, + ), + ) + : null, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), ), - if (widget.canFullscreen && - widget.stream.type == VoipStreamType.video || - widget.stream.type == VoipStreamType.screenshare) - SizedBox( - width: 40, - height: 40, - child: tiamat.IconButton( - icon: Icons.fullscreen, - size: 20, - onPressed: widget.onFullscreen, + child: buildDefault(), + ), + ), + if (preferences.developerMode.value) + Align( + alignment: AlignmentGeometry.topLeft, + child: Container( + decoration: BoxDecoration( + color: ColorScheme.of(context).surfaceContainer, + borderRadius: BorderRadius.circular(8), ), - ) - ], - ), - ); - }); + child: Padding( + padding: const EdgeInsets.all(8.0), + child: tiamat.Text.labelLow(widget.stream.stats), + ), + ), + ), + if (widget.canFullscreen && + widget.stream.type == VoipStreamType.video || + widget.stream.type == VoipStreamType.screenshare) + SizedBox( + width: 40, + height: 40, + child: tiamat.IconButton( + icon: Icons.fullscreen, + size: 20, + onPressed: widget.onFullscreen, + ), + ), + ], + ), + ); + }, + ); } static List streamContextMenuItems( - String participantId, Member user, List streams) { - var incoming = streams.where((i) => - i.direction == VoipStreamDirection.incoming && - i.participantId == participantId); + String participantId, + Member user, + List streams, + ) { + var incoming = streams.where( + (i) => + i.direction == VoipStreamDirection.incoming && + i.participantId == participantId, + ); if (incoming.isEmpty) return []; - var audioStream = - incoming.firstWhereOrNull((i) => i.type == VoipStreamType.audio); + var audioStream = incoming.firstWhereOrNull( + (i) => i.type == VoipStreamType.audio, + ); - var screenShareAudioStream = incoming - .firstWhereOrNull((i) => i.type == VoipStreamType.screenshareAudio); + var screenShareAudioStream = incoming.firstWhereOrNull( + (i) => i.type == VoipStreamType.screenshareAudio, + ); return [ tiamat.ContextMenuItem( @@ -149,14 +169,12 @@ class _VoipStreamViewState extends State spacing: 12, children: [ tiamat.Avatar( - radius: 15, - image: user.avatar, - placeholderColor: user.defaultColor, - placeholderText: user.displayName), - tiamat.Text.name( - user.displayName, - color: user.defaultColor, - ) + radius: 15, + image: user.avatar, + placeholderColor: user.defaultColor, + placeholderText: user.displayName, + ), + tiamat.Text.name(user.displayName, color: user.defaultColor), ], ), ); @@ -172,14 +190,10 @@ class _VoipStreamViewState extends State crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox( - height: 24, - width: 24, - child: Center( - child: Icon( - Icons.mic, - size: 16, - ), - )), + height: 24, + width: 24, + child: Center(child: Icon(Icons.mic, size: 16)), + ), Flexible( child: Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), @@ -201,14 +215,10 @@ class _VoipStreamViewState extends State crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox( - height: 24, - width: 24, - child: Center( - child: Icon( - Icons.screen_share, - size: 16, - ), - )), + height: 24, + width: 24, + child: Center(child: Icon(Icons.screen_share, size: 16)), + ), Flexible( child: Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), @@ -219,7 +229,7 @@ class _VoipStreamViewState extends State ), ); }, - ) + ), ]; } @@ -229,48 +239,53 @@ class _VoipStreamViewState extends State case VoipStreamType.audio: return tiamat.Tile.low( child: Center( - child: Stack( - alignment: AlignmentGeometry.bottomRight, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: AnimatedOpacity( - opacity: widget.stream.isMuted ? 0.5 : 1.0, - duration: Duration(milliseconds: 200), - child: tiamat.Avatar( + child: Stack( + alignment: AlignmentGeometry.bottomRight, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: AnimatedOpacity( + opacity: widget.stream.isMuted ? 0.5 : 1.0, + duration: Duration(milliseconds: 200), + child: tiamat.Avatar( border: Border.all( - strokeAlign: 0.5, - color: getBorderColor(context), - width: clampDouble(audioLevel.value * 15, 0, 5)), + strokeAlign: 0.5, + color: getBorderColor(context), + width: clampDouble(audioLevel.value * 15, 0, 5), + ), radius: 50, image: user.avatar, placeholderColor: user.defaultColor, - placeholderText: user.displayName), + placeholderText: user.displayName, + ), + ), ), - ), - AnimatedScale( - scale: widget.stream.isMuted ? 1.0 : 0.0, - curve: widget.stream.isMuted - ? Curves.bounceOut - : Curves.easeInExpo, - duration: - Duration(milliseconds: widget.stream.isMuted ? 500 : 200), - child: Container( - decoration: BoxDecoration( + AnimatedScale( + scale: widget.stream.isMuted ? 1.0 : 0.0, + curve: widget.stream.isMuted + ? Curves.bounceOut + : Curves.easeInExpo, + duration: Duration( + milliseconds: widget.stream.isMuted ? 500 : 200, + ), + child: Container( + decoration: BoxDecoration( color: ColorScheme.of(context).primary, - borderRadius: BorderRadius.circular(8)), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Icon( - Icons.mic_off_rounded, - size: 18, - color: ColorScheme.of(context).onPrimary, + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Icon( + Icons.mic_off_rounded, + size: 18, + color: ColorScheme.of(context).onPrimary, + ), ), ), ), - ) - ], - )), + ], + ), + ), ); case VoipStreamType.video: @@ -280,18 +295,20 @@ class _VoipStreamViewState extends State Center( child: widget.stream.buildVideoRenderer(widget.fit, rendererKey) ?? - const CircularProgressIndicator(), + const CircularProgressIndicator(), ), Padding( padding: const EdgeInsets.all(8.0), child: tiamat.Avatar.small( - border: Border.all( - strokeAlign: 0.5, - color: getBorderColor(context), - width: clampDouble(audioLevel.value * 15, 0, 5)), - image: user.avatar, - placeholderColor: user.defaultColor, - placeholderText: user.displayName), + border: Border.all( + strokeAlign: 0.5, + color: getBorderColor(context), + width: clampDouble(audioLevel.value * 15, 0, 5), + ), + image: user.avatar, + placeholderColor: user.defaultColor, + placeholderText: user.displayName, + ), ), ], ); @@ -299,8 +316,11 @@ class _VoipStreamViewState extends State } Color getBorderColor(BuildContext context) { - return Color.lerp(Theme.of(context).primaryColor, - Theme.of(context).colorScheme.primary, audioLevel.value)!; + return Color.lerp( + Theme.of(context).primaryColor, + Theme.of(context).colorScheme.primary, + audioLevel.value, + )!; } void onStreamChanged(void event) { @@ -337,9 +357,11 @@ class _StreamVolumeSliderState extends State { ), ), SizedBox( - width: 40, - child: tiamat.Text.labelLow( - "${(widget.stream.volume * 100).toInt()}%")), + width: 40, + child: tiamat.Text.labelLow( + "${(widget.stream.volume * 100).toInt()}%", + ), + ), ], ); } diff --git a/commet/lib/ui/organisms/chat/chat.dart b/commet/lib/ui/organisms/chat/chat.dart index 62e670c54..980f8a6dc 100644 --- a/commet/lib/ui/organisms/chat/chat.dart +++ b/commet/lib/ui/organisms/chat/chat.dart @@ -43,10 +43,7 @@ class Chat extends StatefulWidget { State createState() => ChatState(); } -enum EventInteractionType { - reply, - edit, -} +enum EventInteractionType { reply, edit } class ChatState extends State { Room get room => widget.room; @@ -57,16 +54,16 @@ class ChatState extends State { ThreadsComponent? threadsComponent; String get labelChatPageFileTooLarge => Intl.message( - "This file is too large to upload!", - desc: - "Text that is shown when the user attempts to upload a file that is greater than the allowed size", - name: "labelChatPageFileTooLarge"); + "This file is too large to upload!", + desc: "Text that is shown when the user attempts to upload a file that is greater than the allowed size", + name: "labelChatPageFileTooLarge", + ); String get labelChatPageFileTooLargeTitle => Intl.message( - "Max file size exceeded", - desc: - "Title for the dialog that is shown when the user attempts to upload a file that is greater than the allowed size", - name: "labelChatPageFileTooLargeTitle"); + "Max file size exceeded", + desc: "Title for the dialog that is shown when the user attempts to upload a file that is greater than the allowed size", + name: "labelChatPageFileTooLargeTitle", + ); bool processing = false; List attachments = List.empty(growable: true); @@ -85,8 +82,9 @@ class ChatState extends State { ReadReceiptComponent? receipts; TypingIndicatorComponent? typingIndicators; - Debouncer typingStatusDebouncer = - Debouncer(delay: const Duration(seconds: 5)); + Debouncer typingStatusDebouncer = Debouncer( + delay: const Duration(seconds: 5), + ); DateTime lastSetTyping = DateTime.fromMicrosecondsSinceEpoch(0); bool get isThread => widget.threadId != null; @@ -98,10 +96,12 @@ class ChatState extends State { @override void initState() { Log.i( - "Initializing room timeline for: ${widget.room.displayName} ${widget.threadId ?? ""}"); + "Initializing room timeline for: ${widget.room.displayName} ${widget.threadId ?? ""}", + ); - onFileDroppedSubscription = - EventBus.onFileDropped.stream.listen(onFileDropped); + onFileDroppedSubscription = EventBus.onFileDropped.stream.listen( + onFileDropped, + ); gifs = room.client.getComponent(); emoticons = room.getComponent(); @@ -142,7 +142,9 @@ class ChatState extends State { timeline ??= await room.getTimeline(contextEventId: initialEventId); var threadTimeline = await threadsComponent!.getThreadTimeline( - roomTimeline: timeline, threadRootEventId: widget.threadId!); + roomTimeline: timeline, + threadRootEventId: widget.threadId!, + ); setState(() { _timeline = threadTimeline; }); @@ -152,7 +154,8 @@ class ChatState extends State { @override void dispose() { Log.i( - "Disposing room timeline for: ${widget.room.displayName} ${widget.threadId ?? ""}"); + "Disposing room timeline for: ${widget.room.displayName} ${widget.threadId ?? ""}", + ); onLinkedSubscription?.cancel(); onFileDroppedSubscription?.cancel(); @@ -168,12 +171,18 @@ class ChatState extends State { if (room.client.maxFileSize != null) { if (attachment.size != null && attachment.size! > room.client.maxFileSize!) { - AdaptiveDialog.show(context, builder: (_) { - return SizedBox( + AdaptiveDialog.show( + context, + builder: (_) { + return SizedBox( height: 100, - child: - Center(child: tiamat.Text.label(labelChatPageFileTooLarge))); - }, title: labelChatPageFileTooLargeTitle); + child: Center( + child: tiamat.Text.label(labelChatPageFileTooLarge), + ), + ); + }, + title: labelChatPageFileTooLargeTitle, + ); return; } @@ -201,13 +210,15 @@ class ChatState extends State { if (exif.keys.any((e) => e.toLowerCase().contains("gps"))) { // ignore: use_build_context_synchronously - var confirmation = await AdaptiveDialog.confirmation(context, - title: file.name ?? "File", - confirmationText: "Send File", - cancelText: "Don't send file", - dangerous: true, - prompt: - "Location data was detected in file '${file.name}', are you sure you want to send?"); + var confirmation = await AdaptiveDialog.confirmation( + context, + title: file.name ?? "File", + confirmationText: "Send File", + cancelText: "Don't send file", + dangerous: true, + prompt: + "Location data was detected in file '${file.name}', are you sure you want to send?", + ); if (confirmation != true) { setState(() { @@ -229,7 +240,8 @@ class ChatState extends State { Log.d("Overriding room for client: ${overrideClient}"); } else { Log.e( - "Failed to find correct room to send event for override client. Cancelling"); + "Failed to find correct room to send event for override client. Cancelling", + ); return; } @@ -247,26 +259,28 @@ class ChatState extends State { doCommand(component, message); } else if (isThread) { targetThread!.sendMessage( - threadRootEventId: widget.threadId!, - room: targetRoom, - message: message, - inReplyTo: interactionType == EventInteractionType.reply - ? interactingEvent - : null, - replaceEvent: interactionType == EventInteractionType.edit - ? interactingEvent - : null, - processedAttachments: processedAttachments); + threadRootEventId: widget.threadId!, + room: targetRoom, + message: message, + inReplyTo: interactionType == EventInteractionType.reply + ? interactingEvent + : null, + replaceEvent: interactionType == EventInteractionType.edit + ? interactingEvent + : null, + processedAttachments: processedAttachments, + ); } else { targetRoom.sendMessage( - message: message, - inReplyTo: interactionType == EventInteractionType.reply - ? interactingEvent - : null, - replaceEvent: interactionType == EventInteractionType.edit - ? interactingEvent - : null, - processedAttachments: processedAttachments); + message: message, + inReplyTo: interactionType == EventInteractionType.reply + ? interactingEvent + : null, + replaceEvent: interactionType == EventInteractionType.edit + ? interactingEvent + : null, + processedAttachments: processedAttachments, + ); } typingIndicators?.setTypingStatus(false); @@ -276,15 +290,23 @@ class ChatState extends State { } Future doCommand( - CommandComponent? component, String message) async { + CommandComponent? component, + String message, + ) async { try { - await component?.executeCommand(message, room, - interactingEvent: interactingEvent, type: interactionType); + await component?.executeCommand( + message, + room, + interactingEvent: interactingEvent, + type: interactionType, + ); } catch (error, trace) { Log.onError(error, trace); if (mounted) - AdaptiveDialog.show(context, - builder: (context) => tiamat.Text.label("$error")); + AdaptiveDialog.show( + context, + builder: (context) => tiamat.Text.label("$error"), + ); } } @@ -310,9 +332,10 @@ class ChatState extends State { onFocusMessageInput.add(null); break; case EventInteractionType.edit: - if (event case TimelineEventMessage m) if (timeline != null) { - setMessageInputText.add(m.getPlaintextBody(timeline!)); - } + if (event case TimelineEventMessage m) + if (timeline != null) { + setMessageInputText.add(m.getPlaintextBody(timeline!)); + } onFocusMessageInput.add(null); break; @@ -333,10 +356,9 @@ class ChatState extends State { void sendSticker(Emoticon sticker) { emoticons?.sendSticker( - sticker, - interactionType == EventInteractionType.reply - ? interactingEvent - : null); + sticker, + interactionType == EventInteractionType.reply ? interactingEvent : null, + ); if (interactionType == EventInteractionType.reply) { setInteractingEvent(null); @@ -345,11 +367,10 @@ class ChatState extends State { Future sendGif(GifSearchResult gif) async { await gifs?.sendGif( - room, - gif, - interactionType == EventInteractionType.reply - ? interactingEvent - : null); + room, + gif, + interactionType == EventInteractionType.reply ? interactingEvent : null, + ); if (interactionType == EventInteractionType.reply) { setInteractingEvent(null); @@ -412,9 +433,13 @@ class ChatState extends State { var custom = CustomURI.parse(path); if (custom case AddWidgetURI widgetUri) { - AdaptiveDialog.show(context, builder: (dialogContext) { - return AddWidgetDialog(widgetUri: widgetUri, room: widget.room); - }, title: 'Add "${widgetUri.widgetName ?? "Custom"}"?'); + AdaptiveDialog.show( + context, + builder: (dialogContext) { + return AddWidgetDialog(widgetUri: widgetUri, room: widget.room); + }, + title: 'Add "${widgetUri.widgetName ?? "Custom"}"?', + ); } } @@ -427,14 +452,18 @@ class ChatState extends State { if (mounted) { var attachment = PendingFileAttachment( - name: file.name, path: file.path, size: size, data: data); + name: file.name, + path: file.path, + size: size, + data: data, + ); var processedAttachment = - await AdaptiveDialog.show(context, - scrollable: false, - builder: (context) => AttachmentProcessor( - attachment: attachment, - )); + await AdaptiveDialog.show( + context, + scrollable: false, + builder: (context) => AttachmentProcessor(attachment: attachment), + ); if (processedAttachment != null) { setState(() { @@ -447,20 +476,23 @@ class ChatState extends State { Future sendFavoriteGif(FavoriteGif gif) async { await room.client.getComponent()?.sendFavoriteGif( - room, - gif, - interactionType == EventInteractionType.reply - ? interactingEvent - : null); + room, + gif, + interactionType == EventInteractionType.reply ? interactingEvent : null, + ); } void onLinked(Uri event) { var custom = CustomURI.parse(event.toString()); if (custom case AddWidgetURI widgetUri) { - AdaptiveDialog.show(context, builder: (dialogContext) { - return AddWidgetDialog(widgetUri: widgetUri, room: widget.room); - }, title: 'Add "${widgetUri.widgetName ?? "Custom"}"?'); + AdaptiveDialog.show( + context, + builder: (dialogContext) { + return AddWidgetDialog(widgetUri: widgetUri, room: widget.room); + }, + title: 'Add "${widgetUri.widgetName ?? "Custom"}"?', + ); } } } diff --git a/commet/lib/ui/organisms/chat/chat_view.dart b/commet/lib/ui/organisms/chat/chat_view.dart index 9e925479f..109896c23 100644 --- a/commet/lib/ui/organisms/chat/chat_view.dart +++ b/commet/lib/ui/organisms/chat/chat_view.dart @@ -18,25 +18,29 @@ class ChatView extends StatelessWidget { const ChatView(this.state, {super.key}); final ChatState state; - String get sendEncryptedMessagePrompt => - Intl.message("Send an encrypted message", - name: "sendEncryptedMessagePrompt", - desc: "Placeholder text for message input in an encrypted room"); - - String get sendUnencryptedMessagePrompt => Intl.message("Send a message", - name: "sendUnencryptedMessagePrompt", - desc: "Placeholder text for message input in an unencrypted room"); + String get sendEncryptedMessagePrompt => Intl.message( + "Send an encrypted message", + name: "sendEncryptedMessagePrompt", + desc: "Placeholder text for message input in an encrypted room", + ); + + String get sendUnencryptedMessagePrompt => Intl.message( + "Send a message", + name: "sendUnencryptedMessagePrompt", + desc: "Placeholder text for message input in an unencrypted room", + ); String get cantSentMessagePrompt => Intl.message( - "You do not have permission to send a message in this room", - name: "cantSentMessagePrompt", - desc: "Text that explains the user cannot send a message in this room"); + "You do not have permission to send a message in this room", + name: "cantSentMessagePrompt", + desc: "Text that explains the user cannot send a message in this room", + ); String? get relatedEventSenderName => state.interactingEvent == null ? null : state.room - .getMemberOrFallback(state.interactingEvent!.senderId) - .displayName; + .getMemberOrFallback(state.interactingEvent!.senderId) + .displayName; Color? get relatedEventSenderColor => state.interactingEvent == null ? null @@ -44,28 +48,33 @@ class ChatView extends StatelessWidget { @override Widget build(BuildContext context) { - return Column(children: [ - Expanded( + return Column( + children: [ + Expanded( child: Stack( - fit: StackFit.expand, - children: [timeline(), const ParticlePlayer()], - )), - input(context), - ]); + fit: StackFit.expand, + children: [timeline(), const ParticlePlayer()], + ), + ), + input(context), + ], + ); } Widget timeline() { return state.timeline == null - ? const Center( - child: CircularProgressIndicator(), - ) + ? const Center(child: CircularProgressIndicator()) : RoomTimelineWidget( key: ValueKey("${state.room.identifier}-timeline"), timeline: state.timeline!, - setReplyingEvent: (event) => state.setInteractingEvent(event, - type: EventInteractionType.reply), - setEditingEvent: (event) => state.setInteractingEvent(event, - type: EventInteractionType.edit), + setReplyingEvent: (event) => state.setInteractingEvent( + event, + type: EventInteractionType.reply, + ), + setEditingEvent: (event) => state.setInteractingEvent( + event, + type: EventInteractionType.edit, + ), isThreadTimeline: state.isThread, clearNotifications: clearNotifications, ); @@ -141,15 +150,17 @@ class ChatView extends StatelessWidget { ?.getPrefixedAccount(input, state.room) ?.$1, onTapOverrideClient: (overrideClient) { - EventBus.doOpenRoom(state.room.identifier, - clientId: overrideClient.identifier); + EventBus.doOpenRoom( + state.room.identifier, + clientId: overrideClient.identifier, + ); if (state.isThread) { WidgetsBinding.instance.addPostFrameCallback((_) { EventBus.openThread.add(( overrideClient.identifier, state.room.identifier, - state.threadId! + state.threadId!, )); }); } @@ -157,8 +168,8 @@ class ChatView extends StatelessWidget { editLastMessage: state.editLastMessage, hintText: state.room.permissions.canSendMessage ? state.room.isE2EE - ? sendEncryptedMessagePrompt - : sendUnencryptedMessagePrompt + ? sendEncryptedMessagePrompt + : sendUnencryptedMessagePrompt : cantSentMessagePrompt, cancelReply: () { state.setInteractingEvent(null); @@ -167,7 +178,8 @@ class ChatView extends StatelessWidget { ? TypingIndicatorsWidget( component: state.typingIndicators!, key: ValueKey( - "room_typing_indicators_key_${state.room.identifier}"), + "room_typing_indicators_key_${state.room.identifier}", + ), ) : null, processAutofill: (text) => diff --git a/commet/lib/ui/organisms/home_screen/home_screen.dart b/commet/lib/ui/organisms/home_screen/home_screen.dart index 60f50906d..6180d98b7 100644 --- a/commet/lib/ui/organisms/home_screen/home_screen.dart +++ b/commet/lib/ui/organisms/home_screen/home_screen.dart @@ -80,14 +80,18 @@ class _HomeScreenState extends State { } void updateRecent() { - recentActivity = - List.from(filterClient?.rooms ?? widget.clientManager.rooms); + recentActivity = List.from( + filterClient?.rooms ?? widget.clientManager.rooms, + ); recentActivity.removeWhere((element) => element.lastEvent == null); - mergeSort(recentActivity, compare: (a, b) { - return b.lastEventTimestamp.compareTo(a.lastEventTimestamp); - }); + mergeSort( + recentActivity, + compare: (a, b) { + return b.lastEventTimestamp.compareTo(a.lastEventTimestamp); + }, + ); if (recentActivity.length > widget.numRecentRooms) { recentActivity = recentActivity.sublist(0, widget.numRecentRooms); @@ -114,12 +118,13 @@ class _HomeScreenState extends State { onBurgerMenuTap: widget.onBurgerMenuTap, text: CommonStrings.promptHome, menu: SizedBox( - width: 50, - height: 50, - child: tiamat.IconButton( - icon: Icons.search, - onPressed: () => QuickSwitcher.show(context), - )), + width: 50, + height: 50, + child: tiamat.IconButton( + icon: Icons.search, + onPressed: () => QuickSwitcher.show(context), + ), + ), ), ), ), @@ -138,15 +143,18 @@ class _HomeScreenState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Row(spacing: 8, children: [ - Icon(Icons.search), - tiamat.Text.labelLow(CommonStrings.promptSearch), - ]), + Row( + spacing: 8, + children: [ + Icon(Icons.search), + tiamat.Text.labelLow(CommonStrings.promptSearch), + ], + ), if (MediaQuery.of(context).desktop) Padding( padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), child: tiamat.Text.labelLow("Ctrl + K"), - ) + ), ], ), ), @@ -164,18 +172,20 @@ class _HomeScreenState extends State { IncomingInvitationsWidget(widget.clientManager), HomeScreenView( clientManager: widget.clientManager, - rooms: widget.clientManager - .singleRooms(filterClient: filterClient), + rooms: widget.clientManager.singleRooms( + filterClient: filterClient, + ), recentActivity: recentActivity, onRoomClicked: (room) => EventBus.doOpenRoom( - room.identifier, - clientId: room.client.identifier), + room.identifier, + clientId: room.client.identifier, + ), joinRoom: joinRoom, createRoom: createRoom, ), ], ), - ) + ), ], ), ), diff --git a/commet/lib/ui/organisms/home_screen/home_screen_view.dart b/commet/lib/ui/organisms/home_screen/home_screen_view.dart index deea604d2..3fbc57c67 100644 --- a/commet/lib/ui/organisms/home_screen/home_screen_view.dart +++ b/commet/lib/ui/organisms/home_screen/home_screen_view.dart @@ -23,31 +23,42 @@ class HomeScreenView extends StatelessWidget { final Future Function(Client client, String address)? joinRoom; final Future Function(Client client, CreateRoomArgs args)? createRoom; - const HomeScreenView( - {super.key, - required this.clientManager, - this.rooms, - this.recentActivity, - this.onRoomClicked, - this.acceptInvite, - this.rejectInvite, - this.joinRoom, - this.createRoom, - this.invitations}); + const HomeScreenView({ + super.key, + required this.clientManager, + this.rooms, + this.recentActivity, + this.onRoomClicked, + this.acceptInvite, + this.rejectInvite, + this.joinRoom, + this.createRoom, + this.invitations, + }); - String get labelHomeRecentActivity => Intl.message("Recent Activity", - name: "labelHomeRecentActivity", - desc: "Short label for header of recent room activity"); + String get labelHomeRecentActivity => Intl.message( + "Recent Activity", + name: "labelHomeRecentActivity", + desc: "Short label for header of recent room activity", + ); - String get labelHomeAlerts => Intl.message("Alerts", - name: "labelHomeAlerts", desc: "Short label for header of alerts"); + String get labelHomeAlerts => Intl.message( + "Alerts", + name: "labelHomeAlerts", + desc: "Short label for header of alerts", + ); - static String get labelHomeRoomsList => Intl.message("Rooms", - name: "labelHomeRoomsList", desc: "Short label for header of rooms list"); + static String get labelHomeRoomsList => Intl.message( + "Rooms", + name: "labelHomeRoomsList", + desc: "Short label for header of rooms list", + ); - String get labelHomeInvitations => Intl.message("Invitations", - name: "labelHomeInvitations", - desc: "Short label for header of invitations list"); + String get labelHomeInvitations => Intl.message( + "Invitations", + name: "labelHomeInvitations", + desc: "Short label for header of invitations list", + ); @override Widget build(BuildContext context) { @@ -71,110 +82,121 @@ class HomeScreenView extends StatelessWidget { Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 12), child: roomsList(context), - ) + ), ], ); } Widget alerts() { return Panel( - mode: TileType.surfaceContainerLow, - header: labelHomeAlerts, - child: ImplicitlyAnimatedList( - padding: EdgeInsetsGeometry.zero, - shrinkWrap: true, - itemData: clientManager.alertManager.alerts, - initialAnimation: false, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, alert) { - return AlertView(alert); - }, - )); + mode: TileType.surfaceContainerLow, + header: labelHomeAlerts, + child: ImplicitlyAnimatedList( + padding: EdgeInsetsGeometry.zero, + shrinkWrap: true, + itemData: clientManager.alertManager.alerts, + initialAnimation: false, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, alert) { + return AlertView(alert); + }, + ), + ); } Widget recentRooms() { return Panel( - mode: TileType.surface, - header: labelHomeRecentActivity, - child: ImplicitlyAnimatedList( - shrinkWrap: true, - padding: EdgeInsetsGeometry.zero, - itemData: recentActivity!, - initialAnimation: false, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, room) { - return Padding( - padding: EdgeInsetsGeometry.fromLTRB(0, 2, 0, 2), - child: RoomPanel( + mode: TileType.surface, + header: labelHomeRecentActivity, + child: ImplicitlyAnimatedList( + shrinkWrap: true, + padding: EdgeInsetsGeometry.zero, + itemData: recentActivity!, + initialAnimation: false, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, room) { + return Padding( + padding: EdgeInsetsGeometry.fromLTRB(0, 2, 0, 2), + child: RoomPanel( + shouldShowAvatarForRoom: (room) => + clientManager.clients + .where((i) => i.hasRoom(room.identifier)) + .length > + 1, + key: ValueKey("recent-activity-room_${room.localId}"), + room, + ), + ); + }, + ), + ); + } + + Widget roomsList(BuildContext context) { + return Panel( + mode: TileType.surface, + header: labelHomeRoomsList, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + ImplicitlyAnimatedList( + padding: EdgeInsetsGeometry.zero, + physics: const NeverScrollableScrollPhysics(), + initialAnimation: false, + shrinkWrap: true, + itemData: rooms!, + itemBuilder: (context, room) { + return Padding( + padding: EdgeInsetsGeometry.fromLTRB(0, 2, 0, 2), + child: RoomPanel( + room, shouldShowAvatarForRoom: (room) => clientManager.clients .where((i) => i.hasRoom(room.identifier)) .length > 1, - key: ValueKey("recent-activity-room_${room.localId}"), - room), - ); - }, - )); - } - - Widget roomsList(BuildContext context) { - return Panel( - mode: TileType.surface, - header: labelHomeRoomsList, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - ImplicitlyAnimatedList( - padding: EdgeInsetsGeometry.zero, - physics: const NeverScrollableScrollPhysics(), - initialAnimation: false, - shrinkWrap: true, - itemData: rooms!, - itemBuilder: (context, room) { - return Padding( - padding: EdgeInsetsGeometry.fromLTRB(0, 2, 0, 2), - child: RoomPanel(room, - shouldShowAvatarForRoom: (room) => - clientManager.clients - .where((i) => i.hasRoom(room.identifier)) - .length > - 1, - key: ValueKey("homescreen-room_${room.localId}")), - ); - }, - ), - tiamat.CircleButton( - radius: BuildConfig.MOBILE ? 24 : 16, - icon: Icons.add, - onPressed: () => addRoomDialog(context), - ), - ], - )); + key: ValueKey("homescreen-room_${room.localId}"), + ), + ); + }, + ), + tiamat.CircleButton( + radius: BuildConfig.MOBILE ? 24 : 16, + icon: Icons.add, + onPressed: () => addRoomDialog(context), + ), + ], + ), + ); } Widget invitationsList() { return Panel( - mode: TileType.surfaceContainer, - header: labelHomeInvitations, - child: ImplicitlyAnimatedList( - padding: EdgeInsetsGeometry.zero, - physics: const NeverScrollableScrollPhysics(), - initialAnimation: false, - shrinkWrap: true, - itemData: invitations!, - itemBuilder: (context, invitation) { - return InvitationDisplay( - invitation, - acceptInvitation: acceptInvite, - rejectInvitation: rejectInvite, - ); - }, - )); + mode: TileType.surfaceContainer, + header: labelHomeInvitations, + child: ImplicitlyAnimatedList( + padding: EdgeInsetsGeometry.zero, + physics: const NeverScrollableScrollPhysics(), + initialAnimation: false, + shrinkWrap: true, + itemData: invitations!, + itemBuilder: (context, invitation) { + return InvitationDisplay( + invitation, + acceptInvitation: acceptInvite, + rejectInvitation: rejectInvite, + ); + }, + ), + ); } void addRoomDialog(BuildContext context) { - GetOrCreateRoom.show(null, context, - pickExisting: false, showAllRoomTypes: true); + GetOrCreateRoom.show( + null, + context, + pickExisting: false, + showAllRoomTypes: true, + ); } } diff --git a/commet/lib/ui/organisms/home_screen/important_rooms_list.dart b/commet/lib/ui/organisms/home_screen/important_rooms_list.dart index d41e07bd9..28db20c18 100644 --- a/commet/lib/ui/organisms/home_screen/important_rooms_list.dart +++ b/commet/lib/ui/organisms/home_screen/important_rooms_list.dart @@ -40,8 +40,9 @@ class ImportantRoomsList extends StatelessWidget { child: tiamat.Text.labelLow("Favorites"), ), Padding( - padding: const EdgeInsetsGeometry.fromLTRB(3, 0, 0, 0), - child: child) + padding: const EdgeInsetsGeometry.fromLTRB(3, 0, 0, 0), + child: child, + ), ], ); } @@ -50,16 +51,19 @@ class ImportantRoomsList extends StatelessWidget { }, itemBuilder: (context, value) { return Padding( - padding: padding, - child: RoomPanel( - key: ValueKey("RoomFavoritesList-${value.localId}"), - value, - onTap: () { - EventBus.doOpenRoom(value.identifier, - clientId: value.client.identifier, - openInSpace: false); - }, - )); + padding: padding, + child: RoomPanel( + key: ValueKey("RoomFavoritesList-${value.localId}"), + value, + onTap: () { + EventBus.doOpenRoom( + value.identifier, + clientId: value.client.identifier, + openInSpace: false, + ); + }, + ), + ); }, ), NotifyingListBuilder( @@ -97,8 +101,9 @@ class ImportantRoomsList extends StatelessWidget { ], ), Padding( - padding: const EdgeInsetsGeometry.fromLTRB(3, 0, 0, 0), - child: child) + padding: const EdgeInsetsGeometry.fromLTRB(3, 0, 0, 0), + child: child, + ), ], ); } diff --git a/commet/lib/ui/organisms/home_screen/single_rooms_list.dart b/commet/lib/ui/organisms/home_screen/single_rooms_list.dart index 95fcce309..9ca33e2c8 100644 --- a/commet/lib/ui/organisms/home_screen/single_rooms_list.dart +++ b/commet/lib/ui/organisms/home_screen/single_rooms_list.dart @@ -20,67 +20,75 @@ class SingleRoomsList extends StatelessWidget { var padding = const EdgeInsets.fromLTRB(0, 4, 0, 4); return ScaledSafeArea( - top: true, - bottom: false, - child: SingleChildScrollView( - child: NotifyingListBuilder( - sortFunction: (p0, p1) { - return (p1.lastEventTimestamp.compareTo(p0.lastEventTimestamp)); - }, - shrinkWrap: true, - list: state.singleRooms, - physics: NeverScrollableScrollPhysics(), - builder: (context, {required child, required list}) { - if (list.isNotEmpty) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: tiamat.Text.labelLow( - HomeScreenView.labelHomeRoomsList, - ), + top: true, + bottom: false, + child: SingleChildScrollView( + child: NotifyingListBuilder( + sortFunction: (p0, p1) { + return (p1.lastEventTimestamp.compareTo(p0.lastEventTimestamp)); + }, + shrinkWrap: true, + list: state.singleRooms, + physics: NeverScrollableScrollPhysics(), + builder: (context, {required child, required list}) { + if (list.isNotEmpty) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: tiamat.Text.labelLow( + HomeScreenView.labelHomeRoomsList, ), - Padding( - padding: const EdgeInsets.all(8.0), - child: tiamat.IconButton( - icon: Icons.add, - onPressed: () { - GetOrCreateRoom.show(null, context, - pickExisting: false, showAllRoomTypes: true); - }, - ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: tiamat.IconButton( + icon: Icons.add, + onPressed: () { + GetOrCreateRoom.show( + null, + context, + pickExisting: false, + showAllRoomTypes: true, + ); + }, ), - ], - ), - Padding( - padding: const EdgeInsetsGeometry.fromLTRB(3, 0, 0, 0), - child: child) - ], - ); - } + ), + ], + ), + Padding( + padding: const EdgeInsetsGeometry.fromLTRB(3, 0, 0, 0), + child: child, + ), + ], + ); + } - return child; - }, - itemBuilder: (context, value) { - return Padding( - padding: padding, - child: RoomPanel( - shouldShowAvatarForRoom: (room) => - clientManager!.clients - .where((i) => i.hasRoom(room.identifier)) - .length > - 1, - key: ValueKey("SingleRoomsList-${value.localId}"), - value, - onTap: () { - onSelectRoom?.call(value); - })); - }, - ), - )); + return child; + }, + itemBuilder: (context, value) { + return Padding( + padding: padding, + child: RoomPanel( + shouldShowAvatarForRoom: (room) => + clientManager!.clients + .where((i) => i.hasRoom(room.identifier)) + .length > + 1, + key: ValueKey("SingleRoomsList-${value.localId}"), + value, + onTap: () { + onSelectRoom?.call(value); + }, + ), + ); + }, + ), + ), + ); } } diff --git a/commet/lib/ui/organisms/invitation_view/incoming_invitations_view.dart b/commet/lib/ui/organisms/invitation_view/incoming_invitations_view.dart index 434666731..ff40f9e4b 100644 --- a/commet/lib/ui/organisms/invitation_view/incoming_invitations_view.dart +++ b/commet/lib/ui/organisms/invitation_view/incoming_invitations_view.dart @@ -33,7 +33,7 @@ class _IncomingInvitationsWidgetState extends State { SingleInvitationComponentIncomingView( comp, showCurrentUserId: widget.manager.clients.length > 1, - ) + ), ], ); } diff --git a/commet/lib/ui/organisms/invitation_view/send_invitation.dart b/commet/lib/ui/organisms/invitation_view/send_invitation.dart index 115cd3610..398439bbf 100644 --- a/commet/lib/ui/organisms/invitation_view/send_invitation.dart +++ b/commet/lib/ui/organisms/invitation_view/send_invitation.dart @@ -11,13 +11,16 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class SendInvitationWidget extends StatefulWidget { - const SendInvitationWidget(this.client, this.component, - {super.key, - this.roomId, - this.displayName, - this.onUserPicked, - this.showSuggestions = true, - this.existingMembers}); + const SendInvitationWidget( + this.client, + this.component, { + super.key, + this.roomId, + this.displayName, + this.onUserPicked, + this.showSuggestions = true, + this.existingMembers, + }); final Client client; final bool showSuggestions; final Iterable? existingMembers; @@ -57,10 +60,13 @@ class _SendInvitationWidgetState extends State { var dmComponent = widget.client.getComponent(); var recommended = List.from(dmComponent?.directMessageRooms ?? []); - recommended.removeWhere((element) => - widget.existingMembers - ?.contains(dmComponent?.getDirectMessagePartnerId(element)) == - true); + recommended.removeWhere( + (element) => + widget.existingMembers?.contains( + dmComponent?.getDirectMessagePartnerId(element), + ) == + true, + ); return Opacity( opacity: loading ? 0.3 : 1.0, @@ -68,8 +74,9 @@ class _SendInvitationWidgetState extends State { ignoring: loading, child: ScaledSafeArea( child: SizedBox( - width: 500, - child: Column(children: [ + width: 500, + child: Column( + children: [ tiamat.TextInput( controller: controller, icon: const Icon(Icons.search), @@ -78,22 +85,24 @@ class _SendInvitationWidgetState extends State { ), if (isSearching || searchResults?.isNotEmpty == true) SizedBox( - height: 300, - child: isSearching - ? const Center(child: CircularProgressIndicator()) - : ListView.builder( - itemCount: searchResults!.length, - shrinkWrap: true, - itemBuilder: (context, index) { - return MiniProfileView( - client: widget.component.client, - userId: searchResults![index].identifier, - initialProfile: searchResults![index], - onTap: () => invitePeer( - searchResults![index].identifier), - ); - }, - )), + height: 300, + child: isSearching + ? const Center(child: CircularProgressIndicator()) + : ListView.builder( + itemCount: searchResults!.length, + shrinkWrap: true, + itemBuilder: (context, index) { + return MiniProfileView( + client: widget.component.client, + userId: searchResults![index].identifier, + initialProfile: searchResults![index], + onTap: () => invitePeer( + searchResults![index].identifier, + ), + ); + }, + ), + ), if (!isSearching && searchResults?.isEmpty == true) Column( children: [ @@ -101,7 +110,7 @@ class _SendInvitationWidgetState extends State { tiamat.Button( text: "Send invite", onTap: () => invitePeer(controller.text), - ) + ), ], ), if (showRecommendations && recommended.isNotEmpty) @@ -114,17 +123,21 @@ class _SendInvitationWidgetState extends State { itemCount: recommended.length, itemBuilder: (context, index) { var room = recommended[index]; - var userId = - dmComponent!.getDirectMessagePartnerId(room)!; + var userId = dmComponent!.getDirectMessagePartnerId( + room, + )!; return MiniProfileView( - client: room.client, - onTap: () => invitePeer(userId), - userId: userId); + client: room.client, + onTap: () => invitePeer(userId), + userId: userId, + ); }, ), ], - ) - ])), + ), + ], + ), + ), ), ), ); @@ -163,10 +176,12 @@ class _SendInvitationWidgetState extends State { return; } - final confirm = await AdaptiveDialog.confirmation(context, - prompt: - "Are you sure you want to Invite $userId to the room ${widget.displayName}?", - title: "Invitation"); + final confirm = await AdaptiveDialog.confirmation( + context, + prompt: + "Are you sure you want to Invite $userId to the room ${widget.displayName}?", + title: "Invitation", + ); if (confirm != true) { return; } diff --git a/commet/lib/ui/organisms/invitation_view/single_invitation_component_view.dart b/commet/lib/ui/organisms/invitation_view/single_invitation_component_view.dart index 4465874f9..7de20410c 100644 --- a/commet/lib/ui/organisms/invitation_view/single_invitation_component_view.dart +++ b/commet/lib/ui/organisms/invitation_view/single_invitation_component_view.dart @@ -9,8 +9,11 @@ import 'package:intl/intl.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class SingleInvitationComponentIncomingView extends StatefulWidget { - const SingleInvitationComponentIncomingView(this.component, - {super.key, this.showCurrentUserId = false}); + const SingleInvitationComponentIncomingView( + this.component, { + super.key, + this.showCurrentUserId = false, + }); final InvitationComponent component; final bool showCurrentUserId; @@ -22,15 +25,17 @@ class SingleInvitationComponentIncomingView extends StatefulWidget { class _SingleInvitationComponentIncomingViewState extends State { String labelInvitationsForUser(String user) => Intl.message( - "Invitations for $user", - desc: - "Label for the list of incoming invitations, specifying which user these invitations are intended for", - args: [user], - name: "labelInvitationsForUser"); + "Invitations for $user", + desc: "Label for the list of incoming invitations, specifying which user these invitations are intended for", + args: [user], + name: "labelInvitationsForUser", + ); - String get labelInvitations => Intl.message("Invitations", - desc: "Label for the list of incoming invitations", - name: "labelInvitations"); + String get labelInvitations => Intl.message( + "Invitations", + desc: "Label for the list of incoming invitations", + name: "labelInvitations", + ); StreamSubscription? sub; @@ -55,33 +60,37 @@ class _SingleInvitationComponentIncomingViewState return Padding( padding: const EdgeInsets.fromLTRB(0, 4, 0, 4), child: tiamat.Panel( - mode: tiamat.TileType.surfaceContainer, - header: widget.showCurrentUserId - ? labelInvitationsForUser( - widget.component.client.self!.displayName) - : labelInvitations, - child: Column( - children: [ - for (var invite in widget.component.invitations) - InvitationDisplay( - invite, - acceptInvitation: (invitation) => - acceptInvitation(widget.component, invitation), - rejectInvitation: (invitation) => - rejectInvitation(widget.component, invitation), - ) - ], - )), + mode: tiamat.TileType.surfaceContainer, + header: widget.showCurrentUserId + ? labelInvitationsForUser(widget.component.client.self!.displayName) + : labelInvitations, + child: Column( + children: [ + for (var invite in widget.component.invitations) + InvitationDisplay( + invite, + acceptInvitation: (invitation) => + acceptInvitation(widget.component, invitation), + rejectInvitation: (invitation) => + rejectInvitation(widget.component, invitation), + ), + ], + ), + ), ); } Future acceptInvitation( - InvitationComponent comp, Invitation invite) async { + InvitationComponent comp, + Invitation invite, + ) async { await comp.acceptInvitation(invite); } Future rejectInvitation( - InvitationComponent comp, Invitation invite) async { + InvitationComponent comp, + Invitation invite, + ) async { await comp.rejectInvitation(invite); } } diff --git a/commet/lib/ui/organisms/overlay_windows/overlay_window.dart b/commet/lib/ui/organisms/overlay_windows/overlay_window.dart index e508321fd..be2987e67 100644 --- a/commet/lib/ui/organisms/overlay_windows/overlay_window.dart +++ b/commet/lib/ui/organisms/overlay_windows/overlay_window.dart @@ -36,12 +36,15 @@ class _OverlayWindowState extends State var size = MediaQuery.of(context).scale().size; var margin = 50.0; - var max = Offset(size.width - padding.right - margin, - size.height - padding.bottom - margin); + var max = Offset( + size.width - padding.right - margin, + size.height - padding.bottom - margin, + ); _positionedOffset = Offset( - _positionedOffset.dx.clamp(-targetSize.width + margin, max.dx), - _positionedOffset.dy.clamp(-targetSize.height + margin, max.dy)); + _positionedOffset.dx.clamp(-targetSize.width + margin, max.dx), + _positionedOffset.dy.clamp(-targetSize.height + margin, max.dy), + ); return _positionedOffset; } @@ -51,8 +54,10 @@ class _OverlayWindowState extends State final padding = MediaQuery.of(context).padding; var size = MediaQuery.of(context).scale().size; - return Size(size.width - padding.left - padding.right, - size.height - padding.top - padding.bottom); + return Size( + size.width - padding.left - padding.right, + size.height - padding.top - padding.bottom, + ); } return Size(300, 200); @@ -95,7 +100,8 @@ class _OverlayWindowState extends State newOffset = targetOffset; } - var sizeDiff = (newSize.width - targetSize.width).abs() + + var sizeDiff = + (newSize.width - targetSize.width).abs() + (newSize.height - targetSize.height).abs(); if (sizeDiff < 1) { @@ -132,9 +138,10 @@ class _OverlayWindowState extends State decoration: BoxDecoration( boxShadow: [ BoxShadow( - color: Colors.black.withAlpha(120), - offset: Offset(3, 3), - blurRadius: 10) + color: Colors.black.withAlpha(120), + offset: Offset(3, 3), + blurRadius: 10, + ), ], borderRadius: BorderRadius.circular(8), color: ColorScheme.of(context).surfaceContainer, @@ -153,27 +160,29 @@ class _OverlayWindowState extends State if (fullScreen || ShowOnHover.useTouchControls == false) SizedBox( - height: 30, - width: 30, - child: tiamat.IconButton( - icon: fullScreen - ? Icons.minimize - : Icons.fullscreen, - onPressed: () { - setState(() { - fullScreen = !fullScreen; - }); - }, - )), - SizedBox( height: 30, width: 30, child: tiamat.IconButton( - icon: Icons.close, - onPressed: widget.onClose, - )), + icon: fullScreen + ? Icons.minimize + : Icons.fullscreen, + onPressed: () { + setState(() { + fullScreen = !fullScreen; + }); + }, + ), + ), + SizedBox( + height: 30, + width: 30, + child: tiamat.IconButton( + icon: Icons.close, + onPressed: widget.onClose, + ), + ), ], - ) + ), ], ), ), @@ -185,43 +194,46 @@ class _OverlayWindowState extends State child: Stack( children: [ Container( - color: ColorScheme.of(context) - .surfaceContainerLowest, - child: widget.window.widget), + color: ColorScheme.of(context) + .surfaceContainerLowest, + child: widget.window.widget, + ), if (!fullScreen) ShowOnHover( - background: Container( - color: Colors.transparent, - child: SizedBox( - width: double.infinity, - height: double.infinity, - ), + background: Container( + color: Colors.transparent, + child: SizedBox( + width: double.infinity, + height: double.infinity, ), - child: Container( - color: ColorScheme.of(context) - .surfaceContainerLow - .withAlpha(150), - child: Stack( - children: [ - Center( - child: SizedBox( - width: 50, - height: 50, - child: tiamat.IconButton( - icon: Icons.fullscreen, - size: 25, - onPressed: () { - setState(() { - fullScreen = true; - }); - }, - iconColor: - ColorScheme.of(context) - .onSurface, - ))), - ], - ), - )), + ), + child: Container( + color: ColorScheme.of(context) + .surfaceContainerLow + .withAlpha(150), + child: Stack( + children: [ + Center( + child: SizedBox( + width: 50, + height: 50, + child: tiamat.IconButton( + icon: Icons.fullscreen, + size: 25, + onPressed: () { + setState(() { + fullScreen = true; + }); + }, + iconColor: ColorScheme.of(context) + .onSurface, + ), + ), + ), + ], + ), + ), + ), ], ), ), @@ -244,8 +256,9 @@ class _OverlayWindowState extends State }); }, child: buildWithWindowSize( - Opacity(opacity: 0, child: Placeholder())), - ) + Opacity(opacity: 0, child: Placeholder()), + ), + ), ], ), ), @@ -254,13 +267,15 @@ class _OverlayWindowState extends State Widget buildWithWindowSize(Widget child) { return ScaledSafeArea( - top: fullScreen, - bottom: fullScreen, - left: fullScreen, - right: fullScreen, - child: SizedBox( - width: _currentSize.width, - height: _currentSize.height, - child: child)); + top: fullScreen, + bottom: fullScreen, + left: fullScreen, + right: fullScreen, + child: SizedBox( + width: _currentSize.width, + height: _currentSize.height, + child: child, + ), + ); } } diff --git a/commet/lib/ui/organisms/overlay_windows/overlay_window_manager.dart b/commet/lib/ui/organisms/overlay_windows/overlay_window_manager.dart index 07e782e6a..358ba4b7d 100644 --- a/commet/lib/ui/organisms/overlay_windows/overlay_window_manager.dart +++ b/commet/lib/ui/organisms/overlay_windows/overlay_window_manager.dart @@ -6,8 +6,11 @@ class OverlayWindow { String title; Stream onClose; - OverlayWindow( - {required this.widget, required this.title, required this.onClose}); + OverlayWindow({ + required this.widget, + required this.title, + required this.onClose, + }); } class OverlayWindowsData extends InheritedWidget { @@ -78,14 +81,16 @@ class OverlayWindowsSurface extends StatelessWidget { @override Widget build(BuildContext context) { var data = OverlayWindowsData.of(context); - return Stack(children: [ - for (var i in data.windows) - OverlayWindowWidget( - window: i, - onClose: () { - OverlayWindowsManager.of(context).windowClosed(i); - }, - ), - ]); + return Stack( + children: [ + for (var i in data.windows) + OverlayWindowWidget( + window: i, + onClose: () { + OverlayWindowsManager.of(context).windowClosed(i); + }, + ), + ], + ); } } diff --git a/commet/lib/ui/organisms/particle_player/particle_player.dart b/commet/lib/ui/organisms/particle_player/particle_player.dart index 508ca29f5..10ae99959 100644 --- a/commet/lib/ui/organisms/particle_player/particle_player.dart +++ b/commet/lib/ui/organisms/particle_player/particle_player.dart @@ -56,7 +56,8 @@ class _ParticlePlayerState extends State { Widget build(BuildContext context) { if (currentEffect?.system != null) { return IgnorePointer( - child: ParticleSystemRenderer(system: currentEffect!.system!)); + child: ParticleSystemRenderer(system: currentEffect!.system!), + ); } else { return Container(); } diff --git a/commet/lib/ui/organisms/particle_player/particle_system_confetti.dart b/commet/lib/ui/organisms/particle_player/particle_system_confetti.dart index 31ab4a63d..b6a36a29e 100644 --- a/commet/lib/ui/organisms/particle_player/particle_system_confetti.dart +++ b/commet/lib/ui/organisms/particle_player/particle_system_confetti.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'dart:ui'; import 'dart:ui' as ui; + import 'package:commet/client/components/message_effects/message_effect_particles.dart'; import 'package:flutter/material.dart'; import 'package:starfield/starfield.dart'; @@ -13,16 +14,25 @@ class MessageEffectConfetti implements MessageEffectParticles { @override Future init() async { var data = await ImmutableBuffer.fromAsset( - "assets/images/effects/particles/confetti.webp"); + "assets/images/effects/particles/confetti.webp", + ); var codec = await ui.instantiateImageCodecFromBuffer(data); var sprite = ParticleSprite(); await sprite.init( - codec: codec, - spriteSheet: SpriteSheetInfo( - frames: 59, frameWidth: 64, frameHeight: 64, framesPerSecond: 50)); - system = - ParticleSystemConfetti(sprite: sprite, spriteSize: 0.2, gravity: 10); + codec: codec, + spriteSheet: SpriteSheetInfo( + frames: 59, + frameWidth: 64, + frameHeight: 64, + framesPerSecond: 50, + ), + ); + system = ParticleSystemConfetti( + sprite: sprite, + spriteSize: 0.2, + gravity: 10, + ); system!.setSize(200); } diff --git a/commet/lib/ui/organisms/particle_player/particle_system_eyes.dart b/commet/lib/ui/organisms/particle_player/particle_system_eyes.dart index c242fe40b..e7cbc0054 100644 --- a/commet/lib/ui/organisms/particle_player/particle_system_eyes.dart +++ b/commet/lib/ui/organisms/particle_player/particle_system_eyes.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'dart:ui' as ui; + import 'package:commet/client/components/message_effects/message_effect_particles.dart'; import 'package:flutter/material.dart'; @@ -17,20 +18,27 @@ class MessageEffectEyes implements MessageEffectParticles { @override Future init() async { var data = await ImmutableBuffer.fromAsset( - "assets/images/effects/particles/fluent-emoji-eyes.webp"); + "assets/images/effects/particles/fluent-emoji-eyes.webp", + ); var codec = await ui.instantiateImageCodecFromBuffer(data); var sprite = ParticleSprite(); await sprite.init( - codec: codec, - spriteSheet: SpriteSheetInfo( - frames: 49, - frameWidth: 128, - frameHeight: 128, - framesPerSecond: 30)); + codec: codec, + spriteSheet: SpriteSheetInfo( + frames: 49, + frameWidth: 128, + frameHeight: 128, + framesPerSecond: 30, + ), + ); system = ParticleSystemEyes( - sprite: sprite, spriteSize: 0.4, gravity: -10, height: 500); + sprite: sprite, + spriteSize: 0.4, + gravity: -10, + height: 500, + ); system!.setSize(numParticles); } diff --git a/commet/lib/ui/organisms/particle_player/particle_system_hug.dart b/commet/lib/ui/organisms/particle_player/particle_system_hug.dart index 7b4a3c61f..82ae4a8c6 100644 --- a/commet/lib/ui/organisms/particle_player/particle_system_hug.dart +++ b/commet/lib/ui/organisms/particle_player/particle_system_hug.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'dart:ui'; import 'dart:ui' as ui; + import 'package:commet/client/components/message_effects/message_effect_particles.dart'; import 'package:flutter/material.dart'; @@ -14,20 +15,27 @@ class MessageEffectHug implements MessageEffectParticles { @override Future init() async { var data = await ImmutableBuffer.fromAsset( - "assets/images/effects/particles/fluent-emoji-smile-with-hearts.webp"); + "assets/images/effects/particles/fluent-emoji-smile-with-hearts.webp", + ); var codec = await ui.instantiateImageCodecFromBuffer(data); var sprite = ParticleSprite(); await sprite.init( - codec: codec, - spriteSheet: SpriteSheetInfo( - frames: 72, - frameWidth: 128, - frameHeight: 128, - framesPerSecond: 30)); + codec: codec, + spriteSheet: SpriteSheetInfo( + frames: 72, + frameWidth: 128, + frameHeight: 128, + framesPerSecond: 30, + ), + ); system = ParticleSystemEyes( - sprite: sprite, spriteSize: 0.4, gravity: -10, height: 500); + sprite: sprite, + spriteSize: 0.4, + gravity: -10, + height: 500, + ); system!.setSize(200); } diff --git a/commet/lib/ui/organisms/particle_player/particle_system_snow.dart b/commet/lib/ui/organisms/particle_player/particle_system_snow.dart index e64a8955c..36c418203 100644 --- a/commet/lib/ui/organisms/particle_player/particle_system_snow.dart +++ b/commet/lib/ui/organisms/particle_player/particle_system_snow.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'dart:ui' as ui; + import 'package:commet/client/components/message_effects/message_effect_particles.dart'; import 'package:starfield/starfield.dart'; @@ -11,20 +12,27 @@ class MessageEffectSnow implements MessageEffectParticles { @override Future init() async { var data = await ImmutableBuffer.fromAsset( - "assets/images/effects/particles/fluent-emoji-snowflake.webp"); + "assets/images/effects/particles/fluent-emoji-snowflake.webp", + ); var codec = await ui.instantiateImageCodecFromBuffer(data); var sprite = ParticleSprite(); await sprite.init( - codec: codec, - spriteSheet: SpriteSheetInfo( - frames: 72, - frameWidth: 128, - frameHeight: 128, - framesPerSecond: 30)); + codec: codec, + spriteSheet: SpriteSheetInfo( + frames: 72, + frameWidth: 128, + frameHeight: 128, + framesPerSecond: 30, + ), + ); system = ParticleSystemSnow( - sprite: sprite, spriteSize: 0.3, gravity: 10, height: 500); + sprite: sprite, + spriteSize: 0.3, + gravity: 10, + height: 500, + ); system!.setSize(500); } diff --git a/commet/lib/ui/organisms/particle_player/particle_system_space_invaders.dart b/commet/lib/ui/organisms/particle_player/particle_system_space_invaders.dart index 2047a9d7c..dcf1a7255 100644 --- a/commet/lib/ui/organisms/particle_player/particle_system_space_invaders.dart +++ b/commet/lib/ui/organisms/particle_player/particle_system_space_invaders.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'dart:ui' as ui; + import 'package:commet/client/components/message_effects/message_effect_particles.dart'; import 'package:flutter/material.dart'; import 'package:starfield/starfield.dart'; @@ -14,13 +15,12 @@ class MessageEffectSpaceInvaders implements MessageEffectParticles { @override Future init() async { var data = await ImmutableBuffer.fromAsset( - "assets/images/effects/particles/fluent-emoji-alien-monster.png"); + "assets/images/effects/particles/fluent-emoji-alien-monster.png", + ); var codec = await ui.instantiateImageCodecFromBuffer(data); var sprite = ParticleSprite(); - await sprite.init( - codec: codec, - ); + await sprite.init(codec: codec); FlutterView view = WidgetsBinding.instance.platformDispatcher.views.first; @@ -33,7 +33,11 @@ class MessageEffectSpaceInvaders implements MessageEffectParticles { int columns = 5; system = ParticleSystemSpaceInvaders( - sprite: sprite, spriteSize: 0.2, gravity: 5, factor: rows); + sprite: sprite, + spriteSize: 0.2, + gravity: 5, + factor: rows, + ); int numParticles = rows * columns; diff --git a/commet/lib/ui/organisms/photo_albums/photo_album_view.dart b/commet/lib/ui/organisms/photo_albums/photo_album_view.dart index 9e2e10b67..0b6a11450 100644 --- a/commet/lib/ui/organisms/photo_albums/photo_album_view.dart +++ b/commet/lib/ui/organisms/photo_albums/photo_album_view.dart @@ -143,8 +143,9 @@ class _PhotoAlbumViewState extends State { if (loadingMorePhotos) ScaledSafeArea( child: Align( - alignment: Alignment.bottomCenter, - child: CircularProgressIndicator()), + alignment: Alignment.bottomCenter, + child: CircularProgressIndicator(), + ), ), if (widget.component.canUpload) ScaledSafeArea( @@ -155,7 +156,7 @@ class _PhotoAlbumViewState extends State { child: Icon(Icons.add), ), ), - ) + ), ], ), ); @@ -176,9 +177,7 @@ class _PhotoAlbumViewState extends State { if (item.status == TimelineEventStatus.sending) { result = Container( color: scheme.surfaceContainerLow, - child: Center( - child: CircularProgressIndicator(), - ), + child: Center(child: CircularProgressIndicator()), ); } @@ -186,10 +185,11 @@ class _PhotoAlbumViewState extends State { result = Container( color: scheme.surfaceContainerLow, child: Center( - child: Icon( - Icons.error, - color: Theme.of(context).colorScheme.error, - )), + child: Icon( + Icons.error, + color: Theme.of(context).colorScheme.error, + ), + ), ); } } @@ -202,20 +202,21 @@ class _PhotoAlbumViewState extends State { var tl = (timeline! as MatrixPhotoAlbumTimeline).matrixTimeline; showModalBottomSheet( - showDragHandle: true, - isScrollControlled: true, - elevation: 0, - context: context, - builder: (context) => TimelineEventMenuDialog( - event: event, - timeline: tl, - menu: TimelineEventMenu( - timeline: tl, - event: event, - context: context, - onActionFinished: () => Navigator.of(context).pop(), - ), - )); + showDragHandle: true, + isScrollControlled: true, + elevation: 0, + context: context, + builder: (context) => TimelineEventMenuDialog( + event: event, + timeline: tl, + menu: TimelineEventMenu( + timeline: tl, + event: event, + context: context, + onActionFinished: () => Navigator.of(context).pop(), + ), + ), + ); } }; @@ -224,10 +225,7 @@ class _PhotoAlbumViewState extends State { key: ValueKey("photo-album-image:${item.id}"), fit: StackFit.expand, children: [ - Image( - fit: BoxFit.cover, - image: attachment.image, - ), + Image(fit: BoxFit.cover, image: attachment.image), Material( color: Colors.transparent, child: InkWell( @@ -236,7 +234,7 @@ class _PhotoAlbumViewState extends State { }, onLongPress: callback, ), - ) + ), ], ); } @@ -246,18 +244,16 @@ class _PhotoAlbumViewState extends State { key: ValueKey("photo-album-video:${item.id}"), fit: StackFit.expand, children: [ - Image( - fit: BoxFit.cover, - image: attachment.thumbnail!, - ), + Image(fit: BoxFit.cover, image: attachment.thumbnail!), Align( alignment: Alignment.bottomRight, child: Padding( padding: const EdgeInsets.all(4.0), child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: scheme.secondaryContainer), + borderRadius: BorderRadius.circular(4), + color: scheme.secondaryContainer, + ), child: Padding( padding: const EdgeInsets.all(4.0), child: Row( @@ -285,10 +281,12 @@ class _PhotoAlbumViewState extends State { child: InkWell( onLongPress: callback, onTap: () { - Lightbox.show(context, - video: attachment.file, - aspectRatio: attachment.aspectRatio, - thumbnail: attachment.thumbnail); + Lightbox.show( + context, + video: attachment.file, + aspectRatio: attachment.aspectRatio, + thumbnail: attachment.thumbnail, + ); }, ), ), @@ -299,17 +297,21 @@ class _PhotoAlbumViewState extends State { if (result != null) { if (widget.component is MatrixPhotoAlbumRoomComponent) { var menu = TimelineEventMenu( - context: context, - timeline: (timeline! as MatrixPhotoAlbumTimeline).matrixTimeline, - event: (item as MatrixPhoto).event); + context: context, + timeline: (timeline! as MatrixPhotoAlbumTimeline).matrixTimeline, + event: (item as MatrixPhoto).event, + ); if (MediaQuery.of(context).desktop) { result = tiamat.ContextMenu( items: (menu.primaryActions + menu.secondaryActions) - .map((e) => tiamat.ContextMenuItem( + .map( + (e) => tiamat.ContextMenuItem( text: e.name, icon: e.icon, - onPressed: () => e.action?.call(context))) + onPressed: () => e.action?.call(context), + ), + ) .toList(), child: result, ); @@ -331,16 +333,18 @@ class _PhotoAlbumViewState extends State { late List photos; if (PlatformUtils.isAndroid) { - final usePhotoPicker = await AdaptiveDialog.pickOne(context, - items: [true, false], - itemBuilder: (context, item, onTapped) => SizedBox( - height: 50, - child: tiamat.TextButton( - item ? "Photos" : "Browse Files", - icon: item ? Icons.add_to_photos : Icons.file_open, - onTap: onTapped, - ), - )); + final usePhotoPicker = await AdaptiveDialog.pickOne( + context, + items: [true, false], + itemBuilder: (context, item, onTapped) => SizedBox( + height: 50, + child: tiamat.TextButton( + item ? "Photos" : "Browse Files", + icon: item ? Icons.add_to_photos : Icons.file_open, + onTap: onTapped, + ), + ), + ); if (usePhotoPicker == null) { return; } @@ -355,48 +359,64 @@ class _PhotoAlbumViewState extends State { } photos = files - .map((f) => PickedPhoto( + .map( + (f) => PickedPhoto( name: f.name, filepath: f.path, getBytes: () { return f.readAsBytes(); - })) + }, + ), + ) .toList(); } else { - var files = await FilePicker.platform - .pickFiles(allowMultiple: true, withReadStream: true); + var files = await FilePicker.platform.pickFiles( + allowMultiple: true, + withReadStream: true, + ); if (files == null) return; photos = files.files - .map((e) => PickedPhoto( - filepath: e.path, - name: e.name, - getBytes: () async { - var result = List.empty(growable: true); - await for (final data in e.readStream!) { - print("Read ${data.length} bytes from file"); - result.addAll(data); - } - - print("Read all ${result.length} bytes"); - - return Uint8List.fromList(result); - }, - )) + .map( + (e) => PickedPhoto( + filepath: e.path, + name: e.name, + getBytes: () async { + var result = List.empty(growable: true); + await for (final data in e.readStream!) { + print("Read ${data.length} bytes from file"); + result.addAll(data); + } + + print("Read all ${result.length} bytes"); + + return Uint8List.fromList(result); + }, + ), + ) .toList(); } - AdaptiveDialog.show(context, - builder: (_) => PhotosAlbumUploadView(photos, widget.component)); + AdaptiveDialog.show( + context, + builder: (_) => PhotosAlbumUploadView(photos, widget.component), + ); } void onFileDropped(DropDoneDetails event) { var f = event.files - .map((e) => PickedPhoto( - filepath: e.path, name: e.name, getBytes: () => e.readAsBytes())) + .map( + (e) => PickedPhoto( + filepath: e.path, + name: e.name, + getBytes: () => e.readAsBytes(), + ), + ) .toList(); - AdaptiveDialog.show(context, - builder: (_) => PhotosAlbumUploadView(f, widget.component)); + AdaptiveDialog.show( + context, + builder: (_) => PhotosAlbumUploadView(f, widget.component), + ); } void onChanged(Photo event) { diff --git a/commet/lib/ui/organisms/photo_albums/photos_upload_view.dart b/commet/lib/ui/organisms/photo_albums/photos_upload_view.dart index 88d282ecc..9efd8cd67 100644 --- a/commet/lib/ui/organisms/photo_albums/photos_upload_view.dart +++ b/commet/lib/ui/organisms/photo_albums/photos_upload_view.dart @@ -29,34 +29,36 @@ class _PhotosAlbumUploadViewState extends State { height: 300, width: 500, child: MasonryGridView.extent( - maxCrossAxisExtent: 100, - mainAxisSpacing: 8, - crossAxisSpacing: 8, - itemCount: widget.photos.length, - itemBuilder: (context, i) { - return Column( - children: [ - if (widget.photos[i].filepath != null) - Padding( - padding: const EdgeInsets.fromLTRB(2, 2, 8, 2), - child: ClipRRect( - child: SizedBox( - width: 64, - height: 64, - child: ClipRRect( - borderRadius: - BorderRadiusGeometry.circular(8), - child: buildFilePreview(i))), + maxCrossAxisExtent: 100, + mainAxisSpacing: 8, + crossAxisSpacing: 8, + itemCount: widget.photos.length, + itemBuilder: (context, i) { + return Column( + children: [ + if (widget.photos[i].filepath != null) + Padding( + padding: const EdgeInsets.fromLTRB(2, 2, 8, 2), + child: ClipRRect( + child: SizedBox( + width: 64, + height: 64, + child: ClipRRect( + borderRadius: BorderRadiusGeometry.circular(8), + child: buildFilePreview(i), + ), ), ), - tiamat.Text.tiny( - widget.photos[i].name, - maxLines: 1, - overflow: TextOverflow.ellipsis, ), - ], - ); - }), + tiamat.Text.tiny( + widget.photos[i].name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ); + }, + ), ), if (sendOriginal) SizedBox( @@ -76,17 +78,20 @@ class _PhotosAlbumUploadViewState extends State { onChanged: (val) => setState(() { sendOriginal = val; }), - ) + ), ], ), tiamat.Button( text: "Upload Files", onTap: () { - widget.component.uploadPhotos(widget.photos, - sendOriginal: sendOriginal, extractMetadata: true); + widget.component.uploadPhotos( + widget.photos, + sendOriginal: sendOriginal, + extractMetadata: true, + ); Navigator.of(context).pop(); }, - ) + ), ], ), ); diff --git a/commet/lib/ui/organisms/room_event_search/room_event_search_widget.dart b/commet/lib/ui/organisms/room_event_search/room_event_search_widget.dart index 1ea6de2be..2397f04b7 100644 --- a/commet/lib/ui/organisms/room_event_search/room_event_search_widget.dart +++ b/commet/lib/ui/organisms/room_event_search/room_event_search_widget.dart @@ -11,8 +11,12 @@ import 'package:implicitly_animated_list/implicitly_animated_list.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class RoomEventSearchWidget extends StatefulWidget { - const RoomEventSearchWidget( - {required this.room, this.close, this.onEventClicked, super.key}); + const RoomEventSearchWidget({ + required this.room, + this.close, + this.onEventClicked, + super.key, + }); final Room room; final void Function()? close; final void Function(String eventId)? onEventClicked; @@ -61,11 +65,10 @@ class _RoomEventSearchWidgetState extends State { style: Theme.of(context).textTheme.bodyMedium!, controller: controller, decoration: InputDecoration( - hintText: CommonStrings.promptSearch, - prefix: const SizedBox( - width: 10, - ), - contentPadding: const EdgeInsets.fromLTRB(8, 0, 8, 0)), + hintText: CommonStrings.promptSearch, + prefix: const SizedBox(width: 10), + contentPadding: const EdgeInsets.fromLTRB(8, 0, 8, 0), + ), ), ), ), @@ -76,7 +79,7 @@ class _RoomEventSearchWidgetState extends State { size: 20, onPressed: widget.close, ), - ) + ), ], ), ), @@ -93,20 +96,21 @@ class _RoomEventSearchWidgetState extends State { child: ClipRRect( borderRadius: BorderRadius.circular(8), child: Material( - color: color, - borderRadius: BorderRadius.circular(8), - child: InkWell( - onTap: () => - widget.onEventClicked?.call(data.eventId), - child: Padding( - padding: const EdgeInsets.all(4.0), - child: TimelineEventViewSingle( - room: widget.room, - event: data, - key: ValueKey("search-result_${data.eventId}"), - ), + color: color, + borderRadius: BorderRadius.circular(8), + child: InkWell( + onTap: () => + widget.onEventClicked?.call(data.eventId), + child: Padding( + padding: const EdgeInsets.all(4.0), + child: TimelineEventViewSingle( + room: widget.room, + event: data, + key: ValueKey("search-result_${data.eventId}"), ), - )), + ), + ), + ), ), ); }, @@ -117,7 +121,8 @@ class _RoomEventSearchWidgetState extends State { searchSession != null && loading == false) Flexible( - child: Center(child: tiamat.Text.labelLow("No results found"))), + child: Center(child: tiamat.Text.labelLow("No results found")), + ), if (loading || (currentResults?.isNotEmpty == true && searchSession?.canContinueSearch == true)) @@ -126,35 +131,34 @@ class _RoomEventSearchWidgetState extends State { child: loading ? Center( child: const SizedBox( - width: 15, - height: 15, - child: CircularProgressIndicator( - strokeWidth: 2, - ))) + width: 15, + height: 15, + child: CircularProgressIndicator(strokeWidth: 2), + ), + ) : currentResults?.isNotEmpty == true - ? Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 8, 4), - child: tiamat.TextButton( - "Next", - icon: Icons.search, - highlighted: true, - highlightColor: - ColorScheme.of(context).surfaceContainerLow, - onTap: () { - var stream = searchSession?.continueSearch(); - - currentSubscription?.cancel(); - currentSubscription = - stream!.listen(onResultsChanged); - - setState(() { - loading = true; - }); - }, - ), - ) - : Container(), - ) + ? Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 8, 4), + child: tiamat.TextButton( + "Next", + icon: Icons.search, + highlighted: true, + highlightColor: ColorScheme.of(context) + .surfaceContainerLow, + onTap: () { + var stream = searchSession?.continueSearch(); + + currentSubscription?.cancel(); + currentSubscription = stream!.listen(onResultsChanged); + + setState(() { + loading = true; + }); + }, + ), + ) + : Container(), + ), ], ); } diff --git a/commet/lib/ui/organisms/room_members_list/room_members_list.dart b/commet/lib/ui/organisms/room_members_list/room_members_list.dart index ee1ae00ad..114b58fdb 100644 --- a/commet/lib/ui/organisms/room_members_list/room_members_list.dart +++ b/commet/lib/ui/organisms/room_members_list/room_members_list.dart @@ -17,7 +17,8 @@ class _RoomMembersListWidgetState extends State { late bool isDirectMessage; @override void initState() { - isDirectMessage = widget.room.client + isDirectMessage = + widget.room.client .getComponent() ?.isRoomDirectMessage(widget.room) ?? false; @@ -34,13 +35,13 @@ class _RoomMembersListWidgetState extends State { child: SizedBox( width: MediaQuery.of(context).desktop ? isDirectMessage - ? 300 - : 200 + ? 300 + : 200 : null, child: RoomMemberList( - key: ValueKey( - "room-participant-list-key-${widget.room.localId}"), - widget.room), + key: ValueKey("room-participant-list-key-${widget.room.localId}"), + widget.room, + ), ), ), ], diff --git a/commet/lib/ui/organisms/room_pinned_messages/room_pinned_messages_widget.dart b/commet/lib/ui/organisms/room_pinned_messages/room_pinned_messages_widget.dart index 5d8507f7d..10ee1ee60 100644 --- a/commet/lib/ui/organisms/room_pinned_messages/room_pinned_messages_widget.dart +++ b/commet/lib/ui/organisms/room_pinned_messages/room_pinned_messages_widget.dart @@ -7,8 +7,11 @@ import 'package:intl/intl.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class RoomPinnedMessagesWidget extends StatefulWidget { - const RoomPinnedMessagesWidget( - {required this.room, this.onEventClicked, super.key}); + const RoomPinnedMessagesWidget({ + required this.room, + this.onEventClicked, + super.key, + }); final Room room; final void Function(String eventId)? onEventClicked; @@ -20,10 +23,11 @@ class RoomPinnedMessagesWidget extends StatefulWidget { class _RoomPinnedMessagesWidgetState extends State { List? events; - String get noPinnedMessages => Intl.message("No messages have been pinned!", - desc: - "Placeholder label in the pinned messages menu that is shown when there are no pinned messages", - name: "noPinnedMessages"); + String get noPinnedMessages => Intl.message( + "No messages have been pinned!", + desc: "Placeholder label in the pinned messages menu that is shown when there are no pinned messages", + name: "noPinnedMessages", + ); @override void initState() { @@ -36,12 +40,14 @@ class _RoomPinnedMessagesWidgetState extends State { Widget build(BuildContext context) { if (events == null) { return const tiamat.Tile( - child: Center(child: CircularProgressIndicator())); + child: Center(child: CircularProgressIndicator()), + ); } if (events!.isEmpty) { return tiamat.Tile( - child: Center(child: tiamat.Text.label(noPinnedMessages))); + child: Center(child: tiamat.Text.label(noPinnedMessages)), + ); } return tiamat.Tile.low( @@ -58,16 +64,18 @@ class _RoomPinnedMessagesWidgetState extends State { child: ClipRRect( borderRadius: BorderRadius.circular(8), child: Material( - borderRadius: BorderRadius.circular(8), - child: InkWell( - onTap: () => - widget.onEventClicked?.call(data.eventId), - child: Padding( - padding: const EdgeInsets.all(4.0), - child: TimelineEventViewSingle( - room: widget.room, event: data), + borderRadius: BorderRadius.circular(8), + child: InkWell( + onTap: () => widget.onEventClicked?.call(data.eventId), + child: Padding( + padding: const EdgeInsets.all(4.0), + child: TimelineEventViewSingle( + room: widget.room, + event: data, ), - )), + ), + ), + ), ), ); }, @@ -83,7 +91,8 @@ class _RoomPinnedMessagesWidgetState extends State { var eventIds = comp.getPinnedMessages(); var allEvents = await Future.wait( - eventIds.map((id) => widget.room.getEvent(id))); + eventIds.map((id) => widget.room.getEvent(id)), + ); setState(() { events = List.from(allEvents.where((e) => e != null)); diff --git a/commet/lib/ui/organisms/room_quick_access_menu/room_quick_access_menu.dart b/commet/lib/ui/organisms/room_quick_access_menu/room_quick_access_menu.dart index aa7b581bc..0d3b8ada9 100644 --- a/commet/lib/ui/organisms/room_quick_access_menu/room_quick_access_menu.dart +++ b/commet/lib/ui/organisms/room_quick_access_menu/room_quick_access_menu.dart @@ -39,59 +39,68 @@ class RoomQuickAccessMenu { // Dont show widgets in Voip room. If the widget uses MatrixRTC, // it seems to interfere with the ongoing call... - final bool hasWidgets = isVoipRoom == false && + final bool hasWidgets = + isVoipRoom == false && room.client.getComponent() != null; actions = [ if (invitation != null) RoomQuickAccessMenuEntry( - name: "Invite", - action: (context) => AdaptiveDialog.show(context, - builder: (context) => SendInvitationWidget( - room.client, - invitation, - roomId: room.identifier, - displayName: room.displayName, - existingMembers: room.memberIds, - ), - title: "Invite"), - icon: Icons.person_add), + name: "Invite", + action: (context) => AdaptiveDialog.show( + context, + builder: (context) => SendInvitationWidget( + room.client, + invitation, + roomId: room.identifier, + displayName: room.displayName, + existingMembers: room.memberIds, + ), + title: "Invite", + ), + icon: Icons.person_add, + ), if (canCall) RoomQuickAccessMenuEntry( - name: "Call", - action: (context) => - calls.startCall(room.identifier, CallType.voice), - icon: Icons.call), + name: "Call", + action: (context) => calls.startCall(room.identifier, CallType.voice), + icon: Icons.call, + ), if (preferences.hideRoomSidePanel.value == false || MediaQuery.of(context).mobile) ...[ if (calendar?.hasCalendar == true && calendar?.isCalendarRoom == false) RoomQuickAccessMenuEntry( - name: "Calendar", - action: (context) => EventBus.openCalendar.add(null), - icon: Icons.calendar_month), + name: "Calendar", + action: (context) => EventBus.openCalendar.add(null), + icon: Icons.calendar_month, + ), if (supportsPinnedMessages) RoomQuickAccessMenuEntry( - name: "Pinned Messages", - action: (context) => EventBus.openPinnedMessages.add(null), - icon: Icons.push_pin), + name: "Pinned Messages", + action: (context) => EventBus.openPinnedMessages.add(null), + icon: Icons.push_pin, + ), if (canSearch) RoomQuickAccessMenuEntry( - name: CommonStrings.promptSearch, - action: (context) => EventBus.startSearch.add(null), - icon: Icons.search), + name: CommonStrings.promptSearch, + action: (context) => EventBus.startSearch.add(null), + icon: Icons.search, + ), if (hasWidgets && !PlatformUtils.isWeb) RoomQuickAccessMenuEntry( - name: "Widgets", - action: (context) => EventBus.openWidgets.add(null), - icon: Icons.widgets), + name: "Widgets", + action: (context) => EventBus.openWidgets.add(null), + icon: Icons.widgets, + ), ], if (MediaQuery.of(context).desktop) RoomQuickAccessMenuEntry( - name: "Toggle Panel", - action: (context) => EventBus.toggleRoomSidePanel.add(null), - icon: preferences.hideRoomSidePanel.value - ? Icons.chevron_left - : Icons.chevron_right), + name: "Toggle Panel", + action: (context) => EventBus.toggleRoomSidePanel.add(null), + icon: preferences.hideRoomSidePanel.value + ? Icons.chevron_left + : Icons.chevron_right, + ), ]; } } @@ -101,6 +110,9 @@ class RoomQuickAccessMenuEntry { final Function(BuildContext context)? action; final IconData icon; - RoomQuickAccessMenuEntry( - {required this.name, required this.action, required this.icon}); + RoomQuickAccessMenuEntry({ + required this.name, + required this.action, + required this.icon, + }); } diff --git a/commet/lib/ui/organisms/room_quick_access_menu/room_quick_access_menu_desktop.dart b/commet/lib/ui/organisms/room_quick_access_menu/room_quick_access_menu_desktop.dart index d3109ca67..39a4b93b6 100644 --- a/commet/lib/ui/organisms/room_quick_access_menu/room_quick_access_menu_desktop.dart +++ b/commet/lib/ui/organisms/room_quick_access_menu/room_quick_access_menu_desktop.dart @@ -34,14 +34,17 @@ class _RoomQuickAccessMenuViewDesktopState spacing: 4, mainAxisSize: MainAxisSize.min, children: menu.actions - .map((e) => SizedBox( + .map( + (e) => SizedBox( width: 40, height: 40, child: tiamat.IconButton( key: ValueKey("room-quick-access-menu-action-${e.name}"), icon: e.icon, onPressed: () => e.action?.call(context), - ))) + ), + ), + ) .toList(), ); } diff --git a/commet/lib/ui/organisms/room_quick_access_menu/room_quick_access_menu_mobile.dart b/commet/lib/ui/organisms/room_quick_access_menu/room_quick_access_menu_mobile.dart index 38689cb0b..9e2b60e97 100644 --- a/commet/lib/ui/organisms/room_quick_access_menu/room_quick_access_menu_mobile.dart +++ b/commet/lib/ui/organisms/room_quick_access_menu/room_quick_access_menu_mobile.dart @@ -18,15 +18,18 @@ class RoomQuickAccessMenuViewMobile extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.end, children: menu.actions - .map((e) => AspectRatio( - aspectRatio: 1, - child: SizedBox( - child: tiamat.IconButton( + .map( + (e) => AspectRatio( + aspectRatio: 1, + child: SizedBox( + child: tiamat.IconButton( icon: e.icon, size: 20, onPressed: () => e.action?.call(context), - )), - )) + ), + ), + ), + ) .toList(), ), ), diff --git a/commet/lib/ui/organisms/room_side_panel/room_side_panel.dart b/commet/lib/ui/organisms/room_side_panel/room_side_panel.dart index 9546aef6f..5108138d7 100644 --- a/commet/lib/ui/organisms/room_side_panel/room_side_panel.dart +++ b/commet/lib/ui/organisms/room_side_panel/room_side_panel.dart @@ -24,7 +24,7 @@ enum SidePanelState { pinnedMessages, calendar, widgets, - nothing + nothing, } class RoomSidePanel extends StatefulWidget { @@ -77,10 +77,7 @@ class _RoomSidePanelState extends State { Widget build(BuildContext context) { Widget result = buildPanelContent(context); - result = Material( - color: Colors.transparent, - child: result, - ); + result = Material(color: Colors.transparent, child: result); if (widget.builder != null) { result = widget.builder!.call(state, result); @@ -111,9 +108,7 @@ class _RoomSidePanelState extends State { case SidePanelState.calendar: return buildCalendar(); case SidePanelState.nothing: - return SizedBox( - width: 0, - ); + return SizedBox(width: 0); case SidePanelState.widgets: return buildWidgets(); } @@ -146,7 +141,8 @@ class _RoomSidePanelState extends State { RoomQuickAccessMenuViewMobile( room: widget.state.currentRoom!, key: ValueKey( - "quick_access_menu_${widget.state.currentRoom!.localId}"), + "quick_access_menu_${widget.state.currentRoom!.localId}", + ), ), Flexible( child: Padding( @@ -173,7 +169,8 @@ class _RoomSidePanelState extends State { widget.state.currentRoom!, threadId: currentThreadId, key: ValueKey( - "room-timeline-key-${widget.state.currentRoom!.localId}_thread_$currentThreadId"), + "room-timeline-key-${widget.state.currentRoom!.localId}_thread_$currentThreadId", + ), ), Align( alignment: Alignment.topRight, @@ -196,17 +193,18 @@ class _RoomSidePanelState extends State { Widget buildSearch() { return SizedBox( - width: MediaQuery.of(context).desktop ? 300 : null, - child: RoomEventSearchWidget( - room: widget.state.currentRoom!, - onEventClicked: (eventId) { - EventBus.jumpToEvent.add(eventId); - EventBus.focusTimeline.add(null); - }, - close: () => setState(() { - state = SidePanelState.defaultView; - }), - )); + width: MediaQuery.of(context).desktop ? 300 : null, + child: RoomEventSearchWidget( + room: widget.state.currentRoom!, + onEventClicked: (eventId) { + EventBus.jumpToEvent.add(eventId); + EventBus.focusTimeline.add(null); + }, + close: () => setState(() { + state = SidePanelState.defaultView; + }), + ), + ); } void onStartSearch(void event) { @@ -241,26 +239,28 @@ class _RoomSidePanelState extends State { Widget buildPinnedMessages() { return SizedBox( - width: MediaQuery.of(context).desktop ? 300 : null, - child: Column( - children: [ - if (MediaQuery.of(context).mobile) - RoomQuickAccessMenuViewMobile( - room: widget.state.currentRoom!, - key: ValueKey( - "quick_access_menu_${widget.state.currentRoom!.localId}"), - ), - Expanded( - child: RoomPinnedMessagesWidget( - room: widget.state.currentRoom!, - onEventClicked: (eventId) { - EventBus.jumpToEvent.add(eventId); - EventBus.focusTimeline.add(null); - }, + width: MediaQuery.of(context).desktop ? 300 : null, + child: Column( + children: [ + if (MediaQuery.of(context).mobile) + RoomQuickAccessMenuViewMobile( + room: widget.state.currentRoom!, + key: ValueKey( + "quick_access_menu_${widget.state.currentRoom!.localId}", ), ), - ], - )); + Expanded( + child: RoomPinnedMessagesWidget( + room: widget.state.currentRoom!, + onEventClicked: (eventId) { + EventBus.jumpToEvent.add(eventId); + EventBus.focusTimeline.add(null); + }, + ), + ), + ], + ), + ); } Widget buildCalendar() { @@ -278,35 +278,40 @@ class _RoomSidePanelState extends State { RoomQuickAccessMenuViewMobile( room: widget.state.currentRoom!, key: ValueKey( - "quick_access_menu_${widget.state.currentRoom!.localId}"), - ), - if (MediaQuery.of(context).mobile) - Divider( - height: 2, + "quick_access_menu_${widget.state.currentRoom!.localId}", + ), ), - Expanded(child: LayoutBuilder(builder: (context, constraints) { - var newQuery = query.copyWith( - size: Size(constraints.maxWidth, constraints.maxHeight), - ); - - return Container( - color: Theme.of(context).colorScheme.surface, - child: ScaledSafeArea( - top: false, - bottom: true, - child: SizedBox( - width: constraints.maxWidth, - height: constraints.maxHeight, - child: MediaQuery( + if (MediaQuery.of(context).mobile) Divider(height: 2), + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + var newQuery = query.copyWith( + size: Size(constraints.maxWidth, constraints.maxHeight), + ); + + return Container( + color: Theme.of(context).colorScheme.surface, + child: ScaledSafeArea( + top: false, + bottom: true, + child: SizedBox( + width: constraints.maxWidth, + height: constraints.maxHeight, + child: MediaQuery( data: newQuery, child: CalendarWidgetView( - calendar: calendar!.calendar!, - watermark: false, - useMobileLayout: MediaQuery.of(context).mobile, - autoDisposeCalendar: false))), - ), - ); - })), + calendar: calendar!.calendar!, + watermark: false, + useMobileLayout: MediaQuery.of(context).mobile, + autoDisposeCalendar: false, + ), + ), + ), + ), + ); + }, + ), + ), ], ), ); @@ -314,18 +319,20 @@ class _RoomSidePanelState extends State { Widget buildWidgets() { return SizedBox( - width: MediaQuery.of(context).desktop ? 250 : null, - child: Column( - children: [ - if (MediaQuery.of(context).mobile) - RoomQuickAccessMenuViewMobile( - room: widget.state.currentRoom!, - key: ValueKey( - "quick_access_menu_${widget.state.currentRoom!.localId}"), + width: MediaQuery.of(context).desktop ? 250 : null, + child: Column( + children: [ + if (MediaQuery.of(context).mobile) + RoomQuickAccessMenuViewMobile( + room: widget.state.currentRoom!, + key: ValueKey( + "quick_access_menu_${widget.state.currentRoom!.localId}", ), - Expanded(child: RoomWidgetsView(widget.state.currentRoom!)), - ], - )); + ), + Expanded(child: RoomWidgetsView(widget.state.currentRoom!)), + ], + ), + ); } void onToggleSidePanel(void event) { diff --git a/commet/lib/ui/organisms/room_widgets/room_widgets_view.dart b/commet/lib/ui/organisms/room_widgets/room_widgets_view.dart index 8e3dee258..f170b6e23 100644 --- a/commet/lib/ui/organisms/room_widgets/room_widgets_view.dart +++ b/commet/lib/ui/organisms/room_widgets/room_widgets_view.dart @@ -91,7 +91,8 @@ class _RoomWidgetsViewState extends State { Padding( padding: const EdgeInsets.all(8.0), child: tiamat.Text.labelLow( - "No widgets have been added to this room"), + "No widgets have been added to this room", + ), ), Flexible( child: ListView.builder( @@ -113,8 +114,11 @@ class _RoomWidgetsViewState extends State { icon: hostTypeToIcon(i), onPressed: () { WidgetComponent.runWidget( - widget.room, context, data, - type: i); + widget.room, + context, + data, + type: i, + ); }, ), tiamat.ContextMenuItem( @@ -123,8 +127,9 @@ class _RoomWidgetsViewState extends State { color: ColorScheme.of(context).error, onPressed: () { preferences.clearWidgetSettings( - widget.room.client.identifier, - data.namespace); + widget.room.client.identifier, + data.namespace, + ); }, ), tiamat.ContextMenuItem( @@ -132,17 +137,21 @@ class _RoomWidgetsViewState extends State { icon: Icons.delete_forever, color: ColorScheme.of(context).error, onPressed: () async { - if (await AdaptiveDialog.confirmation(context, - prompt: - "Are you sure you want to remove the widget '${data.name}' from '${widget.room.displayName}'?") == + if (await AdaptiveDialog.confirmation( + context, + prompt: + "Are you sure you want to remove the widget '${data.name}' from '${widget.room.displayName}'?", + ) == true) { var comp = widget.room.client .getComponent(); comp?.removeWidget( - widget: data, room: widget.room); + widget: data, + room: widget.room, + ); } }, - ) + ), ], child: tiamat.TextButton( data.name, @@ -150,7 +159,10 @@ class _RoomWidgetsViewState extends State { avatar: data.icon.image, onTap: () async { WidgetComponent.runWidget( - widget.room, context, data); + widget.room, + context, + data, + ); }, ), ), @@ -163,17 +175,18 @@ class _RoomWidgetsViewState extends State { Padding( padding: const EdgeInsets.all(4.0), child: SizedBox( - height: 50, - child: tiamat.TextButton( - "Browse Widgets", - icon: Icons.open_in_browser, - onTap: () { - LinkUtils.open( - Uri.parse("https://commet.chat/widgets"), - context: context, - ); - }, - )), + height: 50, + child: tiamat.TextButton( + "Browse Widgets", + icon: Icons.open_in_browser, + onTap: () { + LinkUtils.open( + Uri.parse("https://commet.chat/widgets"), + context: context, + ); + }, + ), + ), ), ], ), diff --git a/commet/lib/ui/organisms/side_navigation_bar/side_navigation_bar.dart b/commet/lib/ui/organisms/side_navigation_bar/side_navigation_bar.dart index c20f79a2b..0a82494af 100644 --- a/commet/lib/ui/organisms/side_navigation_bar/side_navigation_bar.dart +++ b/commet/lib/ui/organisms/side_navigation_bar/side_navigation_bar.dart @@ -22,19 +22,21 @@ import 'package:tiamat/tiamat.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class SideNavigationBar extends StatefulWidget { - const SideNavigationBar( - {super.key, - this.currentUser, - this.onSpaceSelected, - this.onDirectMessageSelected, - this.onSettingsSelected, - this.onHomeSelected, - this.extraEntryBuilders, - this.onRoomsViewSelected, - this.clearSpaceSelection}); - - static ValueKey settingsKey = - const ValueKey("SIDE_NAVIGATION_SETTINGS_BUTTON"); + const SideNavigationBar({ + super.key, + this.currentUser, + this.onSpaceSelected, + this.onDirectMessageSelected, + this.onSettingsSelected, + this.onHomeSelected, + this.extraEntryBuilders, + this.onRoomsViewSelected, + this.clearSpaceSelection, + }); + + static ValueKey settingsKey = const ValueKey( + "SIDE_NAVIGATION_SETTINGS_BUTTON", + ); final List? extraEntryBuilders; @@ -51,25 +53,23 @@ class SideNavigationBar extends StatefulWidget { static Widget tooltip(String text, Widget child, BuildContext context) { if (MediaQuery.of(context).mobile) { - return AspectRatio( - aspectRatio: 1.0, - child: child, - ); + return AspectRatio(aspectRatio: 1.0, child: child); } return AspectRatio( aspectRatio: 1, child: JustTheTooltip( - content: Padding( - padding: const EdgeInsets.all(8.0), - child: tiamat.Text(text), - ), - preferredDirection: AxisDirection.right, - offset: 5, - tailLength: 5, - tailBaseWidth: 5, - backgroundColor: Theme.of(context).colorScheme.surfaceContainerLowest, - child: child), + content: Padding( + padding: const EdgeInsets.all(8.0), + child: tiamat.Text(text), + ), + preferredDirection: AxisDirection.right, + offset: 5, + tailLength: 5, + tailBaseWidth: 5, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLowest, + child: child, + ), ); } } @@ -79,8 +79,11 @@ class _SideNavigationBarState extends State { late List subs; - String get promptAddSpace => Intl.message("Add Space", - name: "promptAddSpace", desc: "Prompt to add a new space"); + String get promptAddSpace => Intl.message( + "Add Space", + name: "promptAddSpace", + desc: "Prompt to add a new space", + ); late List items; @@ -109,16 +112,21 @@ class _SideNavigationBarState extends State { _clientManager.onSpaceRemoved.listen((_) => onSpaceUpdate()), _clientManager.onSpaceAdded.listen((_) => onSpaceUpdate()), _clientManager.onClientRemoved.stream.listen((_) => onSpaceUpdate()), - _clientManager.onDirectMessageRoomUpdated.stream - .listen(onDirectMessageUpdated), - _clientManager.onRoomUpdated.stream.listen((_) => setState(() { - updateNotificationCounts(); - })), + _clientManager.onDirectMessageRoomUpdated.stream.listen( + onDirectMessageUpdated, + ), + _clientManager.onRoomUpdated.stream.listen( + (_) => setState(() { + updateNotificationCounts(); + }), + ), EventBus.setFilterClient.stream.listen(setFilterClient), SidebarEntriesComponent.onOrderChanged.listen((_) => onSpaceUpdate()), - preferences.showRoomsInSidebar.onChanged.listen((_) => setState(() { - updateNotificationCounts(); - })), + preferences.showRoomsInSidebar.onChanged.listen( + (_) => setState(() { + updateNotificationCounts(); + }), + ), ]; getSpaces(); @@ -137,8 +145,9 @@ class _SideNavigationBarState extends State { void getSpaces() { if (filterClient != null) { - var entries = - filterClient!.getComponent()!.getEntries(); + var entries = filterClient! + .getComponent()! + .getEntries(); items = entries; } else { @@ -169,9 +178,7 @@ class _SideNavigationBarState extends State { items = finalEntries; } - items.sort( - (a, b) => a.order.compareTo(b.order), - ); + items.sort((a, b) => a.order.compareTo(b.order)); } void onSpaceUpdate() { @@ -195,107 +202,113 @@ class _SideNavigationBarState extends State { @override Widget build(BuildContext context) { return SizedBox( - width: 70.0, - child: Column( - children: [ - Expanded( - child: SpaceSelector( - items, - width: 70, - clearSelection: widget.clearSpaceSelection, - shouldShowAvatarForSpace: shouldShowAvatarForSpace, - header: Column( - children: [ - SideNavigationBar.tooltip( - CommonStrings.promptHome, - Stack( - children: [ - ImageButton( - size: 70, - icon: Icons.home, - onTap: () { - widget.onHomeSelected?.call(); - }, - ), - ], + width: 70.0, + child: Column( + children: [ + Expanded( + child: SpaceSelector( + items, + width: 70, + clearSelection: widget.clearSpaceSelection, + shouldShowAvatarForSpace: shouldShowAvatarForSpace, + header: Column( + children: [ + SideNavigationBar.tooltip( + CommonStrings.promptHome, + Stack( + children: [ + ImageButton( + size: 70, + icon: Icons.home, + onTap: () { + widget.onHomeSelected?.call(); + }, ), - context), - if (preferences.showRoomsInSidebar.value) ...[ - SizedBox( - height: 4, - ), - SideNavigationBar.tooltip( - HomeScreenView.labelHomeRoomsList, - Stack( - children: [ - ImageButton( - size: 70, - icon: Icons.tag, - onTap: () { - widget.onRoomsViewSelected?.call(); - }, - ), - if (notificationCount > 0) - Align( - alignment: AlignmentGeometry.xy(-1.55, 0), - child: DotIndicator()), - if (highlightedNotificationCount > 0) - Align( - alignment: AlignmentGeometry.topRight, - child: NotificationBadge( - highlightedNotificationCount), - ) - ], - ), - context), - ], - SideNavigationBarDirectMessages( - _clientManager.directMessages, - onRoomTapped: widget.onDirectMessageSelected, + ], ), - ], - ), - footer: Column( - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(0, 2, 0, 4), - child: SideNavigationBar.tooltip( - promptAddSpace, + context, + ), + if (preferences.showRoomsInSidebar.value) ...[ + SizedBox(height: 4), + SideNavigationBar.tooltip( + HomeScreenView.labelHomeRoomsList, + Stack( + children: [ ImageButton( size: 70, - icon: Icons.add, + icon: Icons.tag, onTap: () { - GetOrCreateRoom.show(null, context, - pickExisting: false, createSpace: true); + widget.onRoomsViewSelected?.call(); }, ), - context), + if (notificationCount > 0) + Align( + alignment: AlignmentGeometry.xy(-1.55, 0), + child: DotIndicator(), + ), + if (highlightedNotificationCount > 0) + Align( + alignment: AlignmentGeometry.topRight, + child: NotificationBadge( + highlightedNotificationCount, + ), + ), + ], + ), + context, ), - SizedBox( - height: MediaQuery.sizeOf(context).height / 2, - ) ], - ), - onSelected: (space) { - widget.onSpaceSelected?.call(space); - }, + SideNavigationBarDirectMessages( + _clientManager.directMessages, + onRoomTapped: widget.onDirectMessageSelected, + ), + ], ), - ), - if (widget.extraEntryBuilders != null) - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.start, - children: - widget.extraEntryBuilders!.map((e) => e(70.0)).toList(), + footer: Column( + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(0, 2, 0, 4), + child: SideNavigationBar.tooltip( + promptAddSpace, + ImageButton( + size: 70, + icon: Icons.add, + onTap: () { + GetOrCreateRoom.show( + null, + context, + pickExisting: false, + createSpace: true, + ); + }, + ), + context, + ), + ), + SizedBox(height: MediaQuery.sizeOf(context).height / 2), + ], ), - ], - )); + onSelected: (space) { + widget.onSpaceSelected?.call(space); + }, + ), + ), + if (widget.extraEntryBuilders != null) + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + children: widget.extraEntryBuilders!.map((e) => e(70.0)).toList(), + ), + ], + ), + ); } bool shouldShowAvatarForSpace(Space space) { - var spaces = _clientManager.spaces - .where((element) => element.identifier == space.identifier); + var spaces = _clientManager.spaces.where( + (element) => element.identifier == space.identifier, + ); return spaces.length > 1; } } diff --git a/commet/lib/ui/organisms/side_navigation_bar/side_navigation_bar_direct_messages.dart b/commet/lib/ui/organisms/side_navigation_bar/side_navigation_bar_direct_messages.dart index 96735731b..e2422103c 100644 --- a/commet/lib/ui/organisms/side_navigation_bar/side_navigation_bar_direct_messages.dart +++ b/commet/lib/ui/organisms/side_navigation_bar/side_navigation_bar_direct_messages.dart @@ -8,8 +8,12 @@ import 'package:flutter/material.dart'; import 'package:implicitly_animated_list/implicitly_animated_list.dart'; class SideNavigationBarDirectMessages extends StatefulWidget { - const SideNavigationBarDirectMessages(this.directMessages, - {super.key, this.onRoomTapped, this.filterClient}); + const SideNavigationBarDirectMessages( + this.directMessages, { + super.key, + this.onRoomTapped, + this.filterClient, + }); final DirectMessagesInterface directMessages; final Client? filterClient; @@ -35,8 +39,9 @@ class _SideNavigationBarDirectMessagesState rooms = widget.directMessages.highlightedRoomsList; subscriptions = [ EventBus.setFilterClient.stream.listen(setFilterClient), - widget.directMessages.highlightedRoomsList.onListUpdated - .listen(onListUpdated), + widget.directMessages.highlightedRoomsList.onListUpdated.listen( + onListUpdated, + ), ]; } diff --git a/commet/lib/ui/organisms/space_summary/space_summary.dart b/commet/lib/ui/organisms/space_summary/space_summary.dart index 95ec162c1..07f9fdade 100644 --- a/commet/lib/ui/organisms/space_summary/space_summary.dart +++ b/commet/lib/ui/organisms/space_summary/space_summary.dart @@ -13,15 +13,17 @@ import 'package:commet/ui/pages/get_or_create_room/get_or_create_room.dart'; import 'package:commet/ui/pages/settings/room_settings_page.dart'; import 'package:commet/ui/pages/settings/space_settings_page.dart'; import 'package:flutter/material.dart'; + import '../../navigation/navigation_utils.dart'; class SpaceSummary extends StatefulWidget { - const SpaceSummary( - {super.key, - required this.space, - this.onRoomTap, - this.onSpaceTap, - this.onLeaveRoom}); + const SpaceSummary({ + super.key, + required this.space, + this.onRoomTap, + this.onSpaceTap, + this.onLeaveRoom, + }); final Space space; final Function(Room room)? onRoomTap; final Function(Space space)? onSpaceTap; @@ -69,8 +71,9 @@ class _SpaceSummaryState extends State { banner: banner?.banner, openSpaceSettings: openSpaceSettings, onRoomSettingsButtonTap: openRoomSettings, - onInviteButtonTap: - widget.space.permissions.canInviteUser ? onInviteTap : null, + onInviteButtonTap: widget.space.permissions.canInviteUser + ? onInviteTap + : null, spaceColor: widget.space.color, onRoomTap: widget.onRoomTap, showSpaceSettingsButton: widget.space.permissions.canEditAnything, @@ -92,11 +95,13 @@ class _SpaceSummaryState extends State { void openRoomSettings(Room room) { NavigationUtils.navigateTo( - context, - RoomSettingsPage( - room: room, - contextSpace: widget.space, - onLeaveRoom: widget.onLeaveRoom)); + context, + RoomSettingsPage( + room: room, + contextSpace: widget.space, + onLeaveRoom: widget.onLeaveRoom, + ), + ); } void onAddRoomButtonTap() async { @@ -131,12 +136,16 @@ class _SpaceSummaryState extends State { onInviteTap() { final invitation = widget.space.client.getComponent(); if (invitation != null) { - AdaptiveDialog.show(context, - builder: (context) => SendInvitationWidget( - widget.space.client, invitation, - roomId: widget.space.identifier, - displayName: widget.space.displayName), - title: "Invite"); + AdaptiveDialog.show( + context, + builder: (context) => SendInvitationWidget( + widget.space.client, + invitation, + roomId: widget.space.identifier, + displayName: widget.space.displayName, + ), + title: "Invite", + ); } } diff --git a/commet/lib/ui/organisms/space_summary/space_summary_view.dart b/commet/lib/ui/organisms/space_summary/space_summary_view.dart index 7c820c54e..46a9c99fc 100644 --- a/commet/lib/ui/organisms/space_summary/space_summary_view.dart +++ b/commet/lib/ui/organisms/space_summary/space_summary_view.dart @@ -24,26 +24,27 @@ import 'package:tiamat/tiamat.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class SpaceSummaryView extends StatefulWidget { - const SpaceSummaryView( - {super.key, - required this.space, - required this.displayName, - this.topic, - this.joinRoom, - this.avatar, - this.onSpaceUpdated, - this.banner, - this.visibility, - this.spaceColor, - this.showSpaceSettingsButton = false, - this.onInviteButtonTap, - this.openSpaceSettings, - this.onAddRoomButtonTap, - this.onRoomTap, - this.canAddRoom = false, - this.onSpaceTap, - this.colorScheme, - this.onRoomSettingsButtonTap}); + const SpaceSummaryView({ + super.key, + required this.space, + required this.displayName, + this.topic, + this.joinRoom, + this.avatar, + this.onSpaceUpdated, + this.banner, + this.visibility, + this.spaceColor, + this.showSpaceSettingsButton = false, + this.onInviteButtonTap, + this.openSpaceSettings, + this.onAddRoomButtonTap, + this.onRoomTap, + this.canAddRoom = false, + this.onSpaceTap, + this.colorScheme, + this.onRoomSettingsButtonTap, + }); final Space space; final String displayName; @@ -68,47 +69,64 @@ class SpaceSummaryView extends StatefulWidget { } class SpaceSummaryViewState extends State { - static ValueKey spaceSettingsButtonKey = - const ValueKey("SPACE_SUMMARY_SPACE_SETTINGS_BUTTON"); - - String get tooltipSpaceSettings => Intl.message("Space settings", - desc: "Tooltip for the button that opens space settings", - name: "tooltipSpaceSettings"); - - String get tooltipAddRoom => Intl.message("Add room", - desc: "Tooltip for the button that adds a new room to a space", - name: "tooltipAddRoom"); - - String get labelSpaceRoomsList => Intl.message("Rooms", - desc: "Header label for the list of rooms in a space", - name: "labelSpaceRoomsList"); - - String get labelSpaceSubspacesList => Intl.message("Spaces", - desc: "Header label for the list of child spaces in a space", - name: "labelSpaceSubspacesList"); - - String get labelSpaceAvailableRoomsList => Intl.message("Available rooms", - desc: - "Header label for the list of rooms in a space, which the user has not yet joined but are available", - name: "labelSpaceAvailableRoomsList"); - - String get labelSpaceVisibilityPublic => Intl.message("Public space", - desc: "Label to display that the space is publically available", - name: "labelSpaceVisibilityPublic"); - - String get labelSpaceVisibilityPrivate => Intl.message("Private space", - desc: "Label to display that the space is private", - name: "labelSpaceVisibilityPrivate"); - - String get labelSpaceVisibilityRestricted => Intl.message("Restricted space", - desc: "Label to display that the space is restricted", - name: "labelSpaceVisibilityRestricted"); - - String labelSpaceGettingText(spaceName) => - Intl.message("Welcome to \n\n # $spaceName", - args: [spaceName], - desc: "Greeting to the space, supports markdown formatting", - name: "labelSpaceGettingText"); + static ValueKey spaceSettingsButtonKey = const ValueKey( + "SPACE_SUMMARY_SPACE_SETTINGS_BUTTON", + ); + + String get tooltipSpaceSettings => Intl.message( + "Space settings", + desc: "Tooltip for the button that opens space settings", + name: "tooltipSpaceSettings", + ); + + String get tooltipAddRoom => Intl.message( + "Add room", + desc: "Tooltip for the button that adds a new room to a space", + name: "tooltipAddRoom", + ); + + String get labelSpaceRoomsList => Intl.message( + "Rooms", + desc: "Header label for the list of rooms in a space", + name: "labelSpaceRoomsList", + ); + + String get labelSpaceSubspacesList => Intl.message( + "Spaces", + desc: "Header label for the list of child spaces in a space", + name: "labelSpaceSubspacesList", + ); + + String get labelSpaceAvailableRoomsList => Intl.message( + "Available rooms", + desc: "Header label for the list of rooms in a space, which the user has not yet joined but are available", + name: "labelSpaceAvailableRoomsList", + ); + + String get labelSpaceVisibilityPublic => Intl.message( + "Public space", + desc: "Label to display that the space is publically available", + name: "labelSpaceVisibilityPublic", + ); + + String get labelSpaceVisibilityPrivate => Intl.message( + "Private space", + desc: "Label to display that the space is private", + name: "labelSpaceVisibilityPrivate", + ); + + String get labelSpaceVisibilityRestricted => Intl.message( + "Restricted space", + desc: "Label to display that the space is restricted", + name: "labelSpaceVisibilityRestricted", + ); + + String labelSpaceGettingText(spaceName) => Intl.message( + "Welcome to \n\n # $spaceName", + args: [spaceName], + desc: "Greeting to the space, supports markdown formatting", + name: "labelSpaceGettingText", + ); late List previews; @@ -138,12 +156,15 @@ class SpaceSummaryViewState extends State { } subs = [ - widget.space.onChildRoomPreviewAdded - .listen((_) => onPreviewListChanged()), - widget.space.onChildRoomPreviewsUpdated - .listen((_) => onPreviewListChanged()), - widget.space.onChildRoomPreviewRemoved - .listen((_) => onPreviewListChanged()), + widget.space.onChildRoomPreviewAdded.listen( + (_) => onPreviewListChanged(), + ), + widget.space.onChildRoomPreviewsUpdated.listen( + (_) => onPreviewListChanged(), + ), + widget.space.onChildRoomPreviewRemoved.listen( + (_) => onPreviewListChanged(), + ), widget.space.onRoomAdded.listen((_) => onRoomListChanged()), widget.space.onRoomRemoved.listen((_) => onRoomListChanged()), widget.space.onChildSpaceAdded.listen((_) => onSpaceListChanged()), @@ -181,8 +202,7 @@ class SpaceSummaryViewState extends State { @override Widget build(BuildContext context) { - var baseTextTheme = TextTheme.of(context) - .bodySmall + var baseTextTheme = TextTheme.of(context).bodySmall ?.copyWith(color: Theme.of(context).colorScheme.secondary); return Column( @@ -211,46 +231,52 @@ class SpaceSummaryViewState extends State { MarkdownBody( data: labelSpaceGettingText(widget.displayName), styleSheet: MarkdownStyleSheet( - h1Padding: EdgeInsets.zero, - pPadding: EdgeInsets.zero), + h1Padding: EdgeInsets.zero, + pPadding: EdgeInsets.zero, + ), ), if (widget.topic != null) MarkdownBody( - data: widget.topic!, - imageBuilder: (uri, title, alt) { - if (uri.scheme == "mxc" && - widget.space.client is MatrixClient) { - return SizedBox( - height: 50, - child: Image( - image: MatrixMxcImage( - uri, - doFullres: true, - doThumbnail: false, - autoLoadFullRes: true, - (widget.space.client - as MatrixClient) - .matrixClient)), - ); - } - - return Container(); - }, - onTapLink: (text, href, title) { - if (href != null) { - LinkUtils.open(Uri.parse(href), - context: context); - } - }, - styleSheet: MarkdownStyleSheet.fromTheme( - Theme.of(context)) - .copyWith( - a: baseTextTheme?.copyWith( - color: Theme.of(context) - .extension() - ?.linkColor), - p: baseTextTheme, - )), + data: widget.topic!, + imageBuilder: (uri, title, alt) { + if (uri.scheme == "mxc" && + widget.space.client is MatrixClient) { + return SizedBox( + height: 50, + child: Image( + image: MatrixMxcImage( + uri, + doFullres: true, + doThumbnail: false, + autoLoadFullRes: true, + (widget.space.client as MatrixClient) + .matrixClient, + ), + ), + ); + } + + return Container(); + }, + onTapLink: (text, href, title) { + if (href != null) { + LinkUtils.open( + Uri.parse(href), + context: context, + ); + } + }, + styleSheet: + MarkdownStyleSheet.fromTheme(Theme.of(context)) + .copyWith( + a: baseTextTheme?.copyWith( + color: Theme.of(context) + .extension() + ?.linkColor, + ), + p: baseTextTheme, + ), + ), spaceVisibility(), ], ), @@ -266,7 +292,7 @@ class SpaceSummaryViewState extends State { buildSettingsButton(), ], ), - ) + ), ], ), if (children.isNotEmpty || @@ -322,48 +348,52 @@ class SpaceSummaryViewState extends State { ? EdgeInsetsGeometry.only(left: 8, right: 8) : EdgeInsetsGeometry.zero, child: DecoratedBox( - decoration: BoxDecoration( - image: widget.banner != null - ? DecorationImage( - image: widget.banner!, fit: BoxFit.cover) - : null, - color: widget.banner == null ? colorScheme.secondary : null, - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(15), - bottomRight: Radius.circular(15))), - child: ScaledSafeArea( - bottom: false, - left: false, - right: false, - top: true, - child: SizedBox( - height: 250, - // child: widget.banner != null - // ? Image( - // image: widget.banner!, - // fit: BoxFit.cover, - // ) - // : null, - width: double.infinity, - ), - )), + decoration: BoxDecoration( + image: widget.banner != null + ? DecorationImage(image: widget.banner!, fit: BoxFit.cover) + : null, + color: widget.banner == null ? colorScheme.secondary : null, + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(15), + bottomRight: Radius.circular(15), + ), + ), + child: ScaledSafeArea( + bottom: false, + left: false, + right: false, + top: true, + child: SizedBox( + height: 250, + // child: widget.banner != null + // ? Image( + // image: widget.banner!, + // fit: BoxFit.cover, + // ) + // : null, + width: double.infinity, + ), + ), + ), ), Align( alignment: AlignmentGeometry.center, child: Padding( - padding: const EdgeInsets.fromLTRB(0, 150, 0, 0), - child: ScaledSafeArea( - child: Avatar.extraLarge( - border: BoxBorder.all( - color: Theme.of(context).colorScheme.surface, - width: 10, - style: BorderStyle.solid, - strokeAlign: 0.5), - image: widget.avatar, - placeholderText: widget.displayName, - placeholderColor: widget.spaceColor, + padding: const EdgeInsets.fromLTRB(0, 150, 0, 0), + child: ScaledSafeArea( + child: Avatar.extraLarge( + border: BoxBorder.all( + color: Theme.of(context).colorScheme.surface, + width: 10, + style: BorderStyle.solid, + strokeAlign: 0.5, ), - )), + image: widget.avatar, + placeholderText: widget.displayName, + placeholderColor: widget.spaceColor, + ), + ), + ), ), ], ); @@ -371,33 +401,36 @@ class SpaceSummaryViewState extends State { Widget buildPreviewList() { return Panel( - header: labelSpaceAvailableRoomsList, - mode: TileType.surfaceContainer, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - ImplicitlyAnimatedList( - padding: EdgeInsets.all(0), - key: ValueKey( - "animated-list-child-previews-${widget.space.identifier}"), - initialAnimation: false, - physics: NeverScrollableScrollPhysics(), - itemData: previews, - shrinkWrap: true, - itemBuilder: (context, preview) { - return RoomPanelView( - displayName: preview.displayName, - avatar: preview.avatar, - primaryButtonLabel: CommonStrings.promptJoin, - body: preview.topic, - color: preview.color, - onPrimaryButtonPressed: () async { - await widget.joinRoom?.call(preview); - }, - ); - }), - ], - )); + header: labelSpaceAvailableRoomsList, + mode: TileType.surfaceContainer, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + ImplicitlyAnimatedList( + padding: EdgeInsets.all(0), + key: ValueKey( + "animated-list-child-previews-${widget.space.identifier}", + ), + initialAnimation: false, + physics: NeverScrollableScrollPhysics(), + itemData: previews, + shrinkWrap: true, + itemBuilder: (context, preview) { + return RoomPanelView( + displayName: preview.displayName, + avatar: preview.avatar, + primaryButtonLabel: CommonStrings.promptJoin, + body: preview.topic, + color: preview.color, + onPrimaryButtonPressed: () async { + await widget.joinRoom?.call(preview); + }, + ); + }, + ), + ], + ), + ); } Widget spaceVisibility() { @@ -414,7 +447,7 @@ class SpaceSummaryViewState extends State { Padding( padding: const EdgeInsets.all(8.0), child: tiamat.Text.label(text), - ) + ), ], ); } @@ -435,22 +468,24 @@ class SpaceSummaryViewState extends State { var pad = EdgeInsets.fromLTRB(0, 0, showHandles ? 50 : 0, 0); if (MediaQuery.of(context).mobile) { return ReorderableDelayedDragStartListener( - key: key, - enabled: canChangeOrder, - index: index, - child: Padding( - padding: pad, - child: buildItem(item, widget.space), - )); + key: key, + enabled: canChangeOrder, + index: index, + child: Padding( + padding: pad, + child: buildItem(item, widget.space), + ), + ); } else { return ReorderableDragStartListener( - key: key, - enabled: canChangeOrder && orderChanged, - index: index, - child: Padding( - padding: pad, - child: buildItem(item, widget.space), - )); + key: key, + enabled: canChangeOrder && orderChanged, + index: index, + child: Padding( + padding: pad, + child: buildItem(item, widget.space), + ), + ); } }, onReorderStart: (index) => HapticFeedback.mediumImpact(), @@ -458,13 +493,11 @@ class SpaceSummaryViewState extends State { return AnimatedBuilder( animation: animation, builder: (BuildContext context, Widget? child) { - final double animValue = - Curves.easeOut.transform(animation.value); - final double scale = lerpDouble(1, 1.03, animValue)!; - return Transform.scale( - scale: scale, - child: child, + final double animValue = Curves.easeOut.transform( + animation.value, ); + final double scale = lerpDouble(1, 1.03, animValue)!; + return Transform.scale(scale: scale, child: child); }, child: child, ); @@ -506,17 +539,21 @@ class SpaceSummaryViewState extends State { orderChangeLoading = true; }); - widget.space.setChildrenOrder(children, - onProgressChanged: (v) { - setState(() { - orderChangedProgress = v; - }); - }).then((_) { - setState(() { - orderChanged = false; - orderChangeLoading = false; - }); - }); + widget.space + .setChildrenOrder( + children, + onProgressChanged: (v) { + setState(() { + orderChangedProgress = v; + }); + }, + ) + .then((_) { + setState(() { + orderChanged = false; + orderChangeLoading = false; + }); + }); }, child: orderChangeLoading ? SizedBox( @@ -524,11 +561,13 @@ class SpaceSummaryViewState extends State { height: 20, child: CircularProgressIndicator( color: Theme.of(context).colorScheme.onSurface, - value: orderChangedProgress != null && + value: + orderChangedProgress != null && orderChangedProgress! > 0.1 ? orderChangedProgress : null, - )) + ), + ) : Icon(Icons.save), ), ], @@ -546,13 +585,17 @@ class SpaceSummaryViewState extends State { onPressed: () => widget.onAddRoomButtonTap?.call(), ), ), - ) + ), ], ); } - Widget buildItem(SpaceChild item, Space parent, - {int depth = 0, int maxDepth = 5}) { + Widget buildItem( + SpaceChild item, + Space parent, { + int depth = 0, + int maxDepth = 5, + }) { Widget? result; if (item case SpaceChildRoom _) { @@ -563,27 +606,37 @@ class SpaceSummaryViewState extends State { padding: const EdgeInsets.all(8.0), child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: Theme.of(context).colorScheme.surfaceContainer), - child: tiamat.TextButtonExpander(item.child.displayName, - textPadding: EdgeInsetsGeometry.all(20), - icon: Icons.star, onNameTapped: () { - widget.onSpaceTap?.call(item.child); - }, - avatar: item.child.avatar, - avatarPlaceholderColor: item.child.color, - avatarPlaceholderText: item.child.displayName, - avatarRadius: 24, - childrenPadding: const EdgeInsets.fromLTRB(24, 0, 0, 0), - initiallyExpanded: false, - iconColor: Theme.of(context).colorScheme.secondary, - textColor: Theme.of(context).colorScheme.secondary, - children: depth >= maxDepth - ? [] - : item.child.children - .map((i) => buildItem(i, item.child, - depth: depth + 1, maxDepth: maxDepth)) - .toList()), + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).colorScheme.surfaceContainer, + ), + child: tiamat.TextButtonExpander( + item.child.displayName, + textPadding: EdgeInsetsGeometry.all(20), + icon: Icons.star, + onNameTapped: () { + widget.onSpaceTap?.call(item.child); + }, + avatar: item.child.avatar, + avatarPlaceholderColor: item.child.color, + avatarPlaceholderText: item.child.displayName, + avatarRadius: 24, + childrenPadding: const EdgeInsets.fromLTRB(24, 0, 0, 0), + initiallyExpanded: false, + iconColor: Theme.of(context).colorScheme.secondary, + textColor: Theme.of(context).colorScheme.secondary, + children: depth >= maxDepth + ? [] + : item.child.children + .map( + (i) => buildItem( + i, + item.child, + depth: depth + 1, + maxDepth: maxDepth, + ), + ) + .toList(), + ), ), ); } else { diff --git a/commet/lib/ui/organisms/update_installed_dialog/update_installed_dialog.dart b/commet/lib/ui/organisms/update_installed_dialog/update_installed_dialog.dart index c351f5bc0..49f92e335 100644 --- a/commet/lib/ui/organisms/update_installed_dialog/update_installed_dialog.dart +++ b/commet/lib/ui/organisms/update_installed_dialog/update_installed_dialog.dart @@ -17,10 +17,10 @@ class _UpdateInstalledDialogState extends State { MessageEffectConfetti? confetti; String get updateInstalledContent => Intl.message( - "Thank you for updating! Please consider donating to support the project so we can continue to deliver great updates!", - desc: - "Content for the dialog which is shown when an update has been installed", - name: "updateInstalledContent"); + "Thank you for updating! Please consider donating to support the project so we can continue to deliver great updates!", + desc: "Content for the dialog which is shown when an update has been installed", + name: "updateInstalledContent", + ); @override void initState() { @@ -41,68 +41,70 @@ class _UpdateInstalledDialogState extends State { children: [ if (confetti?.system != null) SizedBox( - width: 500, - height: 200, - child: ParticleSystemRenderer(system: confetti!.system!)), - SizedBox( width: 500, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - spacing: 12, - children: [ - tiamat.Text.label(updateInstalledContent), - Material( - clipBehavior: Clip.antiAlias, - color: ColorScheme.of(context).surfaceContainerLowest, - borderRadius: BorderRadius.circular(8), - child: InkWell( - onTap: () { - Navigator.of(context).pop(); + height: 200, + child: ParticleSystemRenderer(system: confetti!.system!), + ), + SizedBox( + width: 500, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + spacing: 12, + children: [ + tiamat.Text.label(updateInstalledContent), + Material( + clipBehavior: Clip.antiAlias, + color: ColorScheme.of(context).surfaceContainerLowest, + borderRadius: BorderRadius.circular(8), + child: InkWell( + onTap: () { + Navigator.of(context).pop(); - widget.onDonateTapped?.call(); - }, - child: SizedBox( - height: 60, - child: Center( - child: Row( - mainAxisSize: MainAxisSize.min, - spacing: 8, - children: [ - Icon( - Icons.favorite, - color: Colors.redAccent, - ), - tiamat.Text.label( - DesktopSettingsPageState.promptDonate), - ], - ), - ), - ), - )), - Material( - clipBehavior: Clip.antiAlias, - color: ColorScheme.of(context).surfaceContainerLow, - borderRadius: BorderRadius.circular(8), - child: InkWell( - onTap: () { - Navigator.of(context).pop(); - }, - child: SizedBox( - height: 40, - child: Center( - child: Row( - mainAxisSize: MainAxisSize.min, - spacing: 8, - children: [ - tiamat.Text(CommonStrings.promptPoliteNo), - ], - ), - ), + widget.onDonateTapped?.call(); + }, + child: SizedBox( + height: 60, + child: Center( + child: Row( + mainAxisSize: MainAxisSize.min, + spacing: 8, + children: [ + Icon(Icons.favorite, color: Colors.redAccent), + tiamat.Text.label( + DesktopSettingsPageState.promptDonate, ), - )), - ]))) + ], + ), + ), + ), + ), + ), + Material( + clipBehavior: Clip.antiAlias, + color: ColorScheme.of(context).surfaceContainerLow, + borderRadius: BorderRadius.circular(8), + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: SizedBox( + height: 40, + child: Center( + child: Row( + mainAxisSize: MainAxisSize.min, + spacing: 8, + children: [tiamat.Text(CommonStrings.promptPoliteNo)], + ), + ), + ), + ), + ), + ], + ), + ), + ), ], ); } diff --git a/commet/lib/ui/organisms/user_profile/user_profile.dart b/commet/lib/ui/organisms/user_profile/user_profile.dart index 4b8f755ac..c24c58d0b 100644 --- a/commet/lib/ui/organisms/user_profile/user_profile.dart +++ b/commet/lib/ui/organisms/user_profile/user_profile.dart @@ -23,16 +23,17 @@ import 'package:intl/intl.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class UserProfile extends StatefulWidget { - const UserProfile( - {super.key, - required this.userId, - this.width = 700, - this.bannerHeight = 230.0, - required this.client, - this.maxBioHeight = 200, - this.doSafeArea = true, - this.showMessageButton = true, - this.dismiss}); + const UserProfile({ + super.key, + required this.userId, + this.width = 700, + this.bannerHeight = 230.0, + required this.client, + this.maxBioHeight = 200, + this.doSafeArea = true, + this.showMessageButton = true, + this.dismiss, + }); final Client client; final String userId; final double bannerHeight; @@ -56,24 +57,33 @@ class UserProfile extends StatefulWidget { }) async { if (MediaQuery.of(context).desktop) return showGeneralDialog( - context: context, - pageBuilder: (context, animation, secondaryAnimation) { - return Theme( - data: Theme.of(context), - child: Center(child: UserProfile(userId: userId, client: client)), - ); - }, - barrierLabel: "USER_PROFILE_BARRIER", - barrierDismissible: dismissible, - transitionDuration: const Duration(milliseconds: 300), - transitionBuilder: (context, animation, secondaryAnimation, child) => - SlideTransition( - position: - Tween(begin: const Offset(0, 1), end: const Offset(0, 0)) - .animate(CurvedAnimation( - parent: animation, curve: Curves.easeOutCubic)), - child: child, - )); + context: context, + pageBuilder: (context, animation, secondaryAnimation) { + return Theme( + data: Theme.of(context), + child: Center( + child: UserProfile(userId: userId, client: client), + ), + ); + }, + barrierLabel: "USER_PROFILE_BARRIER", + barrierDismissible: dismissible, + transitionDuration: const Duration(milliseconds: 300), + transitionBuilder: (context, animation, secondaryAnimation, child) => + SlideTransition( + position: + Tween( + begin: const Offset(0, 1), + end: const Offset(0, 0), + ).animate( + CurvedAnimation( + parent: animation, + curve: Curves.easeOutCubic, + ), + ), + child: child, + ), + ); return showModalBottomSheet( isScrollControlled: true, @@ -128,8 +138,13 @@ class _UserProfileState extends State { if (avatar case MatrixMxcImage mxc) { // create a new image instance so we can load fullres without it loading everywhere - avatar = MatrixMxcImage(mxc.identifier, mxc.client, - doThumbnail: false, doFullres: true, autoLoadFullRes: true); + avatar = MatrixMxcImage( + mxc.identifier, + mxc.client, + doThumbnail: false, + doFullres: true, + autoLoadFullRes: true, + ); } if (value case ProfileWithColorScheme p) { @@ -138,9 +153,10 @@ class _UserProfileState extends State { if (p.color != null) { scheme = ColorScheme.fromSeed( - seedColor: p.color!, - brightness: brightness, - dynamicSchemeVariant: DynamicSchemeVariant.content); + seedColor: p.color!, + brightness: brightness, + dynamicSchemeVariant: DynamicSchemeVariant.content, + ); } } } @@ -153,14 +169,16 @@ class _UserProfileState extends State { if (scheme == null) { if (avatar != null) { scheme = await ColorScheme.fromImageProvider( - provider: value!.banner ?? value.avatar!, - brightness: brightness, - dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot); + provider: value!.banner ?? value.avatar!, + brightness: brightness, + dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot, + ); } else { scheme = ColorScheme.fromSeed( - seedColor: value!.defaultColor, - brightness: brightness, - dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot); + seedColor: value!.defaultColor, + brightness: brightness, + dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot, + ); } } @@ -196,7 +214,9 @@ class _UserProfileState extends State { Widget build(BuildContext context) { if (profile == null) { return SizedBox( - height: 300, child: const Center(child: CircularProgressIndicator())); + height: 300, + child: const Center(child: CircularProgressIndicator()), + ); } Widget? bio; @@ -243,9 +263,10 @@ class _UserProfileState extends State { currentPetName: widget.client .getComponent() ?.getPetName(widget.userId), - hasPetName: widget.client - .getComponent() - ?.getPetName(widget.userId) != + hasPetName: + widget.client.getComponent()?.getPetName( + widget.userId, + ) != null, onSetAvatar: setAvatar, setColorOverride: setColorOverride, @@ -254,9 +275,10 @@ class _UserProfileState extends State { clearStatus: clearStatus, shareCurrentTimezone: shareTimezone, pronouns: pronouns, - hasColorOverride: widget.client - .getComponent() - ?.getColor(profile!.identifier) != + hasColorOverride: + widget.client.getComponent()?.getColor( + profile!.identifier, + ) != null, ), ); @@ -270,17 +292,23 @@ class _UserProfileState extends State { return; } - var existingRooms = component.directMessageRooms.where((element) => - profile!.identifier == component.getDirectMessagePartnerId(element)); + var existingRooms = component.directMessageRooms.where( + (element) => + profile!.identifier == component.getDirectMessagePartnerId(element), + ); if (existingRooms.isNotEmpty == true) { - EventBus.doOpenRoom(existingRooms.first.identifier, - clientId: widget.client.identifier); + EventBus.doOpenRoom( + existingRooms.first.identifier, + clientId: widget.client.identifier, + ); } else { var room = await component.createDirectMessage(profile!.identifier); if (room != null) { - EventBus.doOpenRoom(room.identifier, - clientId: widget.client.identifier); + EventBus.doOpenRoom( + room.identifier, + clientId: widget.client.identifier, + ); } } @@ -288,10 +316,7 @@ class _UserProfileState extends State { } Future setBanner() async { - final action = await ImageSelectDialog.show( - context, - image: banner, - ); + final action = await ImageSelectDialog.show(context, image: banner); if (!mounted) return; @@ -302,8 +327,10 @@ class _UserProfileState extends State { if (action != ImageEditAction.pick) return; - var result = - await PickerUtils.pickImageAndCrop(context, aspectRatio: 700 / 230); + var result = await PickerUtils.pickImageAndCrop( + context, + aspectRatio: 700 / 230, + ); if (result == null) return; setState(() { @@ -334,9 +361,10 @@ class _UserProfileState extends State { void updatePreviewTheme() { theme = Theme.of(context).copyWith( colorScheme: ColorScheme.fromSeed( - seedColor: previewColor, - brightness: previewBrightness, - dynamicSchemeVariant: DynamicSchemeVariant.content), + seedColor: previewColor, + brightness: previewBrightness, + dynamicSchemeVariant: DynamicSchemeVariant.content, + ), ); } @@ -397,13 +425,16 @@ class _UserProfileState extends State { if (text != null) { var client = widget.client; client.getComponent()?.setStatus(text); - client - .getComponent() - ?.setStatus(UserPresenceStatus.online, message: text); + client.getComponent()?.setStatus( + UserPresenceStatus.online, + message: text, + ); setState(() { - presence = UserPresence(UserPresenceStatus.online, - message: UserPresenceMessage(text, PresenceMessageType.userCustom)); + presence = UserPresence( + UserPresenceStatus.online, + message: UserPresenceMessage(text, PresenceMessageType.userCustom), + ); }); } } @@ -413,9 +444,10 @@ class _UserProfileState extends State { await client.getComponent()?.setStatus(null); await client.getComponent()?.setStatus( - UserPresenceStatus.online, - message: null, - clearMessage: true); + UserPresenceStatus.online, + message: null, + clearMessage: true, + ); setState(() { presence = UserPresence(UserPresenceStatus.online); @@ -431,7 +463,10 @@ class _UserProfileState extends State { width: 1000, child: SelectionArea( child: ExpandableCodeBlock( - expanded: true, text: profile!.source, language: "json"), + expanded: true, + text: profile!.source, + language: "json", + ), ), ); }, @@ -439,25 +474,27 @@ class _UserProfileState extends State { } String labelConfirmShareTimezone(String timezone) => Intl.message( - "Are you sure you want to share your timezone '$timezone' publicly?", - name: "labelConfirmShareTimezone", - args: [timezone], - desc: - "Ask the user to confirm that they want to share their current timezone as public information on their profile"); + "Are you sure you want to share your timezone '$timezone' publicly?", + name: "labelConfirmShareTimezone", + args: [timezone], + desc: "Ask the user to confirm that they want to share their current timezone as public information on their profile", + ); Future shareTimezone() async { final currentTimeZone = await FlutterTimezone.getLocalTimezone(); - if (await AdaptiveDialog.confirmation(context, - prompt: labelConfirmShareTimezone(currentTimeZone.identifier)) == + if (await AdaptiveDialog.confirmation( + context, + prompt: labelConfirmShareTimezone(currentTimeZone.identifier), + ) == true) { setState(() { timezone = currentTimeZone.identifier; }); print(currentTimeZone.identifier); - return widget.client - .getComponent() - ?.setTimezone(currentTimeZone.identifier); + return widget.client.getComponent()?.setTimezone( + currentTimeZone.identifier, + ); } } @@ -469,45 +506,53 @@ class _UserProfileState extends State { }); } - String get promptProfileWriteBioHint => Intl.message("Write about yourself", - name: "promptProfileWriteBioHint", - desc: "Hint text for the profile bio editor"); + String get promptProfileWriteBioHint => Intl.message( + "Write about yourself", + name: "promptProfileWriteBioHint", + desc: "Hint text for the profile bio editor", + ); Future setBio() async { - AdaptiveDialog.show(context, builder: (context) { - String? plaintext; + AdaptiveDialog.show( + context, + builder: (context) { + String? plaintext; - if (profile case ProfileWithBio p) { - plaintext = p.plaintextBio; - } + if (profile case ProfileWithBio p) { + plaintext = p.plaintextBio; + } - return SizedBox( - width: 600, - child: MessageInput( - hintText: promptProfileWriteBioHint, - initialText: bioText ?? plaintext, - showAttachmentButton: false, - client: widget.client, - showGifSearch: false, - disableEnterToSend: true, - compact: true, - enableKeyboardAdapter: false, - availibleEmoticons: - widget.client.getComponent()?.availablePacks, - onSendMessage: (message, {overrideClient}) { - widget.client.getComponent()?.setBio(message); - - setState(() { - bioText = message; - }); - - Navigator.of(context).pop(); - - return MessageInputSendResult.success; - }, - ), - ); - }); + return SizedBox( + width: 600, + child: MessageInput( + hintText: promptProfileWriteBioHint, + initialText: bioText ?? plaintext, + showAttachmentButton: false, + client: widget.client, + showGifSearch: false, + disableEnterToSend: true, + compact: true, + enableKeyboardAdapter: false, + availibleEmoticons: widget.client + .getComponent() + ?.availablePacks, + onSendMessage: (message, {overrideClient}) { + widget.client.getComponent()?.setBio( + message, + ); + + setState(() { + bioText = message; + }); + + Navigator.of(context).pop(); + + return MessageInputSendResult.success; + }, + ), + ); + }, + ); } Future clearBio() async { @@ -524,31 +569,32 @@ class _UserProfileState extends State { } } - String get labelProfileYourBadges => Intl.message("Your Badges", - name: "labelProfileYourBadges", - desc: - "label for the ui to select which badges to display on the users profile"); + String get labelProfileYourBadges => Intl.message( + "Your Badges", + name: "labelProfileYourBadges", + desc: "label for the ui to select which badges to display on the users profile", + ); String get labelProfileNoBadges => Intl.message( - "You don't have any badges. You can get badges by donating and supporting development of Commet", - name: "labelProfileNoBadges", - desc: - "text that is shown when the user has no badges, and explain where they can get badges"); + "You don't have any badges. You can get badges by donating and supporting development of Commet", + name: "labelProfileNoBadges", + desc: "text that is shown when the user has no badges, and explain where they can get badges", + ); Future editBadges() async { var availableBadges = await component.getAvailableBadges(); if (availableBadges.isEmpty) { - AdaptiveDialog.show(context, - builder: (context) => SizedBox( - height: 200, - child: Center( - child: Container( - child: tiamat.Text.labelLow(labelProfileNoBadges), - ), - ), - ), - title: labelProfileYourBadges); + AdaptiveDialog.show( + context, + builder: (context) => SizedBox( + height: 200, + child: Center( + child: Container(child: tiamat.Text.labelLow(labelProfileNoBadges)), + ), + ), + title: labelProfileYourBadges, + ); return; } diff --git a/commet/lib/ui/organisms/user_profile/user_profile_view.dart b/commet/lib/ui/organisms/user_profile/user_profile_view.dart index c2c5f4d02..a2f344956 100644 --- a/commet/lib/ui/organisms/user_profile/user_profile_view.dart +++ b/commet/lib/ui/organisms/user_profile/user_profile_view.dart @@ -19,44 +19,45 @@ import 'package:tiamat/tiamat.dart' as tiamat; import 'package:timezone/standalone.dart' as tz; class UserProfileView extends StatefulWidget { - const UserProfileView( - {super.key, - this.userAvatar, - required this.displayName, - required this.userColor, - this.userBanner, - required this.identifier, - required this.isSelf, - this.presence, - this.onSetBanner, - this.timezone, - this.bannerHeight = 230.0, - this.width = 700, - this.setPreviewColor, - this.hasColorOverride = false, - this.setPreviewBrightness, - this.setColorOverride, - this.setPetName, - this.currentPetName, - this.hasPetName = false, - this.shareCurrentTimezone, - this.removeTimezone, - this.onSetAvatar, - this.bio, - this.onSetStatus, - this.editBadges, - this.setBio, - this.badges = const [], - this.clearBio, - this.showMessageButton = true, - this.doSafeArea = true, - this.onChangeName, - this.maxBioHeight = 200, - this.showSource, - this.pronouns = const [], - this.clearStatus, - this.savePreviewTheme, - this.onMessageButtonClicked}); + const UserProfileView({ + super.key, + this.userAvatar, + required this.displayName, + required this.userColor, + this.userBanner, + required this.identifier, + required this.isSelf, + this.presence, + this.onSetBanner, + this.timezone, + this.bannerHeight = 230.0, + this.width = 700, + this.setPreviewColor, + this.hasColorOverride = false, + this.setPreviewBrightness, + this.setColorOverride, + this.setPetName, + this.currentPetName, + this.hasPetName = false, + this.shareCurrentTimezone, + this.removeTimezone, + this.onSetAvatar, + this.bio, + this.onSetStatus, + this.editBadges, + this.setBio, + this.badges = const [], + this.clearBio, + this.showMessageButton = true, + this.doSafeArea = true, + this.onChangeName, + this.maxBioHeight = 200, + this.showSource, + this.pronouns = const [], + this.clearStatus, + this.savePreviewTheme, + this.onMessageButtonClicked, + }); final ImageProvider? userAvatar; final ImageProvider? userBanner; final UserPresence? presence; @@ -101,13 +102,17 @@ class UserProfileView extends StatefulWidget { class UserProfileViewState extends State { bool isLoadingDirectMessage = false; - String get promptOpenDirectMessage => Intl.message("Message", - desc: "Prompt on the button to open a direct message with another user", - name: "promptOpenDirectMessage"); + String get promptOpenDirectMessage => Intl.message( + "Message", + desc: "Prompt on the button to open a direct message with another user", + name: "promptOpenDirectMessage", + ); - String get promptProfileChangeBanner => Intl.message("Change Banner", - desc: "Prompt to change the banner on the user's profile", - name: "promptProfileChangeBanner"); + String get promptProfileChangeBanner => Intl.message( + "Change Banner", + desc: "Prompt to change the banner on the user's profile", + name: "promptProfileChangeBanner", + ); static String get promptProfileSetStatus => Intl.message("Set Status", name: "promptProfileSetStatus"); @@ -124,32 +129,41 @@ class UserProfileViewState extends State { String get promptProfileClearBio => Intl.message("Clear Bio", name: "promptProfileClearBio"); - String get promptProfileShareTimezone => Intl.message("Share Timezone", - name: "promptProfileShareTimezone", - desc: - "Prompt the user to add their current timezone to their user profile"); - - String get promptProfileClearTimezone => Intl.message("Remove Timezone", - name: "promptProfileClearTimezone", - desc: "Prompt to remove the shared timezone from a users profile"); - - String get promptProfileEditColorScheme => Intl.message("Edit Color Scheme", - name: "promptProfileEditColorScheme", - desc: "Prompt to edit the color scheme of the user's own profile"); - - String get promptProfileSetColorOverride => Intl.message("Set Color Override", - name: "promptProfileSetColorOverride", - desc: "Prompt to override the display color of a user"); - - String get promptProfileClearColorOverride => - Intl.message("Clear Color Override", - name: "promptProfileClearColorOverride", - desc: "Prompt to remove an override of the display color of a user"); - - String get promptProfileShowRawProfile => Intl.message("Show Raw Profile", - name: "promptProfileShowRawProfile", - desc: - "Show the raw data of a user profile, typically this is hidden behind developer mode"); + String get promptProfileShareTimezone => Intl.message( + "Share Timezone", + name: "promptProfileShareTimezone", + desc: "Prompt the user to add their current timezone to their user profile", + ); + + String get promptProfileClearTimezone => Intl.message( + "Remove Timezone", + name: "promptProfileClearTimezone", + desc: "Prompt to remove the shared timezone from a users profile", + ); + + String get promptProfileEditColorScheme => Intl.message( + "Edit Color Scheme", + name: "promptProfileEditColorScheme", + desc: "Prompt to edit the color scheme of the user's own profile", + ); + + String get promptProfileSetColorOverride => Intl.message( + "Set Color Override", + name: "promptProfileSetColorOverride", + desc: "Prompt to override the display color of a user", + ); + + String get promptProfileClearColorOverride => Intl.message( + "Clear Color Override", + name: "promptProfileClearColorOverride", + desc: "Prompt to remove an override of the display color of a user", + ); + + String get promptProfileShowRawProfile => Intl.message( + "Show Raw Profile", + name: "promptProfileShowRawProfile", + desc: "Show the raw data of a user profile, typically this is hidden behind developer mode", + ); bool editingColorScheme = false; @@ -162,8 +176,10 @@ class UserProfileViewState extends State { @override void initState() { if (widget.timezone != null) { - timezoneTimer = - Timer.periodic(Duration(seconds: 1), (_) => updateLocalTime()); + timezoneTimer = Timer.periodic( + Duration(seconds: 1), + (_) => updateLocalTime(), + ); updateLocalTime(); } @@ -177,8 +193,10 @@ class UserProfileViewState extends State { timezoneTimer?.cancel(); if (widget.timezone != null) { - timezoneTimer = - Timer.periodic(Duration(seconds: 1), (_) => updateLocalTime()); + timezoneTimer = Timer.periodic( + Duration(seconds: 1), + (_) => updateLocalTime(), + ); updateLocalTime(); } } @@ -222,160 +240,178 @@ class UserProfileViewState extends State { height: bannerHeight, width: double.infinity, child: widget.userBanner != null - ? Image( - image: widget.userBanner!, - fit: BoxFit.cover, - ) + ? Image(image: widget.userBanner!, fit: BoxFit.cover) : widget.userAvatar != null - ? ClipRect( - child: ImageFiltered( - imageFilter: ImageFilter.blur( - sigmaX: 40, - sigmaY: 40, - tileMode: TileMode.repeated), - child: Container( - color: Theme.of(context) - .colorScheme - .surfaceContainer, - child: Image( - image: widget.userAvatar!, - fit: BoxFit.cover, - ), - ), - ), - ) - : Container( + ? ClipRect( + child: ImageFiltered( + imageFilter: ImageFilter.blur( + sigmaX: 40, + sigmaY: 40, + tileMode: TileMode.repeated, + ), + child: Container( color: Theme.of(context) .colorScheme - .surfaceContainerLow, + .surfaceContainer, + child: Image( + image: widget.userAvatar!, + fit: BoxFit.cover, + ), ), + ), + ) + : Container( + color: Theme.of(context) + .colorScheme + .surfaceContainerLow, + ), ), Align( - alignment: AlignmentGeometry.topRight, - child: Padding( - padding: const EdgeInsets.all(4.0), - child: ClipRRect( - borderRadius: BorderRadiusGeometry.circular(15), - child: SizedBox( - width: 30, - height: 30, - child: Material( - color: Theme.of(context) - .colorScheme - .primaryContainer - .withAlpha(100), - child: AdaptiveContextMenu( - modal: true, - items: contextMenuItems(context), - child: Icon( - Icons.more_vert, - size: 15, - ), - ), - )), + alignment: AlignmentGeometry.topRight, + child: Padding( + padding: const EdgeInsets.all(4.0), + child: ClipRRect( + borderRadius: BorderRadiusGeometry.circular(15), + child: SizedBox( + width: 30, + height: 30, + child: Material( + color: Theme.of(context) + .colorScheme + .primaryContainer + .withAlpha(100), + child: AdaptiveContextMenu( + modal: true, + items: contextMenuItems(context), + child: Icon(Icons.more_vert, size: 15), + ), + ), ), - )), + ), + ), + ), Padding( padding: EdgeInsets.fromLTRB( - 0, bannerHeight - avatarOverlap, 0, 0), + 0, + bannerHeight - avatarOverlap, + 0, + 0, + ), child: Stack( children: [ Padding( padding: const EdgeInsets.fromLTRB( - 0, avatarOverlap - 2, 0, 0), + 0, + avatarOverlap - 2, + 0, + 0, + ), child: Container( color: background, child: ScaledSafeArea( - bottom: widget.doSafeArea, - top: widget.doSafeArea, - left: widget.doSafeArea, - right: widget.doSafeArea, - child: Padding( - padding: EdgeInsets.fromLTRB( - 8, avatarOverlap, 8, 8), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: Theme.of(context) - .colorScheme - .surfaceContainer, - ), - child: Column( - spacing: 8, - crossAxisAlignment: - CrossAxisAlignment.stretch, - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - child: Padding( - padding: - const EdgeInsets.fromLTRB( - 12, 4, 12, 4), - child: Row( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Flexible( - child: Column( - crossAxisAlignment: - CrossAxisAlignment - .start, - children: [ - displayName(), - username(context), - pronouns(), - ], - ), + bottom: widget.doSafeArea, + top: widget.doSafeArea, + left: widget.doSafeArea, + right: widget.doSafeArea, + child: Padding( + padding: EdgeInsets.fromLTRB( + 8, + avatarOverlap, + 8, + 8, + ), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context) + .colorScheme + .surfaceContainer, + ), + child: Column( + spacing: 8, + crossAxisAlignment: + CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Padding( + padding: const EdgeInsets.fromLTRB( + 12, + 4, + 12, + 4, + ), + child: Row( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Flexible( + child: Column( + crossAxisAlignment: + CrossAxisAlignment + .start, + children: [ + displayName(), + username(context), + pronouns(), + ], ), - Padding( - padding: const EdgeInsets - .fromLTRB(0, 8, 0, 0), - child: Column( - spacing: 8, - crossAxisAlignment: - CrossAxisAlignment - .end, - children: [ - if (localTime != null && - widget.timezone != - null) - userLocalTime(), - badges(), - ], - ), - ) - ], - ), + ), + Padding( + padding: + const EdgeInsets.fromLTRB( + 0, + 8, + 0, + 0, + ), + child: Column( + spacing: 8, + crossAxisAlignment: + CrossAxisAlignment.end, + children: [ + if (localTime != null && + widget.timezone != + null) + userLocalTime(), + badges(), + ], + ), + ), + ], ), ), - if (widget.bio != null) - Padding( - padding: - const EdgeInsets.fromLTRB( - 8, 0, 8, 0), - child: buildBio(context), + ), + if (widget.bio != null) + Padding( + padding: const EdgeInsets.fromLTRB( + 8, + 0, + 8, + 0, ), - if (!widget.isSelf && - widget.showMessageButton) - Padding( - padding: - const EdgeInsets.all(8.0), - child: tiamat.Button( - text: promptOpenDirectMessage, - isLoading: - isLoadingDirectMessage, - onTap: clickMessageButton, - ), + child: buildBio(context), + ), + if (!widget.isSelf && + widget.showMessageButton) + Padding( + padding: const EdgeInsets.all(8.0), + child: tiamat.Button( + text: promptOpenDirectMessage, + isLoading: isLoadingDirectMessage, + onTap: clickMessageButton, ), - if (editingColorScheme) - buildColorSchemeEditor() - ], - ), + ), + if (editingColorScheme) + buildColorSchemeEditor(), + ], ), - )), + ), + ), + ), ), ), Padding( @@ -384,25 +420,29 @@ class UserProfileViewState extends State { crossAxisAlignment: CrossAxisAlignment.end, children: [ MouseRegion( - cursor: widget.isSelf - ? SystemMouseCursors.click - : MouseCursor.defer, - child: GestureDetector( - onTap: widget.isSelf - ? widget.onSetAvatar - : null, - child: tiamat.Avatar.large( - border: BoxBorder.all( - color: background, - width: 8, - strokeAlign: 0.9), - image: widget.userAvatar, - placeholderColor: widget.userColor, - placeholderText: widget.displayName, - ))), + cursor: widget.isSelf + ? SystemMouseCursors.click + : MouseCursor.defer, + child: GestureDetector( + onTap: widget.isSelf + ? widget.onSetAvatar + : null, + child: tiamat.Avatar.large( + border: BoxBorder.all( + color: background, + width: 8, + strokeAlign: 0.9, + ), + image: widget.userAvatar, + placeholderColor: widget.userColor, + placeholderText: widget.displayName, + ), + ), + ), if (widget.presence?.message != null) Flexible( - child: buildPresenceDisplay(background)) + child: buildPresenceDisplay(background), + ), ], ), ), @@ -423,47 +463,51 @@ class UserProfileViewState extends State { return Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 4), child: Opacity( - opacity: 0.8, - child: Row( - children: [ - Text( - widget.identifier, - style: Theme.of(context).textTheme.labelSmall?.copyWith( - fontFamily: "Code", - color: Theme.of(context).colorScheme.onSurface), - ), - tiamat.IconButton( - icon: Icons.copy, - onPressed: () => - Clipboard.setData(ClipboardData(text: widget.identifier)), - size: Theme.of(context).textTheme.labelSmall?.fontSize ?? 12, - iconColor: Theme.of(context).colorScheme.onSurface, + opacity: 0.8, + child: Row( + children: [ + Text( + widget.identifier, + style: Theme.of(context).textTheme.labelSmall?.copyWith( + fontFamily: "Code", + color: Theme.of(context).colorScheme.onSurface, ), - ], - )), + ), + tiamat.IconButton( + icon: Icons.copy, + onPressed: () => + Clipboard.setData(ClipboardData(text: widget.identifier)), + size: Theme.of(context).textTheme.labelSmall?.fontSize ?? 12, + iconColor: Theme.of(context).colorScheme.onSurface, + ), + ], + ), + ), ); } Container buildBio(BuildContext context) { return Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: Theme.of(context).colorScheme.surface, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).colorScheme.surface, + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ConstrainedBox( + constraints: BoxConstraints(maxHeight: widget.maxBioHeight), + child: Scrollbar( + thumbVisibility: true, + controller: bioScrollController, + child: SingleChildScrollView( + padding: EdgeInsets.all(0), + controller: bioScrollController, + child: widget.bio, + ), + ), ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: ConstrainedBox( - constraints: BoxConstraints(maxHeight: widget.maxBioHeight), - child: Scrollbar( - thumbVisibility: true, - controller: bioScrollController, - child: SingleChildScrollView( - padding: EdgeInsets.all(0), - controller: bioScrollController, - child: widget.bio, - ), - ), - ))); + ), + ); } Widget userLocalTime() { @@ -475,9 +519,9 @@ class UserProfileViewState extends State { : false; var localDay = DateFormat(DateFormat.WEEKDAY).format(DateTime.now()); var day = DateFormat(DateFormat.WEEKDAY).format(t); - var time = MaterialLocalizations.of(context).formatTimeOfDay( - TimeOfDay.fromDateTime(t), - alwaysUse24HourFormat: use24); + var time = MaterialLocalizations.of( + context, + ).formatTimeOfDay(TimeOfDay.fromDateTime(t), alwaysUse24HourFormat: use24); var result = time; if (day != localDay) { @@ -486,8 +530,11 @@ class UserProfileViewState extends State { final colors = Theme.of(context).colorScheme; return tiamat.Tooltip( - child: TinyPill(result, - background: colors.tertiary, foreground: colors.onTertiary), + child: TinyPill( + result, + background: colors.tertiary, + foreground: colors.onTertiary, + ), text: "Local Timezone: ${widget.timezone!}", ); } @@ -496,99 +543,111 @@ class UserProfileViewState extends State { return [ if (widget.isSelf) profileMenuItem( - text: promptProfileChangeBanner, - onPressed: () => widget.onSetBanner?.call(), - icon: Icons.image), + text: promptProfileChangeBanner, + onPressed: () => widget.onSetBanner?.call(), + icon: Icons.image, + ), if (widget.isSelf) profileMenuItem( - text: promptProfileSetStatus, - onPressed: () => widget.onSetStatus?.call(), - onClearPressed: widget.presence?.message != null - ? () => widget.clearStatus?.call() - : null, - icon: Icons.short_text), + text: promptProfileSetStatus, + onPressed: () => widget.onSetStatus?.call(), + onClearPressed: widget.presence?.message != null + ? () => widget.clearStatus?.call() + : null, + icon: Icons.short_text, + ), if (widget.isSelf) profileMenuItem( - text: promptProfileSetBadges, - onPressed: () => widget.editBadges?.call(), - icon: Icons.star), + text: promptProfileSetBadges, + onPressed: () => widget.editBadges?.call(), + icon: Icons.star, + ), if (widget.isSelf) profileMenuItem( - text: promptProfileSetBio, - onPressed: () => widget.setBio?.call(), - icon: Icons.text_snippet, - onClearPressed: () => widget.clearBio?.call()), + text: promptProfileSetBio, + onPressed: () => widget.setBio?.call(), + icon: Icons.text_snippet, + onClearPressed: () => widget.clearBio?.call(), + ), if (widget.isSelf) profileMenuItem( - text: promptProfileShareTimezone, - onPressed: () => widget.shareCurrentTimezone?.call(), - icon: Icons.share_arrival_time, - onClearPressed: widget.timezone != null - ? () => widget.removeTimezone?.call() - : null), + text: promptProfileShareTimezone, + onPressed: () => widget.shareCurrentTimezone?.call(), + icon: Icons.share_arrival_time, + onClearPressed: widget.timezone != null + ? () => widget.removeTimezone?.call() + : null, + ), if (widget.isSelf) profileMenuItem( - text: promptProfileEditColorScheme, - onPressed: () => setState(() { - editingColorScheme = true; - }), - icon: Icons.color_lens), + text: promptProfileEditColorScheme, + onPressed: () => setState(() { + editingColorScheme = true; + }), + icon: Icons.color_lens, + ), profileMenuItem( - text: promptProfileSetColorOverride, - onClearPressed: widget.hasColorOverride - ? () => widget.setColorOverride?.call(null) - : null, - onPressed: () async { - var color = await AdaptiveDialog.show( - title: promptProfileSetColorOverride, - context, - builder: (context) { - return SizedBox( - width: 500, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: tiamat.Text.labelLow( - "Set a local color override for a user. This is only visible to you"), + text: promptProfileSetColorOverride, + onClearPressed: widget.hasColorOverride + ? () => widget.setColorOverride?.call(null) + : null, + onPressed: () async { + var color = await AdaptiveDialog.show( + title: promptProfileSetColorOverride, + context, + builder: (context) { + return SizedBox( + width: 500, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: tiamat.Text.labelLow( + "Set a local color override for a user. This is only visible to you", ), - GridView( - shrinkWrap: true, - gridDelegate: - SliverGridDelegateWithFixedCrossAxisCount( - crossAxisSpacing: 3, - mainAxisSpacing: 3, - crossAxisCount: - MediaQuery.of(context).mobile ? 5 : 10), - children: [ - for (int i = 0; i < 20; i++) - buildColorSchemeItem( - color: HSVColor.fromAHSV(1.0, - (i.toDouble() / 21) * 360, 0.8, 1.0) - .toColor(), - onTap: (c) { - Navigator.of(context).pop(c); - }, - ) - ]), - ], - ), - ); - }, - ); + ), + GridView( + shrinkWrap: true, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisSpacing: 3, + mainAxisSpacing: 3, + crossAxisCount: MediaQuery.of(context).mobile ? 5 : 10, + ), + children: [ + for (int i = 0; i < 20; i++) + buildColorSchemeItem( + color: HSVColor.fromAHSV( + 1.0, + (i.toDouble() / 21) * 360, + 0.8, + 1.0, + ).toColor(), + onTap: (c) { + Navigator.of(context).pop(c); + }, + ), + ], + ), + ], + ), + ); + }, + ); - if (color != null) { - widget.setColorOverride?.call(color); - } - }, - icon: Icons.colorize), + if (color != null) { + widget.setColorOverride?.call(color); + } + }, + icon: Icons.colorize, + ), profileMenuItem( text: "Set Nickame", icon: Icons.badge, - onClearPressed: - widget.hasPetName ? () => widget.setPetName?.call(null) : null, + onClearPressed: widget.hasPetName + ? () => widget.setPetName?.call(null) + : null, onPressed: () async { final text = await AdaptiveDialog.textPrompt( context, @@ -596,24 +655,27 @@ class UserProfileViewState extends State { title: "Nickname", ); if (text != null) { - await widget.setPetName - ?.call(text.trim().isEmpty ? null : text.trim()); + await widget.setPetName?.call( + text.trim().isEmpty ? null : text.trim(), + ); } }, ), if (preferences.developerMode.value) profileMenuItem( - text: promptProfileShowRawProfile, - onPressed: () => widget.showSource?.call(), - icon: Icons.code), + text: promptProfileShowRawProfile, + onPressed: () => widget.showSource?.call(), + icon: Icons.code, + ), ]; } - tiamat.ContextMenuItem profileMenuItem( - {required String text, - required IconData icon, - required Function onPressed, - Function? onClearPressed}) { + tiamat.ContextMenuItem profileMenuItem({ + required String text, + required IconData icon, + required Function onPressed, + Function? onClearPressed, + }) { return tiamat.ContextMenuItem( text: text, icon: icon, @@ -632,27 +694,27 @@ class UserProfileViewState extends State { children: [ Expanded( child: InkWell( - onTap: onClicked, - borderRadius: BorderRadius.circular(8), - child: Container( - padding: const EdgeInsets.fromLTRB(4, 8, 4, 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - spacing: 8, - children: [ - Icon( - icon, - color: c, - size: 20, - ), - tiamat.Text(text, - type: tiamat.TextType.body, - maxLines: 1, - color: c), - ], - ))), + onTap: onClicked, + borderRadius: BorderRadius.circular(8), + child: Container( + padding: const EdgeInsets.fromLTRB(4, 8, 4, 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + spacing: 8, + children: [ + Icon(icon, color: c, size: 20), + tiamat.Text( + text, + type: tiamat.TextType.body, + maxLines: 1, + color: c, + ), + ], + ), + ), + ), ), if (onClearPressed != null) tiamat.IconButton( @@ -676,67 +738,77 @@ class UserProfileViewState extends State { var run = 8; var count = run * 2; return Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: Theme.of(context).colorScheme.surfaceContainer, - ), - child: SizedBox( - width: double.infinity, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - GridView( - shrinkWrap: true, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisSpacing: 3, - mainAxisSpacing: 3, - crossAxisCount: run), - children: [ - for (int i = 0; i < count; i++) - buildColorSchemeItem( - color: HSVColor.fromAHSV(1.0, - (i.toDouble() / (count + 1)) * 360, 0.5, 0.8) - .toColor(), - onTap: (c) => widget.setPreviewColor?.call(c), - ), - buildColorSchemeItem( - icon: Icons.light_mode, - onTap: (_) => widget.setPreviewBrightness - ?.call(Brightness.light)), - buildColorSchemeItem( - icon: Icons.dark_mode, - onTap: (_) => widget.setPreviewBrightness - ?.call(Brightness.dark)), - buildColorSchemeItem( - icon: Icons.tag, - onTap: (_) async { - var hexCode = await AdaptiveDialog.textPrompt(context, - title: "Enter Color Code", hintText: "#FFFFFF"); - if (hexCode != null) { - var color = ColorUtils.fromHexCode(hexCode); - widget.setPreviewColor?.call(color); - } - }, - ), + padding: const EdgeInsets.all(8.0), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).colorScheme.surfaceContainer, + ), + child: SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + GridView( + shrinkWrap: true, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisSpacing: 3, + mainAxisSpacing: 3, + crossAxisCount: run, + ), + children: [ + for (int i = 0; i < count; i++) buildColorSchemeItem( - icon: Icons.save, - onTap: (_) { - widget.savePreviewTheme?.call(); - setState(() { - editingColorScheme = false; - }); - }, + color: HSVColor.fromAHSV( + 1.0, + (i.toDouble() / (count + 1)) * 360, + 0.5, + 0.8, + ).toColor(), + onTap: (c) => widget.setPreviewColor?.call(c), ), - ], - ), - ], - ), + buildColorSchemeItem( + icon: Icons.light_mode, + onTap: (_) => + widget.setPreviewBrightness?.call(Brightness.light), + ), + buildColorSchemeItem( + icon: Icons.dark_mode, + onTap: (_) => + widget.setPreviewBrightness?.call(Brightness.dark), + ), + buildColorSchemeItem( + icon: Icons.tag, + onTap: (_) async { + var hexCode = await AdaptiveDialog.textPrompt( + context, + title: "Enter Color Code", + hintText: "#FFFFFF", + ); + if (hexCode != null) { + var color = ColorUtils.fromHexCode(hexCode); + widget.setPreviewColor?.call(color); + } + }, + ), + buildColorSchemeItem( + icon: Icons.save, + onTap: (_) { + widget.savePreviewTheme?.call(); + setState(() { + editingColorScheme = false; + }); + }, + ), + ], + ), + ], ), ), - )); + ), + ), + ); } Widget buildColorSchemeItem({ @@ -769,19 +841,21 @@ class UserProfileViewState extends State { return Padding( padding: const EdgeInsets.fromLTRB(16, 8, 8, 12), child: Container( - decoration: BoxDecoration( - border: BoxBorder.all(color: background, width: 4), - color: Theme.of(context).colorScheme.secondary, - borderRadius: BorderRadius.circular(12)), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: tiamat.Text( - widget.presence!.message!.message, - maxLines: 2, - overflow: TextOverflow.ellipsis, - color: Theme.of(context).colorScheme.onSecondary, - ), - )), + decoration: BoxDecoration( + border: BoxBorder.all(color: background, width: 4), + color: Theme.of(context).colorScheme.secondary, + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: tiamat.Text( + widget.presence!.message!.message, + maxLines: 2, + overflow: TextOverflow.ellipsis, + color: Theme.of(context).colorScheme.onSecondary, + ), + ), + ), ); } @@ -818,30 +892,25 @@ class UserProfileViewState extends State { return tiamat.Tooltip( text: i.body, child: SizedBox( - width: 30, - height: 30, - child: Stack( - children: [ - if (doOutline) - ImageFiltered( - imageFilter: ImageFilter.blur(sigmaX: 1, sigmaY: 1), - child: ColorFiltered( - colorFilter: ColorFilter.mode( - Theme.of(context) - .colorScheme - .inverseSurface - .withAlpha(200), - BlendMode.srcIn), - child: Image( - image: i.image, - ), + width: 30, + height: 30, + child: Stack( + children: [ + if (doOutline) + ImageFiltered( + imageFilter: ImageFilter.blur(sigmaX: 1, sigmaY: 1), + child: ColorFiltered( + colorFilter: ColorFilter.mode( + Theme.of(context).colorScheme.inverseSurface.withAlpha(200), + BlendMode.srcIn, ), + child: Image(image: i.image), ), - Image( - image: i.image, ), - ], - )), + Image(image: i.image), + ], + ), + ), ); } @@ -853,8 +922,9 @@ class UserProfileViewState extends State { child: Text( widget.displayName, style: Theme.of(context).textTheme.headlineSmall?.copyWith( - fontWeight: FontWeight.bold, - color: Theme.of(context).colorScheme.onSurface), + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.onSurface, + ), ), ), ); @@ -883,11 +953,12 @@ class UserProfileViewState extends State { child: InkWell( onTap: widget.isSelf ? () => widget.editBadges?.call() : null, child: Padding( - padding: EdgeInsetsGeometry.fromLTRB(2, 2, 2, 2), - child: Wrap( - spacing: 8, - children: widget.badges.map((i) => buildBadge(i)).toList(), - )), + padding: EdgeInsetsGeometry.fromLTRB(2, 2, 2, 2), + child: Wrap( + spacing: 8, + children: widget.badges.map((i) => buildBadge(i)).toList(), + ), + ), ), ); } diff --git a/commet/lib/ui/organisms/voip_room_view/voip_room_view.dart b/commet/lib/ui/organisms/voip_room_view/voip_room_view.dart index 8c771da75..ae4968bd9 100644 --- a/commet/lib/ui/organisms/voip_room_view/voip_room_view.dart +++ b/commet/lib/ui/organisms/voip_room_view/voip_room_view.dart @@ -84,7 +84,8 @@ class _VoipRoomViewState extends State { mainAxisSize: MainAxisSize.max, children: [ Expanded( - child: widget.voip.room.isE2EE && + child: + widget.voip.room.isE2EE && preferences.experimentEnableE2eeElementCall.value == false ? e2eeUnsupportedView() : joinCallView(), @@ -104,27 +105,27 @@ class _VoipRoomViewState extends State { Icon(Icons.lock, color: Colors.greenAccent), if (!widget.voip.room.isE2EE) Icon(Icons.lock_open, color: Colors.red), - SizedBox( - width: 3, - ), + SizedBox(width: 3), Shimmer( child: ShimmerLoading( - isLoading: callServerUrl == null, - child: callServerUrl == null - ? Container( - height: 16, - width: 150, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: color), - ) - : tiamat.Text.labelLow(callServerUrl!)), + isLoading: callServerUrl == null, + child: callServerUrl == null + ? Container( + height: 16, + width: 150, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: color, + ), + ) + : tiamat.Text.labelLow(callServerUrl!), + ), ), ], ), ), ), - ) + ), ], ); } @@ -135,36 +136,46 @@ class _VoipRoomViewState extends State { children: [ if (participants.isNotEmpty) Expanded( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: BentoLayout(participants.map((item) { - final member = widget.voip.room.getMemberOrFallback(item); - return Container( - clipBehavior: Clip.antiAlias, - decoration: - BoxDecoration(borderRadius: BorderRadius.circular(8)), - child: tiamat.Tile.low( - child: Center( - child: tiamat.Avatar( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: BentoLayout( + participants.map((item) { + final member = widget.voip.room.getMemberOrFallback(item); + return Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + ), + child: tiamat.Tile.low( + child: Center( + child: tiamat.Avatar( radius: 50, image: member.avatar, placeholderColor: member.defaultColor, - placeholderText: member.displayName)), - ), - ); - }).toList()), - )), + placeholderText: member.displayName, + ), + ), + ), + ); + }).toList(), + ), + ), + ), if (participants.isEmpty) Expanded( child: Padding( padding: const EdgeInsets.all(8.0), child: Container( - clipBehavior: Clip.antiAlias, - decoration: - BoxDecoration(borderRadius: BorderRadius.circular(8)), - child: tiamat.Tile.surfaceContainer( - child: Center( - child: tiamat.Text.labelLow("No one's here...")))), + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + ), + child: tiamat.Tile.surfaceContainer( + child: Center( + child: tiamat.Text.labelLow("No one's here..."), + ), + ), + ), ), ), if (widget.voip.canJoinCall) @@ -177,8 +188,10 @@ class _VoipRoomViewState extends State { ), if (!widget.voip.canJoinCall) Center( - child: tiamat.Text.labelLow( - "You do not have permission to join this call")) + child: tiamat.Text.labelLow( + "You do not have permission to join this call", + ), + ), ], ); } @@ -213,10 +226,12 @@ class _VoipRoomViewState extends State { e2eeUnsupportedView() { return Center( - child: Padding( - padding: const EdgeInsets.all(24.0), - child: tiamat.Text.label( - "Sorry, End-to-end encrypted voice rooms are not yet supported."), - )); + child: Padding( + padding: const EdgeInsets.all(24.0), + child: tiamat.Text.label( + "Sorry, End-to-end encrypted voice rooms are not yet supported.", + ), + ), + ); } } diff --git a/commet/lib/ui/pages/bubble/bubble_page.dart b/commet/lib/ui/pages/bubble/bubble_page.dart index e1ac5e38a..9c0f13f19 100644 --- a/commet/lib/ui/pages/bubble/bubble_page.dart +++ b/commet/lib/ui/pages/bubble/bubble_page.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:commet/client/client.dart'; import 'package:commet/client/client_manager.dart'; import 'package:commet/ui/atoms/room_header.dart'; @@ -9,8 +10,12 @@ import 'package:tiamat/tiamat.dart'; import 'package:flutter/material.dart' as material; class BubblePage extends StatefulWidget { - const BubblePage(this.clientManager, - {super.key, this.initialClientId, this.initialRoom}); + const BubblePage( + this.clientManager, { + super.key, + this.initialClientId, + this.initialRoom, + }); final ClientManager clientManager; final String? initialRoom; final String? initialClientId; @@ -62,16 +67,15 @@ class BubblePageState extends State { caulkBorderBottom: true, child: SizedBox( height: 50, - child: RoomHeader( - currentRoom!, - ), + child: RoomHeader(currentRoom!), ), ), Flexible( child: Chat( currentRoom!, key: ValueKey( - "room-timeline-key-${currentRoom!.localId}"), + "room-timeline-key-${currentRoom!.localId}", + ), isBubble: true, ), ), diff --git a/commet/lib/ui/pages/developer/benchmarks/benchmark_utils.dart b/commet/lib/ui/pages/developer/benchmarks/benchmark_utils.dart index d6d19e925..8053d49cb 100644 --- a/commet/lib/ui/pages/developer/benchmarks/benchmark_utils.dart +++ b/commet/lib/ui/pages/developer/benchmarks/benchmark_utils.dart @@ -20,18 +20,17 @@ extension BenchmarkUtils on MatrixClient { 'notification_count': 0, 'highlight_count': 0, 'prev_batch': 'fake_batch_id', - 'summary': { - 'm.joined_member_count': 100, - 'm.invited_member_count': 0, - }, + 'summary': {'m.joined_member_count': 100, 'm.invited_member_count': 0}, }, getMatrixClient()); - mxRoom.setState(matrix.Event.fromJson({ - 'type': 'm.room.member', - 'state_key': _userId, - 'sender': _userId, - 'content': {'display_name': 'Benchy', 'membership': 'join'} - }, mxRoom)); + mxRoom.setState( + matrix.Event.fromJson({ + 'type': 'm.room.member', + 'state_key': _userId, + 'sender': _userId, + 'content': {'display_name': 'Benchy', 'membership': 'join'}, + }, mxRoom), + ); var room = MatrixRoom(this, mxRoom, getMatrixClient()); rooms.add(room); @@ -42,18 +41,24 @@ extension BenchmarkUtils on MatrixClient { extension BenchmarkTimeline on MatrixRoom { MatrixTimeline getBenchmarkTimeline() { int count = 500; - var chunk = c.TimelineChunk(events: [ - for (var i = 0; i < count; i++) createRandomEvent(i, count), - createTestEndEvent(count), + var chunk = c.TimelineChunk( + events: [ + for (var i = 0; i < count; i++) createRandomEvent(i, count), + createTestEndEvent(count), - // create more events so it doent try to fetch more from server - for (var i = 0; i < 50; i++) createRandomEvent(count + 1 + i, count), - ]); + // create more events so it doent try to fetch more from server + for (var i = 0; i < 50; i++) createRandomEvent(count + 1 + i, count), + ], + ); var mxTimeline = matrix.Timeline(chunk: chunk, room: matrixRoom); - return MatrixTimeline(client as MatrixClient, this, matrixRoom, - initialTimeline: mxTimeline); + return MatrixTimeline( + client as MatrixClient, + this, + matrixRoom, + initialTimeline: mxTimeline, + ); } matrix.Event createTestEndEvent(int eventCount) { @@ -65,7 +70,7 @@ extension BenchmarkTimeline on MatrixRoom { 'room_id': matrixRoom.id, 'origin_server_ts': DateTime.now() .subtract(Duration(days: eventCount)) - .millisecondsSinceEpoch + .millisecondsSinceEpoch, }, matrixRoom); return event; @@ -81,8 +86,9 @@ extension BenchmarkTimeline on MatrixRoom { 'event_id': '\$$seed', 'sender': _userId, 'room_id': matrixRoom.id, - 'origin_server_ts': - DateTime.now().subtract(Duration(days: seed)).millisecondsSinceEpoch + 'origin_server_ts': DateTime.now() + .subtract(Duration(days: seed)) + .millisecondsSinceEpoch, }; if (r.nextDouble() < 0.33 && canBeRelatedEvent) { @@ -91,8 +97,8 @@ extension BenchmarkTimeline on MatrixRoom { 'm.relates_to': { 'event_id': relatedEventId, 'rel_type': 'm.annotation', - 'key': r.nextBool() ? 'String Reaction' : "❤️" - } + 'key': r.nextBool() ? 'String Reaction' : "❤️", + }, }; return matrix.Event.fromJson(json, matrixRoom); @@ -115,13 +121,14 @@ extension BenchmarkTimeline on MatrixRoom { if (isThreadReply) 'rel_type': 'm.thread', if (isThreadReply) 'is_falling_back': true, if (isThreadReply == false) - 'm.in_reply_to': {'event_id': relatedEventId} + 'm.in_reply_to': {'event_id': relatedEventId}, }, }, 'sender': _userId, 'room_id': matrixRoom.id, - 'origin_server_ts': - DateTime.now().subtract(Duration(days: seed)).millisecondsSinceEpoch + 'origin_server_ts': DateTime.now() + .subtract(Duration(days: seed)) + .millisecondsSinceEpoch, }, matrixRoom); return event; diff --git a/commet/lib/ui/pages/developer/benchmarks/timeline_viewer_benchmark.dart b/commet/lib/ui/pages/developer/benchmarks/timeline_viewer_benchmark.dart index 6f63b19e8..3548b05b1 100644 --- a/commet/lib/ui/pages/developer/benchmarks/timeline_viewer_benchmark.dart +++ b/commet/lib/ui/pages/developer/benchmarks/timeline_viewer_benchmark.dart @@ -23,8 +23,10 @@ class _BenchmarkTimelineViewerState extends State { void initState() { MatrixClient.create("benchmark").then((client) { client.mockComponents(); - client.self = MatrixProfile(client, - matrix.Profile(userId: '@benchy:matrix.org', displayName: 'benchy')); + client.self = MatrixProfile( + client, + matrix.Profile(userId: '@benchy:matrix.org', displayName: 'benchy'), + ); var room = client.createRoomWithData(); timeline = room.getBenchmarkTimeline(); diff --git a/commet/lib/ui/pages/fatal_error/fatal_error_page.dart b/commet/lib/ui/pages/fatal_error/fatal_error_page.dart index a96fbabb4..74f891fbc 100644 --- a/commet/lib/ui/pages/fatal_error/fatal_error_page.dart +++ b/commet/lib/ui/pages/fatal_error/fatal_error_page.dart @@ -20,16 +20,20 @@ class FatalErrorPage extends StatelessWidget { const Text("Something went wrong!"), Text(error.toString()), const Text( - "Sorry, there was a fatal error and Commet was unable to start. Please copy the error details and report this issue on GitHub"), + "Sorry, there was a fatal error and Commet was unable to start. Please copy the error details and report this issue on GitHub", + ), const Text( - "Make sure to remove any personal/sensitive information before submitting the report!"), + "Make sure to remove any personal/sensitive information before submitting the report!", + ), ElevatedButton( - onPressed: onCopyButtonPressed, - child: const Text("Copy to clipboard")), + onPressed: onCopyButtonPressed, + child: const Text("Copy to clipboard"), + ), ElevatedButton( - onPressed: onReportButtonPressed, - child: const Text("Report Issue")), - Text(trace.toString()) + onPressed: onReportButtonPressed, + child: const Text("Report Issue"), + ), + Text(trace.toString()), ], ), ), diff --git a/commet/lib/ui/pages/get_or_create_room/calendar_views.dart b/commet/lib/ui/pages/get_or_create_room/calendar_views.dart index 29f676ebf..f1f9b296d 100644 --- a/commet/lib/ui/pages/get_or_create_room/calendar_views.dart +++ b/commet/lib/ui/pages/get_or_create_room/calendar_views.dart @@ -50,8 +50,9 @@ class CalendarCreatorDescription extends StatelessWidget { const CalendarCreatorDescription({super.key}); String get labelCalendarDescription => Intl.message( - "Create a shared calendar to keep track of your plans, and import your schedule from other calendars to let your friends know when you are busy.", - name: "labelCalendarDescription"); + "Create a shared calendar to keep track of your plans, and import your schedule from other calendars to let your friends know when you are busy.", + name: "labelCalendarDescription", + ); @override Widget build(BuildContext context) { @@ -59,107 +60,100 @@ class CalendarCreatorDescription extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, children: [ tiamat.Text.labelLow(labelCalendarDescription), - SizedBox( - height: 10, - ), - LayoutBuilder(builder: (context, constraints) { - double width = (constraints.maxWidth / 4) - (10); - return Container( - decoration: BoxDecoration( + SizedBox(height: 10), + LayoutBuilder( + builder: (context, constraints) { + double width = (constraints.maxWidth / 4) - (10); + return Container( + decoration: BoxDecoration( color: ColorScheme.of(context).surfaceContainerLow, - borderRadius: BorderRadius.circular(8)), - child: Padding( - padding: EdgeInsetsGeometry.all(8), - child: Center( - child: Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 8, - children: [ - Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: EdgeInsetsGeometry.all(8), + child: Center( + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 8, + children: [ + Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + buildFakeEvent( + width: width, + height: 100, + text: "Movies", + senderId: "@luna:commet.chat", + ), + SizedBox(height: 40), + buildFakeEvent( + width: width, + height: 100, + text: "Unavailable", + type: "unavailability", + senderId: "@pluto:commet.chat", + ), + SizedBox(height: 20), + buildFakeEvent( + width: width, + height: 50, + text: "Dinner", + senderId: "@pluto:commet.chat", + ), + ], + ), + ), + Column( children: [ + SizedBox(height: 50), buildFakeEvent( width: width, - height: 100, - text: "Movies", + height: 250, + type: "unavailability", + text: "Work", senderId: "@luna:commet.chat", ), - SizedBox( - height: 40, - ), + ], + ), + Column( + children: [ + SizedBox(height: 30), buildFakeEvent( width: width, - height: 100, - text: "Unavailable", + height: 150, type: "unavailability", + text: "work", senderId: "@pluto:commet.chat", ), - SizedBox( - height: 20, - ), + SizedBox(height: 40), buildFakeEvent( width: width, - height: 50, - text: "Dinner", + height: 70, + text: "Gaminggg", senderId: "@pluto:commet.chat", - ) + ), ], ), - ), - Column( - children: [ - SizedBox( - height: 50, - ), - buildFakeEvent( - width: width, - height: 250, - type: "unavailability", - text: "Work", - senderId: "@luna:commet.chat"), - ], - ), - Column( - children: [ - SizedBox( - height: 30, - ), - buildFakeEvent( - width: width, - height: 150, - type: "unavailability", - text: "work", - senderId: "@pluto:commet.chat"), - SizedBox( - height: 40, - ), - buildFakeEvent( - width: width, - height: 70, - text: "Gaminggg", - senderId: "@pluto:commet.chat"), - ], - ), - Column( - children: [ - SizedBox( - height: 170, - ), - buildFakeEvent( + Column( + children: [ + SizedBox(height: 170), + buildFakeEvent( width: width, height: 100, text: "Beach Night", - senderId: "@luna:commet.chat"), - ], - ), - ], + senderId: "@luna:commet.chat", + ), + ], + ), + ], + ), ), ), - ), - ); - }), + ); + }, + ), ], ); } @@ -172,14 +166,16 @@ class CalendarCreatorDescription extends StatelessWidget { String? type, }) { var event = MatrixCalendarEventState( - senderId: senderId, - type: type, - data: RFC8984CalendarEvent( - uid: "12312312", - updated: DateTime.now(), - title: text, - start: DateTime.now(), - duration: Duration(seconds: 5))); + senderId: senderId, + type: type, + data: RFC8984CalendarEvent( + uid: "12312312", + updated: DateTime.now(), + title: text, + start: DateTime.now(), + duration: Duration(seconds: 5), + ), + ); event.loaded = true; var config = FakeCalendarConfig(); @@ -187,8 +183,12 @@ class CalendarCreatorDescription extends StatelessWidget { return SizedBox( height: height, width: width, - child: EventViewBox(event, config, - color: Colors.blue, boundary: Rect.fromLTWH(0, 0, width, height)), + child: EventViewBox( + event, + config, + color: Colors.blue, + boundary: Rect.fromLTWH(0, 0, width, height), + ), ); } } diff --git a/commet/lib/ui/pages/get_or_create_room/existing_room_picker.dart b/commet/lib/ui/pages/get_or_create_room/existing_room_picker.dart index c2cb3cc5b..5afe26878 100644 --- a/commet/lib/ui/pages/get_or_create_room/existing_room_picker.dart +++ b/commet/lib/ui/pages/get_or_create_room/existing_room_picker.dart @@ -8,8 +8,12 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class ExistingRoomPicker extends StatefulWidget { - const ExistingRoomPicker( - {required this.client, this.filter, this.onPicked, super.key}); + const ExistingRoomPicker({ + required this.client, + this.filter, + this.onPicked, + super.key, + }); final Client client; final bool Function(SpaceChild room)? filter; @@ -53,39 +57,47 @@ class _ExistingRoomPickerState extends State { filtered.addAll(allChildren.where((i) => i is SpaceChildSpace)); if (types.contains(RoomType.voipRoom)) - filtered.addAll(allChildren.where((i) { - if (i case SpaceChildRoom r) { - return r.child.getComponent() != null; - } - return false; - })); + filtered.addAll( + allChildren.where((i) { + if (i case SpaceChildRoom r) { + return r.child.getComponent() != null; + } + return false; + }), + ); if (types.contains(RoomType.calendar)) - filtered.addAll(allChildren.where((i) { - if (i case SpaceChildRoom r) { - return r.child - .getComponent() - ?.isCalendarRoom == - true; - } - return false; - })); + filtered.addAll( + allChildren.where((i) { + if (i case SpaceChildRoom r) { + return r.child + .getComponent() + ?.isCalendarRoom == + true; + } + return false; + }), + ); if (types.contains(RoomType.photoAlbum)) - filtered.addAll(allChildren.where((i) { - if (i case SpaceChildRoom r) { - return r.child.getComponent() != null; - } - return false; - })); + filtered.addAll( + allChildren.where((i) { + if (i case SpaceChildRoom r) { + return r.child.getComponent() != null; + } + return false; + }), + ); if (types.contains(RoomType.defaultRoom)) - filtered.addAll(allChildren.where((i) { - if (i case SpaceChildRoom r) { - return r.child.isSpecialRoomType == false; - } - return false; - })); + filtered.addAll( + allChildren.where((i) { + if (i case SpaceChildRoom r) { + return r.child.isSpecialRoomType == false; + } + return false; + }), + ); } setState(() { @@ -101,37 +113,38 @@ class _ExistingRoomPickerState extends State { Padding( padding: EdgeInsetsGeometry.all(8), child: SegmentedButton( - emptySelectionAllowed: true, - multiSelectionEnabled: false, - segments: [ - ButtonSegment( - tooltip: RoomCreationStrings.labelRoomTypeSpace, - value: RoomType.space, - icon: Icon(Icons.spoke), - ), - ButtonSegment( - tooltip: RoomCreationStrings.labelRoomTypeTextChat, - value: RoomType.defaultRoom, - icon: Icon(Icons.tag), - ), - ButtonSegment( - tooltip: RoomCreationStrings.labelRoomTypeVoiceChat, - value: RoomType.voipRoom, - icon: Icon(Icons.volume_up), - ), - ButtonSegment( - tooltip: RoomCreationStrings.labelRoomTypePhotoAlbum, - value: RoomType.photoAlbum, - icon: Icon(Icons.photo), - ), - ButtonSegment( - tooltip: RoomCreationStrings.labelRoomTypeCalendar, - value: RoomType.calendar, - icon: Icon(Icons.calendar_month), - ), - ], - onSelectionChanged: setSelectedTypes, - selected: selectedTypes), + emptySelectionAllowed: true, + multiSelectionEnabled: false, + segments: [ + ButtonSegment( + tooltip: RoomCreationStrings.labelRoomTypeSpace, + value: RoomType.space, + icon: Icon(Icons.spoke), + ), + ButtonSegment( + tooltip: RoomCreationStrings.labelRoomTypeTextChat, + value: RoomType.defaultRoom, + icon: Icon(Icons.tag), + ), + ButtonSegment( + tooltip: RoomCreationStrings.labelRoomTypeVoiceChat, + value: RoomType.voipRoom, + icon: Icon(Icons.volume_up), + ), + ButtonSegment( + tooltip: RoomCreationStrings.labelRoomTypePhotoAlbum, + value: RoomType.photoAlbum, + icon: Icon(Icons.photo), + ), + ButtonSegment( + tooltip: RoomCreationStrings.labelRoomTypeCalendar, + value: RoomType.calendar, + icon: Icon(Icons.calendar_month), + ), + ], + onSelectionChanged: setSelectedTypes, + selected: selectedTypes, + ), ), Flexible( child: ListView.builder( @@ -174,15 +187,12 @@ class _ExistingRoomPickerState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Avatar( - image: avatar, - placeholderText: displayName, - placeholderColor: color), - SizedBox( - width: 8, + image: avatar, + placeholderText: displayName, + placeholderColor: color, ), - Column( - children: [tiamat.Text.label(displayName)], - ) + SizedBox(width: 8), + Column(children: [tiamat.Text.label(displayName)]), ], ), ), diff --git a/commet/lib/ui/pages/get_or_create_room/get_or_create_room.dart b/commet/lib/ui/pages/get_or_create_room/get_or_create_room.dart index 166c82b67..85223eb8d 100644 --- a/commet/lib/ui/pages/get_or_create_room/get_or_create_room.dart +++ b/commet/lib/ui/pages/get_or_create_room/get_or_create_room.dart @@ -21,7 +21,7 @@ class RoomGetter { final IconData icon; final Widget Function(BuildContext context) descriptionBuilder; final Widget Function(BuildContext context, {Function(SpaceChild)? onPicked}) - formBuilder; + formBuilder; final Future Function(CreateRoomArgs args)? create; final bool hero; @@ -39,8 +39,12 @@ class RoomGetter { enum _RoomSourceOptions { create, existing, join } class GetOrCreateRoom extends StatefulWidget { - const GetOrCreateRoom( - {super.key, required this.creators, this.existing, this.join}); + const GetOrCreateRoom({ + super.key, + required this.creators, + this.existing, + this.join, + }); final List creators; final RoomGetter? existing; @@ -62,9 +66,7 @@ class GetOrCreateRoom extends StatefulWidget { bool Function(SpaceChild child)? existingRoomsRemoveWhere, }) async { if (client == null) { - client = await AdaptiveDialog.pickClient( - context, - ); + client = await AdaptiveDialog.pickClient(context); } if (client == null) { @@ -83,7 +85,9 @@ class GetOrCreateRoom extends StatefulWidget { RoomFieldTopic(), RoomFieldVisibility(client: client!, currentSpace: currentSpace), RoomFieldEncryption( - canEnableEncryption: true, defaultEnabled: true), + canEnableEncryption: true, + defaultEnabled: true, + ), ], ), create: (args) async { @@ -101,7 +105,9 @@ class GetOrCreateRoom extends StatefulWidget { RoomFieldTopic(), RoomFieldVisibility(client: client!, currentSpace: currentSpace), RoomFieldEncryption( - canEnableEncryption: false, defaultEnabled: false), + canEnableEncryption: false, + defaultEnabled: false, + ), RoomFieldType(RoomType.voipRoom), ], ), @@ -197,32 +203,34 @@ class GetOrCreateRoom extends StatefulWidget { if (initialRoomAddress != null) { source = _RoomSourceOptions.join; } else { - source = await AdaptiveDialog.pickOne(context, - items: [ - _RoomSourceOptions.create, - if (existing != null) _RoomSourceOptions.existing, - if (join != null) _RoomSourceOptions.join, - ], - itemBuilder: (context, item, callback) => SizedBox( - height: 50, - child: switch (item) { - _RoomSourceOptions.create => tiamat.TextButton( - RoomCreationStrings.labelCreateRoom, - icon: Icons.add, - onTap: callback, - ), - _RoomSourceOptions.existing => tiamat.TextButton( - RoomCreationStrings.labelPickExistingRoom, - icon: Icons.tag, - onTap: callback, - ), - _RoomSourceOptions.join => tiamat.TextButton( - RoomCreationStrings.labelJoinRoom, - icon: Icons.alternate_email, - onTap: callback, - ), - }, - )); + source = await AdaptiveDialog.pickOne( + context, + items: [ + _RoomSourceOptions.create, + if (existing != null) _RoomSourceOptions.existing, + if (join != null) _RoomSourceOptions.join, + ], + itemBuilder: (context, item, callback) => SizedBox( + height: 50, + child: switch (item) { + _RoomSourceOptions.create => tiamat.TextButton( + RoomCreationStrings.labelCreateRoom, + icon: Icons.add, + onTap: callback, + ), + _RoomSourceOptions.existing => tiamat.TextButton( + RoomCreationStrings.labelPickExistingRoom, + icon: Icons.tag, + onTap: callback, + ), + _RoomSourceOptions.join => tiamat.TextButton( + RoomCreationStrings.labelJoinRoom, + icon: Icons.alternate_email, + onTap: callback, + ), + }, + ), + ); } if (source == _RoomSourceOptions.create) { @@ -230,9 +238,7 @@ class GetOrCreateRoom extends StatefulWidget { context, scrollable: false, builder: (context) { - return GetOrCreateRoom( - creators: creators, - ); + return GetOrCreateRoom(creators: creators); }, ); } @@ -242,8 +248,10 @@ class GetOrCreateRoom extends StatefulWidget { context, scrollable: false, builder: (context) { - return join!.formBuilder(context, - onPicked: (i) => Navigator.of(context).pop(i)); + return join!.formBuilder( + context, + onPicked: (i) => Navigator.of(context).pop(i), + ); }, ); } @@ -254,9 +262,12 @@ class GetOrCreateRoom extends StatefulWidget { scrollable: false, builder: (context) { return SizedBox( - height: 500, - child: existing!.formBuilder(context, - onPicked: (i) => Navigator.of(context).pop(i))); + height: 500, + child: existing!.formBuilder( + context, + onPicked: (i) => Navigator.of(context).pop(i), + ), + ); }, ); } @@ -309,23 +320,30 @@ class _GetOrCreateRoomState extends State { return SizedBox( height: 500, child: buildListViewEntry( - widget.creators.first, context, constraints.maxWidth), + widget.creators.first, + context, + constraints.maxWidth, + ), ); return Container( child: ClipRRect( borderRadius: BorderRadiusGeometry.circular(8), child: SizedBox( - height: 500, - child: ListView( - padding: EdgeInsets.zero, - scrollDirection: Axis.horizontal, - children: [ - for (var entry in widget.creators) - buildListViewEntry( - entry, context, constraints.maxWidth - 150) - ], - )), + height: 500, + child: ListView( + padding: EdgeInsets.zero, + scrollDirection: Axis.horizontal, + children: [ + for (var entry in widget.creators) + buildListViewEntry( + entry, + context, + constraints.maxWidth - 150, + ), + ], + ), + ), ), ); }, @@ -360,80 +378,88 @@ class _GetOrCreateRoomState extends State { if (widget.join != null) createEntry(widget.join!), if (widget.creators.isNotEmpty) tiamat.Text.labelLow("Create Room:"), - for (var entry in widget.creators) createEntry(entry) + for (var entry in widget.creators) createEntry(entry), ], ), ), ), if (selected != null) Flexible( - child: Container( - decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainerLowest, - borderRadius: BorderRadius.circular(8), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - selected!.label, - style: TextTheme.of(context).headlineSmall, - ), - if (!selected!.hero) - Expanded( - child: SingleChildScrollView( - physics: NeverScrollableScrollPhysics(), - child: Padding( - padding: - EdgeInsetsGeometry.fromLTRB(0, 0, 0, 0), - child: - selected!.descriptionBuilder(context), + child: Container( + decoration: BoxDecoration( + color: ColorScheme.of(context).surfaceContainerLowest, + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + selected!.label, + style: TextTheme.of(context).headlineSmall, + ), + if (!selected!.hero) + Expanded( + child: SingleChildScrollView( + physics: NeverScrollableScrollPhysics(), + child: Padding( + padding: EdgeInsetsGeometry.fromLTRB( + 0, + 0, + 0, + 0, + ), + child: selected!.descriptionBuilder( + context, + ), + ), ), ), - ), - if (selected!.hero) - Expanded( + if (selected!.hero) + Expanded( child: selected!.formBuilder( - context, - onPicked: onExistingRoomPicked, - )), - if (!selected!.hero) - Align( - alignment: AlignmentGeometry.bottomRight, - child: tiamat.Button( - text: CommonStrings.promptNext, - onTap: () { - onNextButtonPressed(selected!); - }, + context, + onPicked: onExistingRoomPicked, + ), + ), + if (!selected!.hero) + Align( + alignment: AlignmentGeometry.bottomRight, + child: tiamat.Button( + text: CommonStrings.promptNext, + onTap: () { + onNextButtonPressed(selected!); + }, + ), ), - ) - ], + ], + ), ), ), - )) + ), ], ), ), ), - if (loading) - Center( - child: CircularProgressIndicator(), - ) + if (loading) Center(child: CircularProgressIndicator()), ], ), ); } Widget buildListViewEntry( - RoomGetter entry, BuildContext context, double width) { + RoomGetter entry, + BuildContext context, + double width, + ) { return Padding( padding: const EdgeInsets.fromLTRB(0, 0, 12, 0), child: Container( decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainerLowest, - borderRadius: BorderRadius.circular(8)), + color: ColorScheme.of(context).surfaceContainerLowest, + borderRadius: BorderRadius.circular(8), + ), child: SizedBox( height: 100, child: Padding( @@ -442,24 +468,15 @@ class _GetOrCreateRoomState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - entry.label, - style: TextTheme.of(context).headlineSmall, - ), + Text(entry.label, style: TextTheme.of(context).headlineSmall), Expanded( child: ShaderMask( shaderCallback: (bounds) { return const LinearGradient( end: Alignment(0, 0.7), begin: Alignment(0, 1), - colors: [ - Colors.purple, - Colors.transparent, - ], - stops: [ - 0.0, - 1.0, - ], + colors: [Colors.purple, Colors.transparent], + stops: [0.0, 1.0], ).createShader(bounds); }, blendMode: BlendMode.dstOut, @@ -482,7 +499,7 @@ class _GetOrCreateRoomState extends State { onTap: () => onNextButtonPressed(entry), ), ), - ) + ), ], ), ), diff --git a/commet/lib/ui/pages/get_or_create_room/join_room_view.dart b/commet/lib/ui/pages/get_or_create_room/join_room_view.dart index 3b7fc86fb..dd4ca4785 100644 --- a/commet/lib/ui/pages/get_or_create_room/join_room_view.dart +++ b/commet/lib/ui/pages/get_or_create_room/join_room_view.dart @@ -8,11 +8,13 @@ import 'package:intl/intl.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class JoinRoomView extends StatefulWidget { - const JoinRoomView(this.client, - {required this.asSpace, - this.onPicked, - this.initialRoomAddress, - super.key}); + const JoinRoomView( + this.client, { + required this.asSpace, + this.onPicked, + this.initialRoomAddress, + super.key, + }); final Client client; final String? initialRoomAddress; final bool asSpace; @@ -33,22 +35,22 @@ class _JoinRoomViewState extends State { late TextEditingController controller; String get promptConfirmRoomJoin => Intl.message( - "Join Room!", - name: "promptConfirmRoomJoin", - desc: "Label for a button which confirms the joining of a room", - ); + "Join Room!", + name: "promptConfirmRoomJoin", + desc: "Label for a button which confirms the joining of a room", + ); String get promptRoomAddress => Intl.message( - "Room Address", - name: "promptRoomAddress", - desc: "Short label to prompt for the input of a room address", - ); + "Room Address", + name: "promptRoomAddress", + desc: "Short label to prompt for the input of a room address", + ); String get placeholderRoomAlias => Intl.message( - "#awesome-room", - name: "placeholderRoomAlias", - desc: "Placeholder / Example for a room alias.", - ); + "#awesome-room", + name: "placeholderRoomAlias", + desc: "Placeholder / Example for a room alias.", + ); @override void initState() { @@ -71,23 +73,25 @@ class _JoinRoomViewState extends State { TextField( controller: controller, decoration: InputDecoration( - label: Text(promptRoomAddress), - hint: tiamat.Text.labelLow(placeholderRoomAlias)), + label: Text(promptRoomAddress), + hint: tiamat.Text.labelLow(placeholderRoomAlias), + ), onChanged: (value) { onTextChanged(value); }, ), Flexible( child: SizedBox( - height: 200, - child: loading - ? Center(child: CircularProgressIndicator()) - : preview != null - ? Padding( - padding: const EdgeInsets.all(8.0), - child: RoomPreviewView(previewData: preview!), - ) - : Container()), + height: 200, + child: loading + ? Center(child: CircularProgressIndicator()) + : preview != null + ? Padding( + padding: const EdgeInsets.all(8.0), + child: RoomPreviewView(previewData: preview!), + ) + : Container(), + ), ), ], ), @@ -108,7 +112,7 @@ class _JoinRoomViewState extends State { widget.onPicked?.call(result); }, - ) + ), ], ); } diff --git a/commet/lib/ui/pages/get_or_create_room/photo_album_views.dart b/commet/lib/ui/pages/get_or_create_room/photo_album_views.dart index 74db28289..48632376a 100644 --- a/commet/lib/ui/pages/get_or_create_room/photo_album_views.dart +++ b/commet/lib/ui/pages/get_or_create_room/photo_album_views.dart @@ -9,22 +9,27 @@ class PhotoAlbumCreatorDescription extends StatelessWidget { final images = const [ AssetImage("assets/images/placeholders/photos/pexels-fr3nks-287229.jpg"), AssetImage( - "assets/images/placeholders/photos/pexels-stijn-dijkstra-1306815-16747816.jpg"), + "assets/images/placeholders/photos/pexels-stijn-dijkstra-1306815-16747816.jpg", + ), AssetImage("assets/images/placeholders/photos/pexels-rdne-8474967.jpg"), AssetImage( - "assets/images/placeholders/photos/pexels-james-lee-932763-2017111.jpg"), + "assets/images/placeholders/photos/pexels-james-lee-932763-2017111.jpg", + ), AssetImage( - "assets/images/placeholders/photos/pexels-kostiantyn-35582290.jpg"), + "assets/images/placeholders/photos/pexels-kostiantyn-35582290.jpg", + ), AssetImage( - "assets/images/placeholders/photos/pexels-mikhail-nilov-8221589.jpg"), + "assets/images/placeholders/photos/pexels-mikhail-nilov-8221589.jpg", + ), AssetImage("assets/images/placeholders/photos/pexels-nivdex-796206.jpg"), AssetImage("assets/images/placeholders/photos/pexels-krisof-1252873.jpg"), AssetImage("assets/images/placeholders/photos/pexels-byrahul-2162909.jpg"), ]; - String get labelPhotoAlbumDescription => - Intl.message("Share photos and videos with your friends or community!", - name: "labelPhotoAlbumDescription"); + String get labelPhotoAlbumDescription => Intl.message( + "Share photos and videos with your friends or community!", + name: "labelPhotoAlbumDescription", + ); @override Widget build(BuildContext context) { @@ -33,9 +38,7 @@ class PhotoAlbumCreatorDescription extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text.labelLow(labelPhotoAlbumDescription), - SizedBox( - height: 30, - ), + SizedBox(height: 30), MasonryGridView.extent( shrinkWrap: true, maxCrossAxisExtent: 170, @@ -44,10 +47,11 @@ class PhotoAlbumCreatorDescription extends StatelessWidget { itemCount: images.length, itemBuilder: (context, index) { return ClipRRect( - borderRadius: BorderRadiusGeometry.circular(8), - child: Image(image: images[index])); + borderRadius: BorderRadiusGeometry.circular(8), + child: Image(image: images[index]), + ); }, - ) + ), ], ); } diff --git a/commet/lib/ui/pages/get_or_create_room/room_creation_strings.dart b/commet/lib/ui/pages/get_or_create_room/room_creation_strings.dart index d52b01445..12e1cf62b 100644 --- a/commet/lib/ui/pages/get_or_create_room/room_creation_strings.dart +++ b/commet/lib/ui/pages/get_or_create_room/room_creation_strings.dart @@ -4,37 +4,27 @@ class RoomCreationStrings { static String get labelCreateRoom => Intl.message("Create Room", name: "labelCreateRoom"); - static String get labelPickExistingRoom => Intl.message( - "Existing Room", - name: "labelPickExistingRoom", - ); - - static String get labelJoinRoom => Intl.message( - "Join Room", - name: "labelJoinRoom", - ); - - static String get labelRoomTypeTextChat => Intl.message("Text Chat", - name: "labelRoomTypeTextChat", - desc: "Label for creating a regular text based chat room"); - - static String get labelRoomTypeVoiceChat => Intl.message( - "Voice Chat", - name: "labelRoomTypeVoiceChat", - ); - - static String get labelRoomTypePhotoAlbum => Intl.message( - "Photo Album", - name: "labelRoomTypePhotoAlbum", - ); - - static String get labelRoomTypeCalendar => Intl.message( - "Calendar", - name: "labelRoomTypeCalendar", - ); - - static String get labelRoomTypeSpace => Intl.message( - "Space", - name: "labelRoomTypeSpace", - ); + static String get labelPickExistingRoom => + Intl.message("Existing Room", name: "labelPickExistingRoom"); + + static String get labelJoinRoom => + Intl.message("Join Room", name: "labelJoinRoom"); + + static String get labelRoomTypeTextChat => Intl.message( + "Text Chat", + name: "labelRoomTypeTextChat", + desc: "Label for creating a regular text based chat room", + ); + + static String get labelRoomTypeVoiceChat => + Intl.message("Voice Chat", name: "labelRoomTypeVoiceChat"); + + static String get labelRoomTypePhotoAlbum => + Intl.message("Photo Album", name: "labelRoomTypePhotoAlbum"); + + static String get labelRoomTypeCalendar => + Intl.message("Calendar", name: "labelRoomTypeCalendar"); + + static String get labelRoomTypeSpace => + Intl.message("Space", name: "labelRoomTypeSpace"); } diff --git a/commet/lib/ui/pages/get_or_create_room/room_creator.dart b/commet/lib/ui/pages/get_or_create_room/room_creator.dart index edfc9ae98..c10cbf85e 100644 --- a/commet/lib/ui/pages/get_or_create_room/room_creator.dart +++ b/commet/lib/ui/pages/get_or_create_room/room_creator.dart @@ -36,10 +36,10 @@ class RoomFieldType implements RoomField { class RoomFieldName implements RoomField { String get promptRoomName => Intl.message( - "Room Name", - name: "promptRoomName", - desc: "Prompt to enter a room name, placeholder text for text input", - ); + "Room Name", + name: "promptRoomName", + desc: "Prompt to enter a room name, placeholder text for text input", + ); @override Widget build(CreateRoomArgs args, Function() onArgsChanged) { @@ -63,11 +63,10 @@ class RoomFieldName implements RoomField { class RoomFieldTopic implements RoomField { String get promptTopic => Intl.message( - "Topic (Optional)", - name: "promptTopic", - desc: - "Prompt to enter a topic for room or space, specifying that doing so is optional", - ); + "Topic (Optional)", + name: "promptTopic", + desc: "Prompt to enter a topic for room or space, specifying that doing so is optional", + ); @override Widget build(CreateRoomArgs args, Function() onArgsChanged) { @@ -95,19 +94,21 @@ class RoomFieldEncryption implements RoomField { final bool defaultEnabled; String get promptEnableEncryption => Intl.message( - "Enable Encryption", - name: "promptEnableEncryption", - desc: "Short prompt to enable encryption for a room", - ); + "Enable Encryption", + name: "promptEnableEncryption", + desc: "Short prompt to enable encryption for a room", + ); String get encryptionCannotBeDisabledExplanation => Intl.message( - "If enabled, encryption cannot be disabled later", - name: "encryptionCannotBeDisabledExplanation", - desc: "Explains that encryption cannot be disabled once enabled", - ); + "If enabled, encryption cannot be disabled later", + name: "encryptionCannotBeDisabledExplanation", + desc: "Explains that encryption cannot be disabled once enabled", + ); - RoomFieldEncryption( - {required this.defaultEnabled, this.canEnableEncryption = true}); + RoomFieldEncryption({ + required this.defaultEnabled, + this.canEnableEncryption = true, + }); @override Widget build(CreateRoomArgs args, Function() onArgsChanged) { @@ -122,7 +123,7 @@ class RoomFieldEncryption implements RoomField { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text.label(promptEnableEncryption), - tiamat.Text.labelLow(encryptionCannotBeDisabledExplanation) + tiamat.Text.labelLow(encryptionCannotBeDisabledExplanation), ], ), tiamat.Switch( @@ -131,7 +132,7 @@ class RoomFieldEncryption implements RoomField { args.enableE2EE = value; onArgsChanged(); }, - ) + ), ], ), ), @@ -139,8 +140,9 @@ class RoomFieldEncryption implements RoomField { if (!canEnableEncryption) { result = tiamat.Tooltip( - child: result, - text: "Sorry, Encryption is not yet supported on this type of room"); + child: result, + text: "Sorry, Encryption is not yet supported on this type of room", + ); } return result; @@ -164,40 +166,40 @@ class RoomFieldVisibility implements RoomField { RoomFieldVisibility({required this.client, this.currentSpace}); static String get roomVisibilityPrivateExplanation => Intl.message( - "This room will only be accessible by invitation", - name: "roomVisibilityPrivateExplanation", - desc: "Explains what 'private' room visibility means", - ); + "This room will only be accessible by invitation", + name: "roomVisibilityPrivateExplanation", + desc: "Explains what 'private' room visibility means", + ); static String get roomVisibilityPublicExplanation => Intl.message( - "This room will be publically accessible by anyone on the internet", - name: "roomVisibilityPublicExplanation", - desc: "Explains what 'public' visibility means", - ); + "This room will be publically accessible by anyone on the internet", + name: "roomVisibilityPublicExplanation", + desc: "Explains what 'public' visibility means", + ); static String get labelVisibilityPrivate => Intl.message( - "Private", - name: "labelVisibilityPrivate", - desc: "Short label for room visibility private", - ); + "Private", + name: "labelVisibilityPrivate", + desc: "Short label for room visibility private", + ); static String get labelVisibilityPublic => Intl.message( - "Public", - name: "labelVisibilityPublic", - desc: "Short label for room visibility public", - ); + "Public", + name: "labelVisibilityPublic", + desc: "Short label for room visibility public", + ); static String get roomVisibilityRestrictedExplanation => Intl.message( - "This room will be available to anyone who is a member of it's parent spaces", - name: "roomVisibilityRestrictedExplanation", - desc: "Explains what 'restricted' visibility means", - ); + "This room will be available to anyone who is a member of it's parent spaces", + name: "roomVisibilityRestrictedExplanation", + desc: "Explains what 'restricted' visibility means", + ); static String get labelVisibilityRestricted => Intl.message( - "Restricted", - name: "labelVisibilityRestricted", - desc: "Short label for room visibility restricted", - ); + "Restricted", + name: "labelVisibilityRestricted", + desc: "Short label for room visibility restricted", + ); @override void setDefaults(CreateRoomArgs args) { @@ -224,7 +226,7 @@ class RoomFieldVisibility implements RoomField { RoomVisibilityPrivate(), RoomVisibilityPublic(), if (currentSpace != null) - RoomVisibilityRestricted([currentSpace!.identifier]) + RoomVisibilityRestricted([currentSpace!.identifier]), ], onItemSelected: (item) { args.visibility = item; @@ -255,11 +257,12 @@ class RoomFieldVisibility implements RoomField { subtitle = roomVisibilityRestrictedExplanation; icon = Row( - spacing: 4, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - for (var i in restricted.spaces) buildSpaceIcon(client, i), - ]); + spacing: 4, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + for (var i in restricted.spaces) buildSpaceIcon(client, i), + ], + ); break; case null: break; @@ -287,10 +290,7 @@ class RoomFieldVisibility implements RoomField { ], ), ), - tiamat.Text.labelLow( - subtitle!, - overflow: TextOverflow.fade, - ), + tiamat.Text.labelLow(subtitle!, overflow: TextOverflow.fade), ], ), ); @@ -302,10 +302,11 @@ class RoomFieldVisibility implements RoomField { return tiamat.Tooltip( text: space?.displayName ?? i, child: tiamat.Avatar( - radius: 13, - image: space?.avatar, - placeholderText: space?.displayName ?? i, - placeholderColor: space?.color ?? MatrixPeer.hashColor(i)), + radius: 13, + image: space?.avatar, + placeholderText: space?.displayName ?? i, + placeholderColor: space?.color ?? MatrixPeer.hashColor(i), + ), ); } } @@ -324,10 +325,10 @@ class _RoomCreatorWidgetState extends State { bool valid = false; String get promptConfirmRoomCreation => Intl.message( - "Create Room!", - name: "promptConfirmRoomCreation", - desc: "Label for a button which confirms the creation of a room", - ); + "Create Room!", + name: "promptConfirmRoomCreation", + desc: "Label for a button which confirms the creation of a room", + ); @override void initState() { @@ -356,7 +357,7 @@ class _RoomCreatorWidgetState extends State { }, ), ), - ) + ), ], ), ); diff --git a/commet/lib/ui/pages/get_or_create_room/space_views.dart b/commet/lib/ui/pages/get_or_create_room/space_views.dart index 743dab1b8..637589e18 100644 --- a/commet/lib/ui/pages/get_or_create_room/space_views.dart +++ b/commet/lib/ui/pages/get_or_create_room/space_views.dart @@ -24,32 +24,25 @@ class SpaceCreatorDescription extends StatelessWidget { final voiceChannelNames = ["Gaming", "Movie Night"]; - final photoAlbumNames = [ - "Random Photo Dump", - "Clips", - "Art", - ]; + final photoAlbumNames = ["Random Photo Dump", "Clips", "Art"]; - final calendarNames = [ - "Calendar", - "Work Schedule", - ]; + final calendarNames = ["Calendar", "Work Schedule"]; @override Widget build(BuildContext context) { return Column( children: [ tiamat.Text.labelLow( - "Spaces are a collection of rooms, they can contain text chats, voice chats and more! They are the perfect way to organize your community or group!"), - SizedBox( - height: 30, + "Spaces are a collection of rooms, they can contain text chats, voice chats and more! They are the perfect way to organize your community or group!", ), + SizedBox(height: 30), Wrap( - clipBehavior: Clip.hardEdge, - alignment: WrapAlignment.spaceEvenly, - runSpacing: 24, - spacing: 24, - children: buildItems(context)) + clipBehavior: Clip.hardEdge, + alignment: WrapAlignment.spaceEvenly, + runSpacing: 24, + spacing: 24, + children: buildItems(context), + ), ], ); } @@ -72,37 +65,35 @@ class SpaceCreatorDescription extends StatelessWidget { } Widget buildSpaceChild( - BuildContext context, String name, IconData icon, int seed) { + BuildContext context, + String name, + IconData icon, + int seed, + ) { var random = Random(seed); var color = MatrixMember.hashColor(seed.toString()); color = tiamat.Text.adjustColor(context, color); return Transform.rotate( angle: (random.nextDouble() - 0.5) * 0.2, child: Material( - color: ColorScheme.of(context).surfaceContainerLow, - borderRadius: BorderRadius.circular(8), - clipBehavior: Clip.antiAlias, - child: InkWell( - onTap: () {}, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisSize: MainAxisSize.min, - spacing: 8, - children: [ - Icon( - icon, - color: color, - ), - tiamat.Text( - name, - color: color, - autoAdjustBrightness: false, - ) - ], - ), + color: ColorScheme.of(context).surfaceContainerLow, + borderRadius: BorderRadius.circular(8), + clipBehavior: Clip.antiAlias, + child: InkWell( + onTap: () {}, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisSize: MainAxisSize.min, + spacing: 8, + children: [ + Icon(icon, color: color), + tiamat.Text(name, color: color, autoAdjustBrightness: false), + ], ), - )), + ), + ), + ), ); } } diff --git a/commet/lib/ui/pages/get_or_create_room/text_chat_views.dart b/commet/lib/ui/pages/get_or_create_room/text_chat_views.dart index 9a6f0a53d..bd64b28ad 100644 --- a/commet/lib/ui/pages/get_or_create_room/text_chat_views.dart +++ b/commet/lib/ui/pages/get_or_create_room/text_chat_views.dart @@ -11,70 +11,93 @@ class TextChatCreatorDescription extends StatelessWidget { const TextChatCreatorDescription({super.key}); String get labelTextChatDescription => Intl.message( - "Simple text chat, with all the features you could want! Send messages, media, stickers, GIFs and more!", - name: "labelTextChatDescription"); + "Simple text chat, with all the features you could want! Send messages, media, stickers, GIFs and more!", + name: "labelTextChatDescription", + ); @override Widget build(BuildContext context) { - return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - tiamat.Text.labelLow(labelTextChatDescription), - SizedBox( - height: 16, - ), - Column( - children: [ - TimelineEventLayoutMessage( - senderName: "pluto", - timestamp: "8:17", - senderColor: Colors.pinkAccent.shade400, - senderAvatar: AssetImage("assets/images/placeholders/avatar1.jpg"), - formattedContent: tiamat.Text.body("This guy is a serial gamer"), - ), - TimelineEventLayoutMessage( - senderName: "luna", - timestamp: "8:30", - senderAvatar: AssetImage("assets/images/placeholders/avatar2.jpg"), - senderColor: Colors.cyanAccent, - formattedContent: tiamat.Text.body("Gotta stay on that grind"), - ), - TimelineEventLayoutMessage( - senderName: "luna", - timestamp: "8:31", - senderColor: Colors.cyanAccent, - senderAvatar: AssetImage("assets/images/placeholders/avatar2.jpg"), - formattedContent: tiamat.Text.body("u still wanna play smth?"), - ), - TimelineEventLayoutMessage( - senderName: "pluto", - timestamp: "8:35", - senderColor: Colors.pinkAccent.shade400, - senderAvatar: AssetImage("assets/images/placeholders/avatar1.jpg"), - formattedContent: - tiamat.Text.body("yea just gimme 1 sec im eating icecream 😋"), - reactions: - EmojiReaction(emoji: UnicodeEmoticon("🔥"), numReactions: 1), - ) - ] - .mapIndexed((e, i) => Padding( - padding: const EdgeInsets.all(8.0), - child: Transform.rotate( - angle: (Random((i + 12) * 7).nextDouble() - 0.5) * 0.04, - child: Material( - borderRadius: BorderRadius.circular(12), - clipBehavior: Clip.antiAlias, - color: ColorScheme.of(context).surfaceContainerLow, - child: InkWell( - onTap: () {}, - child: Padding( - padding: EdgeInsets.all(8), - child: e, + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + tiamat.Text.labelLow(labelTextChatDescription), + SizedBox(height: 16), + Column( + children: + [ + TimelineEventLayoutMessage( + senderName: "pluto", + timestamp: "8:17", + senderColor: Colors.pinkAccent.shade400, + senderAvatar: AssetImage( + "assets/images/placeholders/avatar1.jpg", + ), + formattedContent: tiamat.Text.body( + "This guy is a serial gamer", + ), + ), + TimelineEventLayoutMessage( + senderName: "luna", + timestamp: "8:30", + senderAvatar: AssetImage( + "assets/images/placeholders/avatar2.jpg", + ), + senderColor: Colors.cyanAccent, + formattedContent: tiamat.Text.body( + "Gotta stay on that grind", + ), + ), + TimelineEventLayoutMessage( + senderName: "luna", + timestamp: "8:31", + senderColor: Colors.cyanAccent, + senderAvatar: AssetImage( + "assets/images/placeholders/avatar2.jpg", + ), + formattedContent: tiamat.Text.body( + "u still wanna play smth?", + ), + ), + TimelineEventLayoutMessage( + senderName: "pluto", + timestamp: "8:35", + senderColor: Colors.pinkAccent.shade400, + senderAvatar: AssetImage( + "assets/images/placeholders/avatar1.jpg", + ), + formattedContent: tiamat.Text.body( + "yea just gimme 1 sec im eating icecream 😋", + ), + reactions: EmojiReaction( + emoji: UnicodeEmoticon("🔥"), + numReactions: 1, + ), + ), + ] + .mapIndexed( + (e, i) => Padding( + padding: const EdgeInsets.all(8.0), + child: Transform.rotate( + angle: (Random((i + 12) * 7).nextDouble() - 0.5) * 0.04, + child: Material( + borderRadius: BorderRadius.circular(12), + clipBehavior: Clip.antiAlias, + color: ColorScheme.of(context).surfaceContainerLow, + child: InkWell( + onTap: () {}, + child: Padding( + padding: EdgeInsets.all(8), + child: e, + ), ), - )), - ), - )) - .toList(), - ) - ]); + ), + ), + ), + ) + .toList(), + ), + ], + ); } } diff --git a/commet/lib/ui/pages/get_or_create_room/voice_chat_view.dart b/commet/lib/ui/pages/get_or_create_room/voice_chat_view.dart index a3ecf4ac3..93c102940 100644 --- a/commet/lib/ui/pages/get_or_create_room/voice_chat_view.dart +++ b/commet/lib/ui/pages/get_or_create_room/voice_chat_view.dart @@ -5,9 +5,10 @@ import 'package:tiamat/tiamat.dart' as tiamat; class VoiceChatCreatorDescription extends StatelessWidget { const VoiceChatCreatorDescription({super.key}); - String get labelVoiceChatDescription => - Intl.message("A dedicated room for voice calls, for two or more people", - name: "labelVoiceChatDescription"); + String get labelVoiceChatDescription => Intl.message( + "A dedicated room for voice calls, for two or more people", + name: "labelVoiceChatDescription", + ); @override Widget build(BuildContext context) { @@ -32,10 +33,11 @@ class VoiceChatCreatorDescription extends StatelessWidget { spacing: 12, children: [ Icon(Icons.volume_up), - Text("General", - style: TextTheme.of(context) - .headlineSmall - ?.copyWith(fontSize: 20)) + Text( + "General", + style: TextTheme.of(context).headlineSmall + ?.copyWith(fontSize: 20), + ), ], ), ), @@ -45,9 +47,7 @@ class VoiceChatCreatorDescription extends StatelessWidget { name: "pluto", color: Colors.pinkAccent, ), - SizedBox( - height: 12, - ), + SizedBox(height: 12), buildVoiceChatMember( context, image: AssetImage("assets/images/placeholders/avatar2.jpg"), @@ -58,7 +58,7 @@ class VoiceChatCreatorDescription extends StatelessWidget { ], ), ), - ) + ), ], ); } @@ -81,15 +81,13 @@ class VoiceChatCreatorDescription extends StatelessWidget { spacing: 16, children: [ Icon(mute ? Icons.mic_off : Icons.mic), - tiamat.Avatar( - image: image, - ), + tiamat.Avatar(image: image), tiamat.Text( name, type: tiamat.TextType.name, color: color, autoAdjustBrightness: true, - ) + ), ], ), ), diff --git a/commet/lib/ui/pages/login/login_page.dart b/commet/lib/ui/pages/login/login_page.dart index 01a6b657a..eadd0c284 100644 --- a/commet/lib/ui/pages/login/login_page.dart +++ b/commet/lib/ui/pages/login/login_page.dart @@ -23,23 +23,22 @@ class LoginPage extends StatefulWidget { class LoginPageState extends State { String get messageLoginFailed => Intl.message( - "Login Failed...", - name: "messageLoginFailed", - desc: "Generic text to show that an attempted login has failed", - ); + "Login Failed...", + name: "messageLoginFailed", + desc: "Generic text to show that an attempted login has failed", + ); String get messageAlreadyLoggedIn => Intl.message( - "You have already logged in to this account", - name: "messageAlreadyLoggedIn", - desc: - "An error message displayed when the user attempts to add an account which has already been logged in to on this device", - ); + "You have already logged in to this account", + name: "messageAlreadyLoggedIn", + desc: "An error message displayed when the user attempts to add an account which has already been logged in to on this device", + ); String get messageInvalidUsernameOrPassword => Intl.message( - "Invalid username or password", - name: "messageInvalidUsernameOrPassword", - desc: - "An error message displayed when the user attempts to log into an account using the wrong username/password combination"); + "Invalid username or password", + name: "messageInvalidUsernameOrPassword", + desc: "An error message displayed when the user attempts to log into an account using the wrong username/password combination", + ); StreamSubscription? progressSubscription; double? progress; @@ -130,9 +129,7 @@ class LoginPageState extends State { AdaptiveDialog.show( context, title: "Login failed", - builder: (_) => tiamat.Text( - message, - ), + builder: (_) => tiamat.Text(message), ); } } diff --git a/commet/lib/ui/pages/login/login_page_view.dart b/commet/lib/ui/pages/login/login_page_view.dart index fc4b4009b..c6eb43e4c 100644 --- a/commet/lib/ui/pages/login/login_page_view.dart +++ b/commet/lib/ui/pages/login/login_page_view.dart @@ -15,20 +15,21 @@ import 'package:tiamat/atoms/circle_button.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class LoginPageView extends StatefulWidget { - const LoginPageView( - {super.key, - this.canNavigateBack = false, - this.progress, - this.flows, - required this.isLoggingIn, - this.homeserverChecked, - this.doSsoLogin, - this.doPasswordLogin, - this.loadingServerInfo = false, - this.isServerValid = false, - this.hasSsoSupport = false, - this.hasPasswordSupport = false, - this.updateHomeserver}); + const LoginPageView({ + super.key, + this.canNavigateBack = false, + this.progress, + this.flows, + required this.isLoggingIn, + this.homeserverChecked, + this.doSsoLogin, + this.doPasswordLogin, + this.loadingServerInfo = false, + this.isServerValid = false, + this.hasSsoSupport = false, + this.hasPasswordSupport = false, + this.updateHomeserver, + }); final bool canNavigateBack; final bool isLoggingIn; final bool? homeserverChecked; @@ -40,8 +41,11 @@ class LoginPageView extends StatefulWidget { final bool hasPasswordSupport; final Future Function(SsoLoginFlow flow)? doSsoLogin; final Future Function( - PasswordLoginFlow flow, String username, String password)? - doPasswordLogin; + PasswordLoginFlow flow, + String username, + String password, + )? + doPasswordLogin; final Function(String)? updateHomeserver; @@ -56,21 +60,29 @@ class _LoginPageViewState extends State { final TextEditingController _usernameTextField = TextEditingController(); final TextEditingController _passwordTextField = TextEditingController(); - String get promptHomeserver => Intl.message("Homeserver", - name: "promptHomeserver", - desc: "Placeholder text for homeserver field on login form"); + String get promptHomeserver => Intl.message( + "Homeserver", + name: "promptHomeserver", + desc: "Placeholder text for homeserver field on login form", + ); - String get promptUsername => Intl.message("Username", - name: "promptUsername", - desc: "Placeholder text for username field on login form"); + String get promptUsername => Intl.message( + "Username", + name: "promptUsername", + desc: "Placeholder text for username field on login form", + ); - String get promptPassword => Intl.message("Password", - name: "promptPassword", - desc: "Placeholder text for password field on login form"); + String get promptPassword => Intl.message( + "Password", + name: "promptPassword", + desc: "Placeholder text for password field on login form", + ); - String get promptSubmitLogin => Intl.message("Login", - name: "promptSubmitLogin", - desc: "Prompt to submit the username and password, and attempt to login"); + String get promptSubmitLogin => Intl.message( + "Login", + name: "promptSubmitLogin", + desc: "Prompt to submit the username and password, and attempt to login", + ); @override void initState() { @@ -101,11 +113,7 @@ class _LoginPageViewState extends State { color: Colors.transparent, child: Padding( padding: const EdgeInsets.all(8), - child: Stack( - children: [ - loginField(context), - ], - ), + child: Stack(children: [loginField(context)]), ), ), ), @@ -113,33 +121,42 @@ class _LoginPageViewState extends State { Padding( padding: const EdgeInsets.all(16), child: Align( - alignment: Alignment.topLeft, - child: CircleButton( - radius: 25, - icon: Icons.arrow_back, - onPressed: () => Navigator.of(context).pop(), - )), + alignment: Alignment.topLeft, + child: CircleButton( + radius: 25, + icon: Icons.arrow_back, + onPressed: () => Navigator.of(context).pop(), + ), + ), ), ], ), ), SafeArea( child: Align( - alignment: Alignment.topRight, - child: SizedBox( - height: 30, - width: 30, - child: tiamat.IconButton( - icon: Icons.settings, - onPressed: () => NavigationUtils.navigateTo( - context, const AppSettingsPage()), - ))), + alignment: Alignment.topRight, + child: SizedBox( + height: 30, + width: 30, + child: tiamat.IconButton( + icon: Icons.settings, + onPressed: () => NavigationUtils.navigateTo( + context, + const AppSettingsPage(), + ), + ), + ), + ), ), Align( alignment: Alignment.bottomCenter, child: Padding( padding: EdgeInsets.fromLTRB( - 0, 0, 0, MediaQuery.of(context).padding.bottom), + 0, + 0, + 0, + MediaQuery.of(context).padding.bottom, + ), child: SettingsCategoryAbout.info(context), ), ), @@ -156,15 +173,19 @@ class _LoginPageViewState extends State { constraints: const BoxConstraints(maxWidth: 500), child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Theme.of(context).colorScheme.surfaceContainer, - border: Border.all( - color: Theme.of(context).colorScheme.outline, width: 1), - boxShadow: [ - BoxShadow( - blurRadius: 50, - color: Theme.of(context).shadowColor.withAlpha(50)) - ]), + borderRadius: BorderRadius.circular(10), + color: Theme.of(context).colorScheme.surfaceContainer, + border: Border.all( + color: Theme.of(context).colorScheme.outline, + width: 1, + ), + boxShadow: [ + BoxShadow( + blurRadius: 50, + color: Theme.of(context).shadowColor.withAlpha(50), + ), + ], + ), child: Padding( padding: const EdgeInsets.fromLTRB(20, 20, 20, 0), child: Stack( @@ -172,9 +193,10 @@ class _LoginPageViewState extends State { IgnorePointer( ignoring: widget.isLoggingIn, child: AnimatedOpacity( - opacity: widget.isLoggingIn ? 0.5 : 1.0, - duration: Durations.short2, - child: loginInputs(context)), + opacity: widget.isLoggingIn ? 0.5 : 1.0, + duration: Durations.short2, + child: loginInputs(context), + ), ), ], ), @@ -183,9 +205,7 @@ class _LoginPageViewState extends State { ), ), if (widget.isLoggingIn) - const Center( - child: CircularProgressIndicator(), - ) + const Center(child: CircularProgressIndicator()), ], ); } @@ -197,91 +217,94 @@ class _LoginPageViewState extends State { defaultSso = ssoFlows.where((e) => e.id == null).firstOrNull; } - return Column(mainAxisSize: MainAxisSize.min, children: [ - Flexible( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - appIcon(context), - ], - ), - ), - const SizedBox(height: 16), - homeserverEntry(), - const SizedBox(height: 16), - if (widget.hasPasswordSupport) usenamePasswordLoginInputs(), - if (widget.hasSsoSupport) + return Column( + mainAxisSize: MainAxisSize.min, + children: [ Flexible( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (widget.hasPasswordSupport) - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox( - width: 100, - height: 10, - child: tiamat.Seperator(), - ), - tiamat.Text.labelLow(CommonStrings.labelOr), - const SizedBox( - width: 100, - height: 10, - child: tiamat.Seperator(), - ), - ], + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [appIcon(context)], + ), + ), + const SizedBox(height: 16), + homeserverEntry(), + const SizedBox(height: 16), + if (widget.hasPasswordSupport) usenamePasswordLoginInputs(), + if (widget.hasSsoSupport) + Flexible( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (widget.hasPasswordSupport) + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox( + width: 100, + height: 10, + child: tiamat.Seperator(), + ), + tiamat.Text.labelLow(CommonStrings.labelOr), + const SizedBox( + width: 100, + height: 10, + child: tiamat.Seperator(), + ), + ], + ), ), - ), - if (defaultSso != null) - tiamat.Button.secondary( - text: "Login with " + defaultSso.name, - onTap: () => {widget.doSsoLogin?.call(defaultSso!)}, - ), - if (ssoFlows != null) - Flexible( + if (defaultSso != null) + tiamat.Button.secondary( + text: "Login with " + defaultSso.name, + onTap: () => {widget.doSsoLogin?.call(defaultSso!)}, + ), + if (ssoFlows != null) + Flexible( child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - spacing: 10, - children: ssoFlows - .whereType() - .where((e) => e != defaultSso) - .map((e) => ElevatedButton.icon( - icon: SizedBox( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + spacing: 10, + children: ssoFlows + .whereType() + .where((e) => e != defaultSso) + .map( + (e) => ElevatedButton.icon( + icon: SizedBox( width: e.icon == null ? 0 : 32, height: 48, child: e.icon != null ? Image(image: e.icon!) - : null), - label: Text("Continue with ${e.name}"), - onPressed: () => widget.doSsoLogin?.call(e), - )) - .toList(), + : null, + ), + label: Text("Continue with ${e.name}"), + onPressed: () => widget.doSsoLogin?.call(e), + ), + ) + .toList(), + ), + ), ), - )) - ], + ], + ), ), - ), - SizedBox( - height: 15, - child: Center( - child: SizedBox( - height: 5, - child: widget.progress == null - ? null - : LinearProgressIndicator( - value: widget.progress, - ), + SizedBox( + height: 15, + child: Center( + child: SizedBox( + height: 5, + child: widget.progress == null + ? null + : LinearProgressIndicator(value: widget.progress), + ), ), ), - ), - ]); + ], + ); } Column usenamePasswordLoginInputs() { @@ -312,8 +335,11 @@ class _LoginPageViewState extends State { child: tiamat.Button( text: promptSubmitLogin, onTap: flow != null - ? () => widget.doPasswordLogin - ?.call(flow, _usernameTextField.text, _passwordTextField.text) + ? () => widget.doPasswordLogin?.call( + flow, + _usernameTextField.text, + _passwordTextField.text, + ) : null, ), ); @@ -354,21 +380,21 @@ class _LoginPageViewState extends State { keyboardType: TextInputType.url, inputFormatters: [FilteringTextInputFormatter.deny(RegExp("[ ]"))], decoration: InputDecoration( - prefixText: 'https://', - border: const OutlineInputBorder(), - labelText: promptHomeserver, - suffix: homeserverEntrySuffix()), + prefixText: 'https://', + border: const OutlineInputBorder(), + labelText: promptHomeserver, + suffix: homeserverEntrySuffix(), + ), ); } Widget homeserverEntrySuffix() { if (widget.loadingServerInfo) { return const SizedBox( - width: 15, - height: 15, - child: CircularProgressIndicator( - strokeWidth: 2, - )); + width: 15, + height: 15, + child: CircularProgressIndicator(strokeWidth: 2), + ); } return Icon( diff --git a/commet/lib/ui/pages/main/main_page.dart b/commet/lib/ui/pages/main/main_page.dart index 6eb6cfe30..26739a058 100644 --- a/commet/lib/ui/pages/main/main_page.dart +++ b/commet/lib/ui/pages/main/main_page.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:collection/collection.dart'; import 'package:commet/client/client.dart'; import 'package:commet/client/client_manager.dart'; @@ -39,11 +40,13 @@ import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; class MainPage extends StatefulWidget { - const MainPage(this.clientManager, - {super.key, - this.initialClientId, - this.initialRoom, - this.wasLoggedInAtStartup = false}); + const MainPage( + this.clientManager, { + super.key, + this.initialClientId, + this.initialRoom, + this.wasLoggedInAtStartup = false, + }); final ClientManager clientManager; final String? initialRoom; final String? initialClientId; @@ -53,11 +56,7 @@ class MainPage extends StatefulWidget { State createState() => MainPageState(); } -enum MainPageSubView { - space, - home, - rooms, -} +enum MainPageSubView { space, home, rooms } class MainPageState extends State { Space? _currentSpace; @@ -91,13 +90,17 @@ class MainPageState extends State { VoipSession? get currentCall => currentRoom == null ? null - : widget.clientManager.callManager - .getCallInRoom(currentRoom!.client, currentRoom!.identifier); + : widget.clientManager.callManager.getCallInRoom( + currentRoom!.client, + currentRoom!.identifier, + ); - String get updateInstalledTitle => Intl.message("Update Installed", - desc: - "Title for the dialog which is shown when an update has been installed", - name: "updateInstalledTitle"); + String get updateInstalledTitle => Intl.message( + "Update Installed", + desc: + "Title for the dialog which is shown when an update has been installed", + name: "updateInstalledTitle", + ); @override void initState() { @@ -106,7 +109,8 @@ class MainPageState extends State { Client? client; if (preferences.filterClient.value != null) { filterClient = clientManager.clients.firstWhereOrNull( - (i) => i.identifier == preferences.filterClient.value); + (i) => i.identifier == preferences.filterClient.value, + ); } if (widget.initialClientId != null) { @@ -130,45 +134,58 @@ class MainPageState extends State { } var allFavoriteRooms = NotifyingListCombiner( - clientManager.clients.map((i) => i.favoriteRooms).toList()); - - favoriteRooms = NotifyingListFilter(allFavoriteRooms, where: (item) { - if (filterClient == null) return true; - return item.client == filterClient; - }, onFilterParamsChanged: [onFilterClientChanged.stream]); + clientManager.clients.map((i) => i.favoriteRooms).toList(), + ); + + favoriteRooms = NotifyingListFilter( + allFavoriteRooms, + where: (item) { + if (filterClient == null) return true; + return item.client == filterClient; + }, + onFilterParamsChanged: [onFilterClientChanged.stream], + ); directMessages = NotifyingListFilter( - clientManager.directMessages.directMessageRooms, where: (item) { - if (item.isFavorite) return false; - - if (filterClient == null) return true; - return item.client == filterClient; - }, onFilterParamsChanged: [ - onFilterClientChanged.stream, - allFavoriteRooms.onListUpdated, - ]); - - singleRooms = NotifyingListFilter(clientManager.rooms, where: (item) { - if (filterClient != null) { - if (item.client != filterClient) return false; - } - var dms = item.client.getComponent(); + clientManager.directMessages.directMessageRooms, + where: (item) { + if (item.isFavorite) return false; + + if (filterClient == null) return true; + return item.client == filterClient; + }, + onFilterParamsChanged: [ + onFilterClientChanged.stream, + allFavoriteRooms.onListUpdated, + ], + ); + + singleRooms = NotifyingListFilter( + clientManager.rooms, + where: (item) { + if (filterClient != null) { + if (item.client != filterClient) return false; + } + var dms = item.client.getComponent(); - if (dms?.isRoomDirectMessage(item) != false) { - return false; - } + if (dms?.isRoomDirectMessage(item) != false) { + return false; + } - if (item.client.spaces - .any((space) => space.containsRoom(item.identifier))) { - return false; - } + if (item.client.spaces.any( + (space) => space.containsRoom(item.identifier), + )) { + return false; + } - return true; - }, onFilterParamsChanged: [ - onFilterClientChanged.stream, - clientManager.onSpaceUpdated.stream, - clientManager.rooms.onListUpdated - ]); + return true; + }, + onFilterParamsChanged: [ + onFilterClientChanged.stream, + clientManager.onSpaceUpdated.stream, + clientManager.rooms.onListUpdated, + ], + ); ServicesBinding.instance.keyboard.addHandler(_onKeyPressed); @@ -176,10 +193,13 @@ class MainPageState extends State { // setState(() {}); // }); - onCallStartedSubscription = - clientManager.callManager.currentSessions.onListUpdated.listen((event) { - setState(() {}); - }); + onCallStartedSubscription = clientManager + .callManager + .currentSessions + .onListUpdated + .listen((event) { + setState(() {}); + }); EventBus.openRoom.stream.listen(onOpenRoomSignal); @@ -192,8 +212,9 @@ class MainPageState extends State { EventBus.openUserProfile.stream.listen(onOpenUserProfileSignal); - onClientRemovedSubscription = - clientManager.onClientRemoved.stream.listen(onClientRemoved); + onClientRemovedSubscription = clientManager.onClientRemoved.stream.listen( + onClientRemoved, + ); onClientAddedSubscription = clientManager.onClientAdded.stream.listen((_) { if (mounted) setState(() {}); @@ -428,8 +449,9 @@ class MainPageState extends State { if (room != null) { if (preferences.automaticallyOpenSpace.value && args.openInSpace) { - var spacesWithRoom = - client.spaces.where((element) => element.containsRoom(roomId)); + var spacesWithRoom = client.spaces.where( + (element) => element.containsRoom(roomId), + ); if (spacesWithRoom.isNotEmpty) { selectSpace(spacesWithRoom.first); @@ -438,19 +460,26 @@ class MainPageState extends State { selectRoom(room, bypassSpecialRoomType: bypassSpecialRoomType); } else { - GetOrCreateRoom.show(client, context, - pickExisting: false, - showAllRoomTypes: false, - initialRoomAddress: originalId); + GetOrCreateRoom.show( + client, + context, + pickExisting: false, + showAllRoomTypes: false, + initialRoomAddress: originalId, + ); } } Future askSwitchAccount( - Client newClient, (String, String?) strings) async { - var confirm = await AdaptiveDialog.confirmation(context, - prompt: - "You tried to open a room for another account (${newClient.self?.identifier}), would you like to switch?", - title: "Switch Account"); + Client newClient, + (String, String?) strings, + ) async { + var confirm = await AdaptiveDialog.confirmation( + context, + prompt: + "You tried to open a room for another account (${newClient.self?.identifier}), would you like to switch?", + title: "Switch Account", + ); if (confirm != true) return; EventBus.setFilterClient.add(newClient); @@ -461,12 +490,13 @@ class MainPageState extends State { void navigateRoomSettings() { if (currentRoom != null) { NavigationUtils.navigateTo( - context, - RoomSettingsPage( - room: currentRoom!, - contextSpace: currentSpace, - onLeaveRoom: clearRoomSelection, - )); + context, + RoomSettingsPage( + room: currentRoom!, + contextSpace: currentSpace, + onLeaveRoom: clearRoomSelection, + ), + ); } } @@ -485,23 +515,23 @@ class MainPageState extends State { if (donationCheck != null) { var client = clientManager.getClient(donationCheck.$1); - Log.i( - "Resuming donation flow for user: ${client?.self?.identifier}", - ); + Log.i("Resuming donation flow for user: ${client?.self?.identifier}"); if (client != null) { var secret = await client .getComponent() ?.getClientSecret(); if (secret != null) { - AdaptiveDialog.show(context, - builder: (context) => DonationRewardsConfirmation( - client: client, - identifier: secret, - didOpenDonationWindow: true, - since: donationCheck.$2, - ), - dismissible: false); + AdaptiveDialog.show( + context, + builder: (context) => DonationRewardsConfirmation( + client: client, + identifier: secret, + didOpenDonationWindow: true, + since: donationCheck.$2, + ), + dismissible: false, + ); } } } @@ -518,24 +548,28 @@ class MainPageState extends State { final invitation = client.getComponent(); if (invitation == null) return; - AdaptiveDialog.show(context, - builder: (context) => SendInvitationWidget( - client!, - invitation, - showSuggestions: false, - onUserPicked: (userId) async { - final confirm = await AdaptiveDialog.confirmation(context, - prompt: "Are you sure you want to invite $userId to chat?", - title: "Invitation"); - if (confirm != true) { - return; - } - - var comp = client!.getComponent(); - await comp?.createDirectMessage(userId); - }, - ), - title: "Start Direct Message"); + AdaptiveDialog.show( + context, + builder: (context) => SendInvitationWidget( + client!, + invitation, + showSuggestions: false, + onUserPicked: (userId) async { + final confirm = await AdaptiveDialog.confirmation( + context, + prompt: "Are you sure you want to invite $userId to chat?", + title: "Invitation", + ); + if (confirm != true) { + return; + } + + var comp = client!.getComponent(); + await comp?.createDirectMessage(userId); + }, + ), + title: "Start Direct Message", + ); } bool _onKeyPressed(KeyEvent event) { diff --git a/commet/lib/ui/pages/main/main_page_view_desktop.dart b/commet/lib/ui/pages/main/main_page_view_desktop.dart index 8af9171d0..2375b3ba1 100644 --- a/commet/lib/ui/pages/main/main_page_view_desktop.dart +++ b/commet/lib/ui/pages/main/main_page_view_desktop.dart @@ -28,10 +28,10 @@ class MainPageViewDesktop extends StatelessWidget { final MainPageState state; String get directMessagesListHeaderDesktop => Intl.message( - "Direct Messages", - desc: "The header for the direct messages list on desktop", - name: "directMessagesListHeaderDesktop", - ); + "Direct Messages", + desc: "The header for the direct messages list on desktop", + name: "directMessagesListHeaderDesktop", + ); @override Widget build(BuildContext context) { @@ -89,12 +89,13 @@ class MainPageViewDesktop extends StatelessWidget { ), Flexible( child: tiamat.Tile.surfaceContainer( - caulkClipBottomLeft: true, - caulkClipTopRight: true, - caulkPadTop: true, - caulkClipBottomRight: true, - caulkClipTopLeft: true, - child: buildRoomPicker(context)), + caulkClipBottomLeft: true, + caulkClipTopRight: true, + caulkPadTop: true, + caulkClipBottomRight: true, + caulkClipTopLeft: true, + child: buildRoomPicker(context), + ), ), ], ), @@ -138,20 +139,18 @@ class MainPageViewDesktop extends StatelessWidget { SpaceHeader( state.currentSpace!, onTap: state.clearRoomSelection, - backgroundColor: Theme.of( - context, - ).colorScheme.surfaceContainerLow, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, ), Expanded( child: SingleChildScrollView( child: SpaceViewer( state.currentSpace!, - key: ValueKey( - "space-view-key-${state.currentSpace!.localId}", - ), + key: ValueKey("space-view-key-${state.currentSpace!.localId}"), onRoomSelected: (room, {bool bypassSpecialRoomType = false}) { - state.selectRoom(room, - bypassSpecialRoomType: bypassSpecialRoomType); + state.selectRoom( + room, + bypassSpecialRoomType: bypassSpecialRoomType, + ); }, ), ), @@ -206,8 +205,9 @@ class MainPageViewDesktop extends StatelessWidget { onTap: state.currentRoom?.permissions.canEditAnything == true ? () => state.navigateRoomSettings() : null, - menu: - RoomQuickAccessMenuViewDesktop(room: state.currentRoom!), + menu: RoomQuickAccessMenuViewDesktop( + room: state.currentRoom!, + ), ), ), ), @@ -227,8 +227,10 @@ class MainPageViewDesktop extends StatelessWidget { caulkClipBottomLeft: true, caulkClipBottomRight: true, caulkBorderLeft: true, - child: RoomPrimaryView(state.currentRoom!, - bypassSpecialRoomTypes: state.showAsTextRoom), + child: RoomPrimaryView( + state.currentRoom!, + bypassSpecialRoomTypes: state.showAsTextRoom, + ), ), ), RoomSidePanel( @@ -278,8 +280,9 @@ class MainPageViewDesktop extends StatelessWidget { child: SizedBox( height: double.infinity, child: ImportantRoomsList( - state: state, - directMessagesListHeaderDesktop: directMessagesListHeaderDesktop), + state: state, + directMessagesListHeaderDesktop: directMessagesListHeaderDesktop, + ), ), ); } else { diff --git a/commet/lib/ui/pages/main/main_page_view_mobile.dart b/commet/lib/ui/pages/main/main_page_view_mobile.dart index 83f66b031..b62b65146 100644 --- a/commet/lib/ui/pages/main/main_page_view_mobile.dart +++ b/commet/lib/ui/pages/main/main_page_view_mobile.dart @@ -41,9 +41,11 @@ class _MainPageViewMobileState extends State { bool shouldMainIgnoreInput = false; double height = -1; - String get directMessagesListHeaderMobile => Intl.message("Direct Messages", - desc: "The header for the direct messages list on desktop", - name: "directMessagesListHeaderMobile"); + String get directMessagesListHeaderMobile => Intl.message( + "Direct Messages", + desc: "The header for the direct messages list on desktop", + name: "directMessagesListHeaderMobile", + ); GlobalKey mainPanelKey = GlobalKey(); @@ -91,44 +93,44 @@ class _MainPageViewMobileState extends State { @override Widget build(BuildContext context) { return PopScope( - canPop: canPop(), - onPopInvokedWithResult: (didPop, result) { - var event = ScopePopped(); - event.currentMobileSide = panelsKey.currentState?.currentSide; - - EventBus.onPopInvoked.add(event); - - if (event.handled) { - return; - } - - if (widget.state.currentView == MainPageSubView.home && - widget.state.currentRoom != null) { - if (widget.state.currentRoom != null) { - var dm = widget.state.currentRoom!.client - .getComponent(); - if (dm?.isRoomDirectMessage(widget.state.currentRoom!) == true) { - panelsKey.currentState?.reveal(RevealSide.left); - return; - } + canPop: canPop(), + onPopInvokedWithResult: (didPop, result) { + var event = ScopePopped(); + event.currentMobileSide = panelsKey.currentState?.currentSide; + + EventBus.onPopInvoked.add(event); + + if (event.handled) { + return; + } + + if (widget.state.currentView == MainPageSubView.home && + widget.state.currentRoom != null) { + if (widget.state.currentRoom != null) { + var dm = widget.state.currentRoom!.client + .getComponent(); + if (dm?.isRoomDirectMessage(widget.state.currentRoom!) == true) { + panelsKey.currentState?.reveal(RevealSide.left); + return; } - - widget.state.selectHome(); - - return; } - switch (panelsKey.currentState?.currentSide) { - case RevealSide.right: - panelsKey.currentState?.reveal(RevealSide.main); - case RevealSide.main: - panelsKey.currentState?.reveal(RevealSide.left); - default: - break; - } - }, - child: Foundation( - child: Stack( + widget.state.selectHome(); + + return; + } + + switch (panelsKey.currentState?.currentSide) { + case RevealSide.right: + panelsKey.currentState?.reveal(RevealSide.main); + case RevealSide.main: + panelsKey.currentState?.reveal(RevealSide.left); + default: + break; + } + }, + child: Foundation( + child: Stack( children: [ OverlappingPanels( key: panelsKey, @@ -143,15 +145,18 @@ class _MainPageViewMobileState extends State { }, left: navigation(context), main: Foundation( - child: IgnorePointer( - ignoring: shouldMainIgnoreInput, - child: Container(key: mainPanelKey, child: mainPanel()), - )), + child: IgnorePointer( + ignoring: shouldMainIgnoreInput, + child: Container(key: mainPanelKey, child: mainPanel()), + ), + ), right: rightPanel(context), ), const OverlayWindowsSurface(), ], - ))); + ), + ), + ); } Widget? rightPanel(BuildContext context) { @@ -164,18 +169,21 @@ class _MainPageViewMobileState extends State { children: [ Tile.low( child: ScaledSafeArea( - child: Container(), - bottom: false, - top: true, - left: false, - right: false), + child: Container(), + bottom: false, + top: true, + left: false, + right: false, + ), ), Expanded( child: RoomSidePanel( - key: ValueKey( - "room-side-panel-${widget.state.currentRoom!.localId}"), - state: widget.state), - ) + key: ValueKey( + "room-side-panel-${widget.state.currentRoom!.localId}", + ), + state: widget.state, + ), + ), ], ), ); @@ -230,20 +238,22 @@ class _MainPageViewMobileState extends State { directMessagesView(), if (widget.state.currentView == MainPageSubView.rooms) Flexible( - child: Tile.surfaceContainer( - caulkClipTopLeft: true, - caulkClipBottomLeft: true, - caulkPadRight: true, - caulkClipTopRight: true, - caulkClipBottomRight: true, - child: SingleRoomsList( - state: widget.state, - onSelectRoom: (r) => selectRoom(r), - ))), + child: Tile.surfaceContainer( + caulkClipTopLeft: true, + caulkClipBottomLeft: true, + caulkPadRight: true, + caulkClipTopRight: true, + caulkClipBottomRight: true, + child: SingleRoomsList( + state: widget.state, + onSelectRoom: (r) => selectRoom(r), + ), + ), + ), if (widget.state.currentView == MainPageSubView.space && widget.state.currentSpace != null) spaceRoomSelector(newContext), - const BackgroundTaskViewContainer() + const BackgroundTaskViewContainer(), ], ), ), @@ -255,11 +265,9 @@ class _MainPageViewMobileState extends State { child: ScaledSafeArea( bottom: true, top: false, - child: CurrentSessionPanel( - currentUser: widget.state.currentUser, - ), + child: CurrentSessionPanel(currentUser: widget.state.currentUser), ), - ) + ), ], ), ); @@ -273,7 +281,8 @@ class _MainPageViewMobileState extends State { child: SingleChildScrollView( child: SpaceSummary( key: ValueKey( - "space-summary-key-${widget.state.currentSpace!.localId}"), + "space-summary-key-${widget.state.currentSpace!.localId}", + ), space: widget.state.currentSpace!, onRoomTap: (room) { widget.state.selectRoom(room); @@ -309,7 +318,11 @@ class _MainPageViewMobileState extends State { height: 50, child: RoomHeader( widget.state.currentRoom!, - onTap: widget.state.currentRoom?.permissions + onTap: + widget + .state + .currentRoom + ?.permissions .canEditAnything == true ? () => widget.state.navigateRoomSettings() @@ -346,13 +359,14 @@ class _MainPageViewMobileState extends State { return Material( child: Tile( - child: HomeScreen( - clientManager: widget.state.clientManager, - filterClient: widget.state.filterClient, - onBurgerMenuTap: () { - panelsKey.currentState?.reveal(RevealSide.left); - }, - )), + child: HomeScreen( + clientManager: widget.state.clientManager, + filterClient: widget.state.filterClient, + onBurgerMenuTap: () { + panelsKey.currentState?.reveal(RevealSide.left); + }, + ), + ), ); } @@ -371,7 +385,8 @@ class _MainPageViewMobileState extends State { child: RoomMembersListWidget( widget.state.currentRoom!, key: ValueKey( - "room-participant-list-key-${widget.state.currentRoom!.localId}"), + "room-participant-list-key-${widget.state.currentRoom!.localId}", + ), ), ), ), @@ -399,9 +414,10 @@ class _MainPageViewMobileState extends State { children: [ Flexible( child: ImportantRoomsList( - state: widget.state, - directMessagesListHeaderDesktop: - directMessagesListHeaderMobile), + state: widget.state, + directMessagesListHeaderDesktop: + directMessagesListHeaderMobile, + ), ), ], ), @@ -423,22 +439,28 @@ class _MainPageViewMobileState extends State { children: [ SpaceHeader( widget.state.currentSpace!, - backgroundColor: - material.Theme.of(context).colorScheme.surfaceContainerLow, + backgroundColor: material.Theme.of(context) + .colorScheme + .surfaceContainerLow, onTap: clearSelectedRoom, ), Expanded( - child: SingleChildScrollView( - child: SpaceViewer( - widget.state.currentSpace!, - key: ValueKey( - "space-view-key-${widget.state.currentSpace!.localId}"), - onRoomSelected: (room, {bypassSpecialRoomType = false}) async { - selectRoom(room, - bypassSpecialRoomType: bypassSpecialRoomType); - }, + child: SingleChildScrollView( + child: SpaceViewer( + widget.state.currentSpace!, + key: ValueKey( + "space-view-key-${widget.state.currentSpace!.localId}", + ), + onRoomSelected: + (room, {bypassSpecialRoomType = false}) async { + selectRoom( + room, + bypassSpecialRoomType: bypassSpecialRoomType, + ); + }, + ), ), - )), + ), ], ), ), diff --git a/commet/lib/ui/pages/main/room_primary_view.dart b/commet/lib/ui/pages/main/room_primary_view.dart index 7734ce053..d2d489b73 100644 --- a/commet/lib/ui/pages/main/room_primary_view.dart +++ b/commet/lib/ui/pages/main/room_primary_view.dart @@ -12,8 +12,11 @@ import 'package:commet/ui/organisms/voip_room_view/voip_room_view.dart'; import 'package:flutter/material.dart'; class RoomPrimaryView extends StatelessWidget { - const RoomPrimaryView(this.room, - {super.key, this.bypassSpecialRoomTypes = false}); + const RoomPrimaryView( + this.room, { + super.key, + this.bypassSpecialRoomTypes = false, + }); final Room room; final bool bypassSpecialRoomTypes; @@ -30,25 +33,16 @@ class RoomPrimaryView extends StatelessWidget { return ScaledSafeArea( bottom: true, top: false, - child: VoipRoomView( - voip, - key: key, - ), + child: VoipRoomView(voip, key: key), ); } if (photos != null) { - return PhotoAlbumView( - photos, - key: key, - ); + return PhotoAlbumView(photos, key: key); } if (calendar?.isCalendarRoom == true) { - return CalendarRoomView( - calendar!, - key: key, - ); + return CalendarRoomView(calendar!, key: key); } } @@ -60,9 +54,7 @@ class RoomPrimaryView extends StatelessWidget { return Column( children: [ if (call != null) Flexible(child: CallWidget(call)), - Flexible( - child: Chat(room, key: key), - ), + Flexible(child: Chat(room, key: key)), ], ); } diff --git a/commet/lib/ui/pages/matrix/authentication/matrix_uia_request.dart b/commet/lib/ui/pages/matrix/authentication/matrix_uia_request.dart index f430ae985..fd30c5edf 100644 --- a/commet/lib/ui/pages/matrix/authentication/matrix_uia_request.dart +++ b/commet/lib/ui/pages/matrix/authentication/matrix_uia_request.dart @@ -53,10 +53,14 @@ class _MatrixUIARequestState extends State { void submitAuthentication(String password) { ErrorUtils.tryRun(context, () async { - await widget.request.completeStage(AuthenticationPassword( + await widget.request.completeStage( + AuthenticationPassword( password: password, identifier: AuthenticationUserIdentifier( - user: widget.client.matrixClient.userID!))); + user: widget.client.matrixClient.userID!, + ), + ), + ); }); } @@ -64,13 +68,16 @@ class _MatrixUIARequestState extends State { // https://spec.matrix.org/v1.15/client-server-api/#client-behaviour-21 var hs = widget.client.matrixClient.homeserver!; var url = hs.replace( - path: "/_matrix/client/v3/auth/m.login.sso/fallback/web", - queryParameters: {"session": widget.request.session}); + path: "/_matrix/client/v3/auth/m.login.sso/fallback/web", + queryParameters: {"session": widget.request.session}, + ); - LinkUtils.open(url, - bypassConfirmation: true, - filterTrackingParameters: false, - context: context); + LinkUtils.open( + url, + bypassConfirmation: true, + filterTrackingParameters: false, + context: context, + ); Navigator.of(context).pop(); } } diff --git a/commet/lib/ui/pages/matrix/authentication/matrix_uia_request_view.dart b/commet/lib/ui/pages/matrix/authentication/matrix_uia_request_view.dart index 3b31273d1..92f1bae8b 100644 --- a/commet/lib/ui/pages/matrix/authentication/matrix_uia_request_view.dart +++ b/commet/lib/ui/pages/matrix/authentication/matrix_uia_request_view.dart @@ -8,13 +8,15 @@ import 'package:tiamat/tiamat.dart' as tiamat; import 'package:flutter/material.dart' as material; class MatrixUIARequestView extends StatefulWidget { - const MatrixUIARequestView(this.state, - {this.onSubmitAuthentication, - required this.nextSteps, - super.key, - this.onFail, - this.onSubmitSso, - this.onSuccess}); + const MatrixUIARequestView( + this.state, { + this.onSubmitAuthentication, + required this.nextSteps, + super.key, + this.onFail, + this.onSubmitSso, + this.onSuccess, + }); final UiaRequestState state; final Set nextSteps; final Function(String password)? onSubmitAuthentication; @@ -26,10 +28,7 @@ class MatrixUIARequestView extends StatefulWidget { State createState() => _MatrixUIARequestViewState(); } -enum UIAStep { - password, - sso, -} +enum UIAStep { password, sso } class _MatrixUIARequestViewState extends State { TextEditingController passwordFieldController = TextEditingController(); @@ -53,10 +52,7 @@ class _MatrixUIARequestViewState extends State { Widget build(BuildContext context) { return SizedBox( width: 500, - child: Padding( - padding: const EdgeInsets.all(12.0), - child: buildView(), - ), + child: Padding(padding: const EdgeInsets.all(12.0), child: buildView()), ); } @@ -90,18 +86,20 @@ class _MatrixUIARequestViewState extends State { ), if (canUseSso) tiamat.Button( - text: "Continue with SSO", - onTap: () { - widget.onSubmitSso?.call(); - setState(() { - pickedStep = UIAStep.sso; - }); - }), + text: "Continue with SSO", + onTap: () { + widget.onSubmitSso?.call(); + setState(() { + pickedStep = UIAStep.sso; + }); + }, + ), if (canUseAnyNextStep == false) ...[ tiamat.Text.labelLow( - "Sorry, none of the authentication methods provided by the server are supported."), + "Sorry, none of the authentication methods provided by the server are supported.", + ), tiamat.Text.labelLow(widget.nextSteps.toString()), - ] + ], ], ), ); @@ -122,11 +120,10 @@ class _MatrixUIARequestViewState extends State { Widget showSsoStep() { return SizedBox( - height: 300, - width: 300, - child: Center( - child: CircularProgressIndicator(), - )); + height: 300, + width: 300, + child: Center(child: CircularProgressIndicator()), + ); } Widget userPasswordInput() { @@ -141,20 +138,20 @@ class _MatrixUIARequestViewState extends State { controller: passwordFieldController, ), SizedBox( - height: 40, - child: Button( - text: CommonStrings.promptSubmit, - onTap: () => widget.onSubmitAuthentication - ?.call(passwordFieldController.text), - )) + height: 40, + child: Button( + text: CommonStrings.promptSubmit, + onTap: () => widget.onSubmitAuthentication?.call( + passwordFieldController.text, + ), + ), + ), ], ); } Widget loading() { - return const Center( - child: material.CircularProgressIndicator(), - ); + return const Center(child: material.CircularProgressIndicator()); } Widget done(BuildContext context) { @@ -173,7 +170,7 @@ class _MatrixUIARequestViewState extends State { size: 40, ), ), - const tiamat.Text.largeTitle("Success!") + const tiamat.Text.largeTitle("Success!"), ], ), SizedBox( @@ -183,7 +180,7 @@ class _MatrixUIARequestViewState extends State { text: CommonStrings.promptContinue, onTap: () => widget.onSuccess?.call(), ), - ) + ), ], ); } @@ -203,7 +200,7 @@ class _MatrixUIARequestViewState extends State { size: 40, ), ), - const tiamat.Text.largeTitle("Login failed...") + const tiamat.Text.largeTitle("Login failed..."), ], ), SizedBox( @@ -213,7 +210,7 @@ class _MatrixUIARequestViewState extends State { text: CommonStrings.promptContinue, onTap: () => widget.onFail?.call(), ), - ) + ), ], ); } diff --git a/commet/lib/ui/pages/matrix/room_address_settings/matrix_room_add_local_alias_view.dart b/commet/lib/ui/pages/matrix/room_address_settings/matrix_room_add_local_alias_view.dart index 23b13ab01..20aad9f8b 100644 --- a/commet/lib/ui/pages/matrix/room_address_settings/matrix_room_add_local_alias_view.dart +++ b/commet/lib/ui/pages/matrix/room_address_settings/matrix_room_add_local_alias_view.dart @@ -4,8 +4,11 @@ import 'package:tiamat/tiamat.dart' as tiamat; class MatrixRoomAddLocalAliasView extends StatefulWidget { const MatrixRoomAddLocalAliasView( - this.homeserver, this.isAliasAvailable, this.createAlias, - {super.key}); + this.homeserver, + this.isAliasAvailable, + this.createAlias, { + super.key, + }); final String homeserver; final Future Function(String alias) isAliasAvailable; final Future Function(String alias) createAlias; @@ -59,9 +62,7 @@ class _MatrixRoomAddLocalAliasViewState suffixText: ":${widget.homeserver}", prefixText: "#", ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -74,15 +75,18 @@ class _MatrixRoomAddLocalAliasViewState const Padding( padding: EdgeInsets.all(8.0), child: SizedBox( - width: 15, height: 15, child: CircularProgressIndicator()), + width: 15, + height: 15, + child: CircularProgressIndicator(), + ), ), tiamat.Button( text: "Create!", onTap: submit, isLoading: createLoading, - ) + ), ], - ) + ), ], ); } diff --git a/commet/lib/ui/pages/matrix/room_address_settings/matrix_room_address_settings.dart b/commet/lib/ui/pages/matrix/room_address_settings/matrix_room_address_settings.dart index a02a6f9dc..23ad61e22 100644 --- a/commet/lib/ui/pages/matrix/room_address_settings/matrix_room_address_settings.dart +++ b/commet/lib/ui/pages/matrix/room_address_settings/matrix_room_address_settings.dart @@ -42,15 +42,23 @@ class _MatrixRoomAddressSettingsState extends State { newAliases.addAll(List.from(result['aliases'] as Iterable)); } catch (_) {} - var altAliases = widget.matrixRoom.states["m.room.canonical_alias"]?[""] - ?.content["alt_aliases"] as Iterable?; + var altAliases = + widget + .matrixRoom + .states["m.room.canonical_alias"]?[""] + ?.content["alt_aliases"] + as Iterable?; if (altAliases != null) { - newAliases.addAll(List.from(altAliases) - .where((element) => newAliases.contains(element) == false)); + newAliases.addAll( + List.from(altAliases) + .where((element) => newAliases.contains(element) == false), + ); - newPublishedAliases.addAll(List.from(altAliases) - .where((element) => newPublishedAliases.contains(element) == false)); + newPublishedAliases.addAll( + List.from(altAliases) + .where((element) => newPublishedAliases.contains(element) == false), + ); } if (widget.matrixRoom.canonicalAlias != "" && @@ -94,8 +102,9 @@ class _MatrixRoomAddressSettingsState extends State { setMainAlias: setMainAlias, publishAlias: publishAlias, unpublishAlias: unpublishAlias, - canChangeMainAlias: - widget.matrixRoom.canChangeStateEvent("m.room.canonical_alias"), + canChangeMainAlias: widget.matrixRoom.canChangeStateEvent( + "m.room.canonical_alias", + ), ); } @@ -107,8 +116,10 @@ class _MatrixRoomAddressSettingsState extends State { Future createAlias(String alias) async { var fullAlias = "#$alias:$userHomeserverPart"; try { - await widget.matrixRoom.client - .setRoomAlias(fullAlias, widget.matrixRoom.id); + await widget.matrixRoom.client.setRoomAlias( + fullAlias, + widget.matrixRoom.id, + ); setState(() { aliases?.add(fullAlias); @@ -146,8 +157,12 @@ class _MatrixRoomAddressSettingsState extends State { void updatePublishedAliases() { var result = List.empty(growable: true); - var altAliases = widget.matrixRoom.states["m.room.canonical_alias"]?[""] - ?.content["alt_aliases"] as Iterable?; + var altAliases = + widget + .matrixRoom + .states["m.room.canonical_alias"]?[""] + ?.content["alt_aliases"] + as Iterable?; if (altAliases != null) { result.addAll(List.from(altAliases)); @@ -176,7 +191,11 @@ class _MatrixRoomAddressSettingsState extends State { } await widget.matrixRoom.client.setRoomStateWithKey( - widget.matrixRoom.id, EventTypes.RoomCanonicalAlias, "", state); + widget.matrixRoom.id, + EventTypes.RoomCanonicalAlias, + "", + state, + ); setState(() { publishedAliases?.add(newPublishedAlias); @@ -207,7 +226,11 @@ class _MatrixRoomAddressSettingsState extends State { } await widget.matrixRoom.client.setRoomStateWithKey( - widget.matrixRoom.id, EventTypes.RoomCanonicalAlias, "", state); + widget.matrixRoom.id, + EventTypes.RoomCanonicalAlias, + "", + state, + ); setState(() { publishedAliases?.remove(alias); @@ -223,7 +246,11 @@ class _MatrixRoomAddressSettingsState extends State { state["alias"] = newMainAlias; await widget.matrixRoom.client.setRoomStateWithKey( - widget.matrixRoom.id, EventTypes.RoomCanonicalAlias, "", state); + widget.matrixRoom.id, + EventTypes.RoomCanonicalAlias, + "", + state, + ); onMainAliasChanged.add(newMainAlias); } diff --git a/commet/lib/ui/pages/matrix/room_address_settings/matrix_room_address_settings_view.dart b/commet/lib/ui/pages/matrix/room_address_settings/matrix_room_address_settings_view.dart index 67ab7bd3c..3c7bbd2d6 100644 --- a/commet/lib/ui/pages/matrix/room_address_settings/matrix_room_address_settings_view.dart +++ b/commet/lib/ui/pages/matrix/room_address_settings/matrix_room_address_settings_view.dart @@ -10,20 +10,22 @@ import 'package:tiamat/tiamat.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class MatrixRoomAddressSettingsView extends StatefulWidget { - const MatrixRoomAddressSettingsView(this.knownAliases, - {this.mainAlias, - this.userHomeserver, - required this.mainAliasChangedStream, - required this.isAliasAvailable, - required this.canChangeMainAlias, - required this.canAddLocalAlias, - required this.createAlias, - required this.deleteAlias, - required this.setMainAlias, - required this.publishAlias, - required this.unpublishAlias, - required this.publishedAliases, - super.key}); + const MatrixRoomAddressSettingsView( + this.knownAliases, { + this.mainAlias, + this.userHomeserver, + required this.mainAliasChangedStream, + required this.isAliasAvailable, + required this.canChangeMainAlias, + required this.canAddLocalAlias, + required this.createAlias, + required this.deleteAlias, + required this.setMainAlias, + required this.publishAlias, + required this.unpublishAlias, + required this.publishedAliases, + super.key, + }); final List knownAliases; final List publishedAliases; final String? mainAlias; @@ -97,7 +99,8 @@ class _MatrixRoomAddressSettingsViewState height: 50, child: Center( child: tiamat.Text.labelLow( - "This room does not currently have any local Addresses"), + "This room does not currently have any local Addresses", + ), ), ), ImplicitlyAnimatedList( @@ -114,25 +117,26 @@ class _MatrixRoomAddressSettingsViewState IgnorePointer( ignoring: isEditable(data) == false, child: SizedBox( - width: boxSize, - height: boxSize, - child: tiamat.Tooltip( - text: isPublished(data) - ? "Unpublish Address" - : "Publish Address", - child: tiamat.IconToggle( - icon: Icons.public, - size: iconSize, - state: isPublished(data), - onPressed: (newState) { - if (newState) { - widget.publishAlias(data); - } else { - widget.unpublishAlias(data); - } - }, - ), - )), + width: boxSize, + height: boxSize, + child: tiamat.Tooltip( + text: isPublished(data) + ? "Unpublish Address" + : "Publish Address", + child: tiamat.IconToggle( + icon: Icons.public, + size: iconSize, + state: isPublished(data), + onPressed: (newState) { + if (newState) { + widget.publishAlias(data); + } else { + widget.unpublishAlias(data); + } + }, + ), + ), + ), ), Flexible( child: Padding( @@ -182,9 +186,9 @@ class _MatrixRoomAddressSettingsViewState onPressed: showAddAliasDialog, ), ), - ) + ), ], - ) + ), ], ), ); @@ -195,8 +199,11 @@ class _MatrixRoomAddressSettingsViewState context, title: "Add Local Address", builder: (context) { - return MatrixRoomAddLocalAliasView(widget.userHomeserver!, - widget.isAliasAvailable, widget.createAlias); + return MatrixRoomAddLocalAliasView( + widget.userHomeserver!, + widget.isAliasAvailable, + widget.createAlias, + ); }, ); } @@ -212,9 +219,11 @@ class _MatrixRoomAddressSettingsViewState items: widget.knownAliases, value: widget.mainAlias, itemHeight: 60, - hint: tiamat.Text.labelLow(widget.canChangeMainAlias - ? "Select a main room address" - : "This room does not have a set main alias"), + hint: tiamat.Text.labelLow( + widget.canChangeMainAlias + ? "Select a main room address" + : "This room does not have a set main alias", + ), onItemSelected: (item) => widget.setMainAlias(item!), itemBuilder: (item) { return Row( @@ -236,8 +245,10 @@ class _MatrixRoomAddressSettingsViewState } Future deleteAlias(String item) async { - var confirmation = await AdaptiveDialog.confirmation(context, - prompt: "Are you sure you want to delete the address '$item'"); + var confirmation = await AdaptiveDialog.confirmation( + context, + prompt: "Are you sure you want to delete the address '$item'", + ); if (confirmation != true) { return; diff --git a/commet/lib/ui/pages/matrix/verification/matrix_verification_view.dart b/commet/lib/ui/pages/matrix/verification/matrix_verification_view.dart index b9f062280..a093fb069 100644 --- a/commet/lib/ui/pages/matrix/verification/matrix_verification_view.dart +++ b/commet/lib/ui/pages/matrix/verification/matrix_verification_view.dart @@ -10,17 +10,18 @@ import 'package:tiamat/tiamat.dart' as tiamat; import 'package:tiamat/tiamat.dart'; class MatrixVerificationPageView extends StatelessWidget { - const MatrixVerificationPageView( - {required this.state, - required this.sasTypes, - required this.sasNumbers, - required this.sasEmoji, - required this.userID, - super.key, - this.onVerificationRequestAccepted, - this.onVerificationRequestRejected, - this.onSasAccepted, - this.onSasRejected}); + const MatrixVerificationPageView({ + required this.state, + required this.sasTypes, + required this.sasNumbers, + required this.sasEmoji, + required this.userID, + super.key, + this.onVerificationRequestAccepted, + this.onVerificationRequestRejected, + this.onSasAccepted, + this.onSasRejected, + }); final Function? onVerificationRequestAccepted; final Function? onVerificationRequestRejected; @@ -34,37 +35,42 @@ class MatrixVerificationPageView extends StatelessWidget { final KeyVerificationState state; String get messageWaitingOtherDeviceToAccept => Intl.message( - "Waiting for the other device to accept the request", - name: "messageWaitingOtherDeviceToAccept", - desc: - "Message to show while waiting for another device to accept a matrix session verification request"); - - String messageMatrixSessionVerificationRequest(String username) => Intl.message( - "**$username** has requested to verify your session", - desc: - "Message to show when another user has requested to verify your matrix session. Supports markdown to emphasise the user name", - args: [username], - name: "messageMatrixSessionVerificationRequest"); + "Waiting for the other device to accept the request", + name: "messageWaitingOtherDeviceToAccept", + desc: "Message to show while waiting for another device to accept a matrix session verification request", + ); + + String messageMatrixSessionVerificationRequest(String username) => + Intl.message( + "**$username** has requested to verify your session", + desc: "Message to show when another user has requested to verify your matrix session. Supports markdown to emphasise the user name", + args: [username], + name: "messageMatrixSessionVerificationRequest", + ); String get messageSasEmojiVerificationPrompt => Intl.message( - "Check that the emoji are the same, and in the same order as on the other device", - name: "messageSasEmojiVerificationPrompt", - desc: - "Explains what to look for when verifying using emoji. Needs to portray that the emoji MUST be the same AND in the same order"); - - String get promptConfirmEmojiMatches => Intl.message("They match!", - name: "promptConfirmEmojiMatches", - desc: "Button text to confirm that the emoji matches"); - - String get promptEmojiDoNotMatch => Intl.message("They don't match", - name: "promptEmojiDoNotMatch", - desc: "Button text to confirm that the emoji do NOT match"); + "Check that the emoji are the same, and in the same order as on the other device", + name: "messageSasEmojiVerificationPrompt", + desc: "Explains what to look for when verifying using emoji. Needs to portray that the emoji MUST be the same AND in the same order", + ); + + String get promptConfirmEmojiMatches => Intl.message( + "They match!", + name: "promptConfirmEmojiMatches", + desc: "Button text to confirm that the emoji matches", + ); + + String get promptEmojiDoNotMatch => Intl.message( + "They don't match", + name: "promptEmojiDoNotMatch", + desc: "Button text to confirm that the emoji do NOT match", + ); String get messageVerificationComplete => Intl.message( - "Verification Complete!", - name: "messageVerificationComplete", - desc: - "Message to show when verification was completed successfully, and the session has been verified"); + "Verification Complete!", + name: "messageVerificationComplete", + desc: "Message to show when verification was completed successfully, and the session has been verified", + ); @override Widget build(BuildContext context) { @@ -83,7 +89,7 @@ class MatrixVerificationPageView extends StatelessWidget { return Column( children: [ tiamat.Text.label(messageWaitingOtherDeviceToAccept), - loading(context) + loading(context), ], ); case KeyVerificationState.waitingSas: @@ -98,8 +104,10 @@ class MatrixVerificationPageView extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( - child: Markdown( - data: messageMatrixSessionVerificationRequest(userID))), + child: Markdown( + data: messageMatrixSessionVerificationRequest(userID), + ), + ), Column( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.stretch, @@ -108,8 +116,9 @@ class MatrixVerificationPageView extends StatelessWidget { Padding( padding: const EdgeInsets.all(8.0), child: Button.success( - text: CommonStrings.promptAccept, - onTap: onVerificationRequestAccepted?.call), + text: CommonStrings.promptAccept, + onTap: onVerificationRequestAccepted?.call, + ), ), Padding( padding: const EdgeInsets.all(8.0), @@ -117,7 +126,7 @@ class MatrixVerificationPageView extends StatelessWidget { text: CommonStrings.promptReject, onTap: onVerificationRequestRejected?.call, ), - ) + ), ], ), ], @@ -144,23 +153,22 @@ class MatrixVerificationPageView extends StatelessWidget { alignment: WrapAlignment.center, crossAxisAlignment: WrapCrossAlignment.center, children: sasEmoji - .map((e) => Padding( - padding: const EdgeInsets.all(1.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - EmojiWidget( - UnicodeEmoticon(e.emoji), - height: 30, - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: tiamat.Text.tiny(e.name), - ) - ], - ), - )) + .map( + (e) => Padding( + padding: const EdgeInsets.all(1.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + EmojiWidget(UnicodeEmoticon(e.emoji), height: 30), + Padding( + padding: const EdgeInsets.all(8.0), + child: tiamat.Text.tiny(e.name), + ), + ], + ), + ), + ) .toList(), ), ), @@ -174,8 +182,9 @@ class MatrixVerificationPageView extends StatelessWidget { Padding( padding: const EdgeInsets.all(8.0), child: Button.success( - text: promptConfirmEmojiMatches, - onTap: onSasAccepted?.call), + text: promptConfirmEmojiMatches, + onTap: onSasAccepted?.call, + ), ), Padding( padding: const EdgeInsets.all(8.0), @@ -183,10 +192,10 @@ class MatrixVerificationPageView extends StatelessWidget { text: promptEmojiDoNotMatch, onTap: onSasRejected?.call, ), - ) + ), ], ), - ) + ), ], ); } @@ -195,21 +204,24 @@ class MatrixVerificationPageView extends StatelessWidget { Widget done(BuildContext context) { return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Expanded( - child: Center( - child: Icon( - Icons.verified_user_rounded, - color: Colors.green, - size: 100, - ))), - Button.success( - text: messageVerificationComplete, - onTap: () => Navigator.pop(context), - ) - ]); + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Expanded( + child: Center( + child: Icon( + Icons.verified_user_rounded, + color: Colors.green, + size: 100, + ), + ), + ), + Button.success( + text: messageVerificationComplete, + onTap: () => Navigator.pop(context), + ), + ], + ); } Widget loading(BuildContext context) { diff --git a/commet/lib/ui/pages/settings/app_settings_page.dart b/commet/lib/ui/pages/settings/app_settings_page.dart index f9b861ad7..6709c64e4 100644 --- a/commet/lib/ui/pages/settings/app_settings_page.dart +++ b/commet/lib/ui/pages/settings/app_settings_page.dart @@ -11,10 +11,13 @@ class AppSettingsPage extends StatelessWidget { @override Widget build(BuildContext context) { - return SettingsPage(showDonateButton: true, settings: [ - if (clientManager!.clients.isNotEmpty) SettingsCategoryAccount(), - SettingsCategoryApp(), - SettingsCategoryAbout(), - ]); + return SettingsPage( + showDonateButton: true, + settings: [ + if (clientManager!.clients.isNotEmpty) SettingsCategoryAccount(), + SettingsCategoryApp(), + SettingsCategoryAbout(), + ], + ); } } diff --git a/commet/lib/ui/pages/settings/categories/about/settings_category_about.dart b/commet/lib/ui/pages/settings/categories/about/settings_category_about.dart index f184f3a61..1e20611e7 100644 --- a/commet/lib/ui/pages/settings/categories/about/settings_category_about.dart +++ b/commet/lib/ui/pages/settings/categories/about/settings_category_about.dart @@ -21,34 +21,38 @@ import 'package:vodozemac/vodozemac.dart' as vod; import 'package:intl/intl.dart' as intl; class SettingsCategoryAbout implements SettingsCategory { - String get labelSettingsAppLogs => Intl.message("Logs", - name: "labelSettingsAppLogs", - desc: - "Label for the logs settings page, usually hidden unless developer mode is turned on"); + String get labelSettingsAppLogs => Intl.message( + "Logs", + name: "labelSettingsAppLogs", + desc: "Label for the logs settings page, usually hidden unless developer mode is turned on", + ); - String get labelSettingsAppInfo => Intl.message("About", - name: "labelSettingsAppInfo", - desc: "Label for the app info settings page"); + String get labelSettingsAppInfo => Intl.message( + "About", + name: "labelSettingsAppInfo", + desc: "Label for the app info settings page", + ); @override List get tabs => List.from([ - SettingsTab( - label: labelSettingsAppInfo, - icon: Icons.info_outline, - makeScrollable: false, - pageBuilder: (context) { - return const _AppInfo(); - }), - if (preferences.developerMode.value) - SettingsTab( - label: labelSettingsAppLogs, - icon: m.Icons.text_snippet, - makeScrollable: false, - pageBuilder: (context) { - return LogPage(Log.log); - }, - ) - ]); + SettingsTab( + label: labelSettingsAppInfo, + icon: Icons.info_outline, + makeScrollable: false, + pageBuilder: (context) { + return const _AppInfo(); + }, + ), + if (preferences.developerMode.value) + SettingsTab( + label: labelSettingsAppLogs, + icon: m.Icons.text_snippet, + makeScrollable: false, + pageBuilder: (context) { + return LogPage(Log.log); + }, + ), + ]); static Widget info(BuildContext context) { return SizedBox( @@ -61,33 +65,39 @@ class SettingsCategoryAbout implements SettingsCategory { const tiamat.Text.label(" · "), Text.rich( TextSpan( - style: const TextStyle(decoration: TextDecoration.underline), - text: "Source Code", - recognizer: TapGestureRecognizer() - ..onTap = () => LinkUtils.open( - Uri.parse("https://github.com/commetchat/commet"), - context: context)), + style: const TextStyle(decoration: TextDecoration.underline), + text: "Source Code", + recognizer: TapGestureRecognizer() + ..onTap = () => LinkUtils.open( + Uri.parse("https://github.com/commetchat/commet"), + context: context, + ), + ), ), const tiamat.Text.label(" · "), Text.rich( TextSpan( - style: const TextStyle(decoration: TextDecoration.underline), - text: "License", - recognizer: TapGestureRecognizer() - ..onTap = () => LinkUtils.open( - Uri.parse( - "https://github.com/commetchat/commet/blob/main/LICENSE"), - context: context)), + style: const TextStyle(decoration: TextDecoration.underline), + text: "License", + recognizer: TapGestureRecognizer() + ..onTap = () => LinkUtils.open( + Uri.parse( + "https://github.com/commetchat/commet/blob/main/LICENSE", + ), + context: context, + ), + ), ), const tiamat.Text.label(" · "), Text.rich( TextSpan( - style: const TextStyle(decoration: TextDecoration.underline), - text: "Open Source Licenses", - recognizer: TapGestureRecognizer() - ..onTap = () { - showLicensePage(context: context); - }), + style: const TextStyle(decoration: TextDecoration.underline), + text: "Open Source Licenses", + recognizer: TapGestureRecognizer() + ..onTap = () { + showLicensePage(context: context); + }, + ), ), ], ), @@ -136,7 +146,8 @@ class _AppInfoState extends State<_AppInfo> { child: SvgPicture.asset( "assets/images/app_icon/icon.svg", theme: SvgTheme( - currentColor: Theme.of(context).colorScheme.onSurface), + currentColor: Theme.of(context).colorScheme.onSurface, + ), ), ), ), @@ -149,27 +160,34 @@ class _AppInfoState extends State<_AppInfo> { children: [ const tiamat.Text.largeTitle(BuildConfig.appName), const tiamat.Text.labelEmphasised( - BuildConfig.VERSION_TAG), + BuildConfig.VERSION_TAG, + ), + tiamat.Text.labelLow( + "${BuildConfig.GIT_HASH.substring(0, 7)} ${BuildConfig.BUILD_DETAIL}", + ), tiamat.Text.labelLow( - "${BuildConfig.GIT_HASH.substring(0, 7)} ${BuildConfig.BUILD_DETAIL}"), - tiamat.Text.labelLow("Built: " + - intl.DateFormat(intl.DateFormat.YEAR_MONTH_DAY) - .format(BuildConfig.BUILD_DATE)), + "Built: " + + intl.DateFormat(intl.DateFormat.YEAR_MONTH_DAY) + .format(BuildConfig.BUILD_DATE), + ), if (deviceInfo != null) Row( spacing: 10, children: [ if (deviceInfo!.data["name"] is String) tiamat.Text.labelLow( - deviceInfo!.data["name"]!.toString()), + deviceInfo!.data["name"]!.toString(), + ), if (deviceInfo!.data["version"] is String) tiamat.Text.labelLow( - deviceInfo!.data["version"]!.toString()), + deviceInfo!.data["version"]!.toString(), + ), if (PlatformUtils.isLinux) tiamat.Text.labelLow(PlatformUtils.displayServer), if (PlatformUtils.desktopEnvironment != null) tiamat.Text.labelLow( - PlatformUtils.desktopEnvironment!) + PlatformUtils.desktopEnvironment!, + ), ], ), if (Subplatforms.subplatform != null) @@ -177,7 +195,7 @@ class _AppInfoState extends State<_AppInfo> { if (preferences.developerMode.value) tiamat.Text.labelLow(getEncryptionInfo()), if (preferences.developerMode.value) - tiamat.Text.labelLow(commandLineArgs.join(" ")) + tiamat.Text.labelLow(commandLineArgs.join(" ")), ], ), Padding( @@ -192,7 +210,7 @@ class _AppInfoState extends State<_AppInfo> { ), ], ), - SettingsCategoryAbout.info(context) + SettingsCategoryAbout.info(context), ], ); } @@ -217,7 +235,8 @@ class _AppInfoState extends State<_AppInfo> { } void copySystemInfo() { - var data = """ + var data = + """
Device Information
diff --git a/commet/lib/ui/pages/settings/categories/account/account_emoji/account_emoji_tab.dart b/commet/lib/ui/pages/settings/categories/account/account_emoji/account_emoji_tab.dart index d9f17f1bf..bde4b587b 100644 --- a/commet/lib/ui/pages/settings/categories/account/account_emoji/account_emoji_tab.dart +++ b/commet/lib/ui/pages/settings/categories/account/account_emoji/account_emoji_tab.dart @@ -12,8 +12,11 @@ import 'package:flutter/widgets.dart'; import '../../../../../molecules/account_selector.dart'; class AccountEmojiTab extends StatefulWidget { - const AccountEmojiTab( - {required this.clientManager, this.selectedClientIndex = 0, super.key}); + const AccountEmojiTab({ + required this.clientManager, + this.selectedClientIndex = 0, + super.key, + }); final ClientManager clientManager; final int selectedClientIndex; @override @@ -45,10 +48,8 @@ class _AccountEmojiTabState extends State { }); }, ), - const SizedBox( - height: 10, - ), - buildEmojiView(context) + const SizedBox(height: 10), + buildEmojiView(context), ], ); } @@ -62,13 +63,8 @@ class _AccountEmojiTabState extends State { // I dont love using a key here, is there a better way to do this? i dont know key: ValueKey("account_emoji_editor_key_${selectedClient!.identifier}"), children: [ - RoomEmojiPackSettingsView( - component: component!, - editable: true, - ), - const SizedBox( - height: 5, - ), + RoomEmojiPackSettingsView(component: component!, editable: true), + const SizedBox(height: 5), if (component!.globalPacks().isNotEmpty) AccountEmojiView(component!), ], ); diff --git a/commet/lib/ui/pages/settings/categories/account/account_emoji/account_emoji_view.dart b/commet/lib/ui/pages/settings/categories/account/account_emoji/account_emoji_view.dart index a4f637dac..158855484 100644 --- a/commet/lib/ui/pages/settings/categories/account/account_emoji/account_emoji_view.dart +++ b/commet/lib/ui/pages/settings/categories/account/account_emoji/account_emoji_view.dart @@ -37,8 +37,9 @@ class _AccountEmojiViewState extends State { tiamat.Panel( header: "Favorite Packs", mode: tiamat.TileType.surfaceContainerLow, - child: - Column(children: globalPacks.map((e) => packSummary(e)).toList()), + child: Column( + children: globalPacks.map((e) => packSummary(e)).toList(), + ), ), ], ); @@ -70,9 +71,11 @@ class _AccountEmojiViewState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ tiamat.Text.labelEmphasised(pack.displayName), - tiamat.Text.labelLow(preferences.developerMode.value - ? "${pack.ownerDisplayName} - (${pack.ownerId})" - : pack.ownerDisplayName), + tiamat.Text.labelLow( + preferences.developerMode.value + ? "${pack.ownerDisplayName} - (${pack.ownerId})" + : pack.ownerDisplayName, + ), ], ), ), @@ -85,7 +88,7 @@ class _AccountEmojiViewState extends State { icon: Icons.heart_broken, onPressed: () => pack.markAsGlobal(false), ), - ) + ), ], ), ), diff --git a/commet/lib/ui/pages/settings/categories/account/account_management/account_management_tab.dart b/commet/lib/ui/pages/settings/categories/account/account_management/account_management_tab.dart index 2125a41b6..6a3462df7 100644 --- a/commet/lib/ui/pages/settings/categories/account/account_management/account_management_tab.dart +++ b/commet/lib/ui/pages/settings/categories/account/account_management/account_management_tab.dart @@ -17,8 +17,9 @@ import 'package:tiamat/tiamat.dart'; class AccountManagementSettingsTab extends StatefulWidget { const AccountManagementSettingsTab({super.key, required this.clientManager}); - static ValueKey addAccountKey = - const ValueKey("ACCOUNT_MANAGEMENT_SETTINGS_ADD_ACCOUNT_BUTTON"); + static ValueKey addAccountKey = const ValueKey( + "ACCOUNT_MANAGEMENT_SETTINGS_ADD_ACCOUNT_BUTTON", + ); final ClientManager clientManager; @override State createState() => @@ -32,17 +33,23 @@ class _AccountManagementSettingsTabState final GlobalKey _listKey = GlobalKey(); late int _numClients; - String get promptAddAccount => Intl.message("Add Account", - desc: "Label for button in settings to add another account", - name: "promptAddAccount"); + String get promptAddAccount => Intl.message( + "Add Account", + desc: "Label for button in settings to add another account", + name: "promptAddAccount", + ); - String get promptLogoutSingleAccount => Intl.message("Logout", - desc: "Label for button in settings to log out of an account", - name: "promptLogoutSingleAccount"); + String get promptLogoutSingleAccount => Intl.message( + "Logout", + desc: "Label for button in settings to log out of an account", + name: "promptLogoutSingleAccount", + ); - String get labelCurrentAccountsHeader => Intl.message("Current Accounts", - desc: "Label for header of accounts list", - name: "labelCurrentAccountsHeader"); + String get labelCurrentAccountsHeader => Intl.message( + "Current Accounts", + desc: "Label for header of accounts list", + name: "labelCurrentAccountsHeader", + ); @override Widget build(BuildContext context) { @@ -51,26 +58,29 @@ class _AccountManagementSettingsTabState @override void initState() { - onClientAddedListener = - widget.clientManager.onClientAdded.stream.listen((index) { + onClientAddedListener = widget.clientManager.onClientAdded.stream.listen(( + index, + ) { _listKey.currentState?.insertItem(index); setState(() { _numClients++; }); }); - onClientRemovedListener = - widget.clientManager.onClientRemoved.stream.listen((info) { - _listKey.currentState?.removeItem( - info.index, - (context, animation) => SizeTransition( - sizeFactor: animation, - child: accountListItem( - displayName: info.displayName!, - avatar: info.avatar, - detail: info.identifier), - )); - }); + onClientRemovedListener = widget.clientManager.onClientRemoved.stream + .listen((info) { + _listKey.currentState?.removeItem( + info.index, + (context, animation) => SizeTransition( + sizeFactor: animation, + child: accountListItem( + displayName: info.displayName!, + avatar: info.avatar, + detail: info.identifier, + ), + ), + ); + }); _numClients = widget.clientManager.clients.length; @@ -101,7 +111,7 @@ class _AccountManagementSettingsTabState crossAxisAlignment: CrossAxisAlignment.start, children: [ accountListBuilder(context, clientManager), - addAccountButton(context) + addAccountButton(context), ], ), ), @@ -122,25 +132,26 @@ class _AccountManagementSettingsTabState return SizeTransition( sizeFactor: animation, child: accountListItem( - client: clients[index], - displayName: clients[index].self!.displayName, - avatar: clients[index].self!.avatar, - detail: clients[index].self!.identifier, - internalId: clients[index].identifier, - onLogoutClicked: () => - clientmanager.logoutClient(clients[index])), + client: clients[index], + displayName: clients[index].self!.displayName, + avatar: clients[index].self!.avatar, + detail: clients[index].self!.identifier, + internalId: clients[index].identifier, + onLogoutClicked: () => clientmanager.logoutClient(clients[index]), + ), ); }, ); } - Widget accountListItem( - {required String displayName, - Client? client, - ImageProvider? avatar, - String? detail, - String? internalId, - Function? onLogoutClicked}) { + Widget accountListItem({ + required String displayName, + Client? client, + ImageProvider? avatar, + String? detail, + String? internalId, + Function? onLogoutClicked, + }) { String detailString = detail ?? ""; if (preferences.developerMode.value && internalId != null) { @@ -160,10 +171,11 @@ class _AccountManagementSettingsTabState : [ if (_numClients > 1) tiamat.ContextMenuItem( - text: "Set Prefix", - onPressed: () { - setPrefixDialog(client); - }) + text: "Set Prefix", + onPressed: () { + setPrefixDialog(client); + }, + ), ], child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -182,7 +194,7 @@ class _AccountManagementSettingsTabState onTap: () { onLogoutClicked?.call(); }, - ) + ), ], ), ), @@ -198,12 +210,12 @@ class _AccountManagementSettingsTabState } final newPrefix = await AdaptiveTextDialog.show( - title: "Set Prefix", - placeholder: "Enter Prefix", - description: - "When more than one of your logged in accounts share the same room, you can type this prefix to quickly send messages from this account", - context, - defaultText: component.clientPrefix); + title: "Set Prefix", + placeholder: "Enter Prefix", + description: "When more than one of your logged in accounts share the same room, you can type this prefix to quickly send messages from this account", + context, + defaultText: component.clientPrefix, + ); if (newPrefix == null) { return; } @@ -215,35 +227,36 @@ class _AccountManagementSettingsTabState return Padding( padding: const EdgeInsets.fromLTRB(0, 8, 12, 12), child: Align( - alignment: Alignment.centerRight, - child: JustTheTooltip( - content: Padding( - padding: const EdgeInsets.all(8.0), - child: tiamat.Text(promptAddAccount), - ), - preferredDirection: AxisDirection.down, - offset: 5, - tailLength: 5, - tailBaseWidth: 5, - backgroundColor: - Theme.of(context).colorScheme.surfaceContainerLowest, - child: tiamat.CircleButton( - key: AccountManagementSettingsTab.addAccountKey, - icon: Icons.add, - radius: 20, - onPressed: () { - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => LoginPage( - canNavigateBack: true, - onSuccess: ( - _, - ) { - Navigator.of(context).pop(); - }, - ))); - }, - ), - )), + alignment: Alignment.centerRight, + child: JustTheTooltip( + content: Padding( + padding: const EdgeInsets.all(8.0), + child: tiamat.Text(promptAddAccount), + ), + preferredDirection: AxisDirection.down, + offset: 5, + tailLength: 5, + tailBaseWidth: 5, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLowest, + child: tiamat.CircleButton( + key: AccountManagementSettingsTab.addAccountKey, + icon: Icons.add, + radius: 20, + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => LoginPage( + canNavigateBack: true, + onSuccess: (_) { + Navigator.of(context).pop(); + }, + ), + ), + ); + }, + ), + ), + ), ); } } diff --git a/commet/lib/ui/pages/settings/categories/account/account_state/account_state_tab.dart b/commet/lib/ui/pages/settings/categories/account/account_state/account_state_tab.dart index de26582b3..48ac19e19 100644 --- a/commet/lib/ui/pages/settings/categories/account/account_state/account_state_tab.dart +++ b/commet/lib/ui/pages/settings/categories/account/account_state/account_state_tab.dart @@ -6,8 +6,11 @@ import 'package:flutter/widgets.dart'; import '../../../../../molecules/account_selector.dart'; class AccountStateTab extends StatefulWidget { - const AccountStateTab( - {required this.clientManager, this.selectedClientIndex = 0, super.key}); + const AccountStateTab({ + required this.clientManager, + this.selectedClientIndex = 0, + super.key, + }); final ClientManager clientManager; final int selectedClientIndex; @override @@ -36,7 +39,7 @@ class _AccountStateTabState extends State { }); }, ), - selectedClient!.buildDebugInfo() + selectedClient!.buildDebugInfo(), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/account/preferences/preferences_chat_privacy.dart b/commet/lib/ui/pages/settings/categories/account/preferences/preferences_chat_privacy.dart index 2a40a810d..3cdcce32b 100644 --- a/commet/lib/ui/pages/settings/categories/account/preferences/preferences_chat_privacy.dart +++ b/commet/lib/ui/pages/settings/categories/account/preferences/preferences_chat_privacy.dart @@ -22,42 +22,48 @@ class _ChatPrivacyPreferences extends State { InvitationComponent get invitationsComponent => widget.client.getComponent()!; - String get labelChatPrivacyTitle => Intl.message("Chat Privacy", - desc: "Header for the chat privacy section in settings", - name: "labelChatPrivacyTitle"); + String get labelChatPrivacyTitle => Intl.message( + "Chat Privacy", + desc: "Header for the chat privacy section in settings", + name: "labelChatPrivacyTitle", + ); - String get labelPublicReadReceiptsToggle => Intl.message("Read receipts", - desc: - "Label for the toggle for enabling and disabling sending read receipts", - name: "labelPublicReadReceiptsToggle"); + String get labelPublicReadReceiptsToggle => Intl.message( + "Read receipts", + desc: + "Label for the toggle for enabling and disabling sending read receipts", + name: "labelPublicReadReceiptsToggle", + ); String get labelPublicReadReceiptsDescription => Intl.message( - "Let other members of a room know when you have read their messages.", - desc: - "description for the toggle for enabling and disabling sending read receipts", - name: "labelPublicReadReceiptsDescription"); + "Let other members of a room know when you have read their messages.", + desc: "description for the toggle for enabling and disabling sending read receipts", + name: "labelPublicReadReceiptsDescription", + ); - String get labelTypingIndicatorsToggle => Intl.message("Typing indicator", - desc: - "Label for the toggle for enabling and disabling sending typing indicator", - name: "labelTypingIndicatorsToggle"); + String get labelTypingIndicatorsToggle => Intl.message( + "Typing indicator", + desc: "Label for the toggle for enabling and disabling sending typing indicator", + name: "labelTypingIndicatorsToggle", + ); String get labelPublicTypingIndicatorDescription => Intl.message( - "Let other members of a room know when you are typing a message.", - desc: - "description for the toggle for enabling and disabling sending typing indicator", - name: "labelPublicTypingIndicatorDescription"); + "Let other members of a room know when you are typing a message.", + desc: "description for the toggle for enabling and disabling sending typing indicator", + name: "labelPublicTypingIndicatorDescription", + ); - String get labelAllowInvitationsToggle => Intl.message("Allow invitations", - desc: - "Label for the toggle for enabling and disabling the automatic blocking of invitations", - name: "labelAllowInvitationsToggle"); + String get labelAllowInvitationsToggle => Intl.message( + "Allow invitations", + desc: "Label for the toggle for enabling and disabling the automatic blocking of invitations", + name: "labelAllowInvitationsToggle", + ); String get labelAllowInvitationsDescription => Intl.message( - "Allow other users to invite you to rooms", - desc: - "description for the toggle for enabling and disabling the automatic blocking of invitations", - name: "labelAllowInvitationsDescription"); + "Allow other users to invite you to rooms", + desc: "description for the toggle for enabling and disabling the automatic blocking of invitations", + name: "labelAllowInvitationsDescription", + ); @override void initState() { @@ -69,38 +75,40 @@ class _ChatPrivacyPreferences extends State { return tiamat.Panel( header: labelChatPrivacyTitle, mode: tiamat.TileType.surfaceContainerLow, - child: Column(children: [ - BooleanToggle( - setValue: (value) async { - await ErrorUtils.tryRun(context, () async { - await userPresenceComponent.setUsePublicReadReceipts(value); - }); - }, - getValue: () => userPresenceComponent.usePublicReadReceipts, - title: labelPublicReadReceiptsToggle, - description: labelPublicReadReceiptsDescription, - ), - BooleanToggle( - setValue: (value) async { - await ErrorUtils.tryRun(context, () async { - await userPresenceComponent.setTypingIndicatorEnabled(value); - }); - }, - getValue: () => userPresenceComponent.typingIndicatorEnabled, - title: labelTypingIndicatorsToggle, - description: labelPublicTypingIndicatorDescription, - ), - BooleanToggle( - setValue: (value) async { - await ErrorUtils.tryRun(context, () async { - await invitationsComponent.setInvitationsAllowed(value); - }); - }, - getValue: () => invitationsComponent.allowInvitations, - title: labelAllowInvitationsToggle, - description: labelAllowInvitationsDescription, - ), - ]), + child: Column( + children: [ + BooleanToggle( + setValue: (value) async { + await ErrorUtils.tryRun(context, () async { + await userPresenceComponent.setUsePublicReadReceipts(value); + }); + }, + getValue: () => userPresenceComponent.usePublicReadReceipts, + title: labelPublicReadReceiptsToggle, + description: labelPublicReadReceiptsDescription, + ), + BooleanToggle( + setValue: (value) async { + await ErrorUtils.tryRun(context, () async { + await userPresenceComponent.setTypingIndicatorEnabled(value); + }); + }, + getValue: () => userPresenceComponent.typingIndicatorEnabled, + title: labelTypingIndicatorsToggle, + description: labelPublicTypingIndicatorDescription, + ), + BooleanToggle( + setValue: (value) async { + await ErrorUtils.tryRun(context, () async { + await invitationsComponent.setInvitationsAllowed(value); + }); + }, + getValue: () => invitationsComponent.allowInvitations, + title: labelAllowInvitationsToggle, + description: labelAllowInvitationsDescription, + ), + ], + ), ); } } diff --git a/commet/lib/ui/pages/settings/categories/account/preferences/preferences_tab.dart b/commet/lib/ui/pages/settings/categories/account/preferences/preferences_tab.dart index a2a18137d..c1d4cf219 100644 --- a/commet/lib/ui/pages/settings/categories/account/preferences/preferences_tab.dart +++ b/commet/lib/ui/pages/settings/categories/account/preferences/preferences_tab.dart @@ -34,13 +34,13 @@ class _AccountSettingsTabState extends State { }); }, ), - const SizedBox( - height: 4, - ), + const SizedBox(height: 4), ChatPrivacyPreferences( - client: selectedClient, - key: ValueKey( - "chat-privacy-preferences_${selectedClient.identifier}")), + client: selectedClient, + key: ValueKey( + "chat-privacy-preferences_${selectedClient.identifier}", + ), + ), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/account/profile/profile_edit_tab.dart b/commet/lib/ui/pages/settings/categories/account/profile/profile_edit_tab.dart index af227af56..f45a067d1 100644 --- a/commet/lib/ui/pages/settings/categories/account/profile/profile_edit_tab.dart +++ b/commet/lib/ui/pages/settings/categories/account/profile/profile_edit_tab.dart @@ -7,8 +7,11 @@ import 'package:flutter/widgets.dart'; import 'package:tiamat/tiamat.dart'; class ProfileEditTab extends StatefulWidget { - const ProfileEditTab( - {required this.clientManager, this.selectedClientIndex = 0, super.key}); + const ProfileEditTab({ + required this.clientManager, + this.selectedClientIndex = 0, + super.key, + }); final ClientManager clientManager; final int selectedClientIndex; @override @@ -38,7 +41,7 @@ class _ProfileEditTabState extends State { client: client, maxBioHeight: double.infinity, ), - const Seperator() + const Seperator(), ], ); }, diff --git a/commet/lib/ui/pages/settings/categories/account/security/matrix/cross_signing/cross_signing_page.dart b/commet/lib/ui/pages/settings/categories/account/security/matrix/cross_signing/cross_signing_page.dart index e42146928..9647144c1 100644 --- a/commet/lib/ui/pages/settings/categories/account/security/matrix/cross_signing/cross_signing_page.dart +++ b/commet/lib/ui/pages/settings/categories/account/security/matrix/cross_signing/cross_signing_page.dart @@ -9,15 +9,16 @@ enum MatrixCrossSigningMode { enableBackup, restoreBackup, resetCrossSigning, - crossSigningOnly + crossSigningOnly, } class MatrixCrossSigningPage extends StatefulWidget { - const MatrixCrossSigningPage( - {required this.client, - this.mode = MatrixCrossSigningMode.standard, - super.key, - this.onComplete}); + const MatrixCrossSigningPage({ + required this.client, + this.mode = MatrixCrossSigningMode.standard, + super.key, + this.onComplete, + }); final MatrixClient client; final MatrixCrossSigningMode mode; final Function()? onComplete; @@ -73,8 +74,9 @@ class MatrixCrossSigningPageState extends State { await bootstrapper?.openExistingSsss(); if (bootstrapper!.encryption.crossSigning.enabled) { - await bootstrapper?.client.encryption!.crossSigning - .selfSign(keyOrPassphrase: key); + await bootstrapper?.client.encryption!.crossSigning.selfSign( + keyOrPassphrase: key, + ); } }, wipeCrossSigning: (wipe) { diff --git a/commet/lib/ui/pages/settings/categories/account/security/matrix/cross_signing/cross_signing_view.dart b/commet/lib/ui/pages/settings/categories/account/security/matrix/cross_signing/cross_signing_view.dart index 2a81ffb8a..a5d352a22 100644 --- a/commet/lib/ui/pages/settings/categories/account/security/matrix/cross_signing/cross_signing_view.dart +++ b/commet/lib/ui/pages/settings/categories/account/security/matrix/cross_signing/cross_signing_view.dart @@ -11,17 +11,19 @@ import 'package:matrix/encryption.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class MatrixCrossSigningView extends StatefulWidget { - const MatrixCrossSigningView(this.state, - {super.key, - this.onSetNewSsss, - this.onAskSetupCrossSigning, - this.recoveryKey, - this.onAskSetupOnlineBackup, - this.useExistingKeys, - this.wipeSsss, - this.wipeExistingBackup, - this.openExistingSsss, - this.wipeCrossSigning}); + const MatrixCrossSigningView( + this.state, { + super.key, + this.onSetNewSsss, + this.onAskSetupCrossSigning, + this.recoveryKey, + this.onAskSetupOnlineBackup, + this.useExistingKeys, + this.wipeSsss, + this.wipeExistingBackup, + this.openExistingSsss, + this.wipeCrossSigning, + }); final BootstrapState state; final Function(String?)? onSetNewSsss; @@ -50,162 +52,196 @@ class _MatrixCrossSigningViewState extends State { bool isActionLoading = false; - String get promptWipeMatrixKeys => Intl.message("Wipe Keys", - desc: "Text on the button to wipe matrix encryption keys", - name: "promptWipeMatrixKeys"); + String get promptWipeMatrixKeys => Intl.message( + "Wipe Keys", + desc: "Text on the button to wipe matrix encryption keys", + name: "promptWipeMatrixKeys", + ); - String get promptAbortWipingMatrixKeys => Intl.message("Wait, No!", - desc: "Text on the button which aborts wiping matrix encryption keys", - name: "promptAbortWipingMatrixKeys"); + String get promptAbortWipingMatrixKeys => Intl.message( + "Wait, No!", + desc: "Text on the button which aborts wiping matrix encryption keys", + name: "promptAbortWipingMatrixKeys", + ); - String get promptGenerateMatrixRecoveryKey => Intl.message("Generate Key", - desc: "Button text to generate a recovery key", - name: "promptGenerateMatrixRecoveryKey"); + String get promptGenerateMatrixRecoveryKey => Intl.message( + "Generate Key", + desc: "Button text to generate a recovery key", + name: "promptGenerateMatrixRecoveryKey", + ); String get labelMatrixRecoveryKeyCreateExplanation => Intl.message( - "We need to set a security key, which can be used to access message history. We can either generate a key for you, or you can choose your own security phrase", - desc: - "Explains what the matrix recovery key does, and that it can be generated or user input", - name: "labelMatrixRecoveryKeyCreateExplanation"); - - String get promptSetMatrixPassphrase => Intl.message("Set Phrase", - desc: "Button text to set a passphrase", - name: "promptSetMatrixPassphrase"); - - String get promptUseExistingMatrixKeys => Intl.message("Use Existing Keys", - desc: "Button text to opt to use existing keys", - name: "promptUseExistingMatrixKeys"); - - String get promptCreateNewMatrixKeys => Intl.message("No, create new keys", - desc: "Button text to opt to create new keys", - name: "promptCreateNewMatrixKeys"); - - String get promptWipeMatrixBackup => Intl.message("Wipe backup", - desc: "Button text to wipe the matrix message backup", - name: "promptWipeMatrixBackup"); - - String get promptEnableMatrixBackup => Intl.message("Enable backup", - desc: "Button text to enable to encrypted message backup", - name: "promptEnableMatrixBackup"); + "We need to set a security key, which can be used to access message history. We can either generate a key for you, or you can choose your own security phrase", + desc: "Explains what the matrix recovery key does, and that it can be generated or user input", + name: "labelMatrixRecoveryKeyCreateExplanation", + ); + + String get promptSetMatrixPassphrase => Intl.message( + "Set Phrase", + desc: "Button text to set a passphrase", + name: "promptSetMatrixPassphrase", + ); + + String get promptUseExistingMatrixKeys => Intl.message( + "Use Existing Keys", + desc: "Button text to opt to use existing keys", + name: "promptUseExistingMatrixKeys", + ); + + String get promptCreateNewMatrixKeys => Intl.message( + "No, create new keys", + desc: "Button text to opt to create new keys", + name: "promptCreateNewMatrixKeys", + ); + + String get promptWipeMatrixBackup => Intl.message( + "Wipe backup", + desc: "Button text to wipe the matrix message backup", + name: "promptWipeMatrixBackup", + ); + + String get promptEnableMatrixBackup => Intl.message( + "Enable backup", + desc: "Button text to enable to encrypted message backup", + name: "promptEnableMatrixBackup", + ); String get labelExistingMatrixKeysFound => Intl.message( - "Existing signing keys have been found!", - desc: - "Text that is shown when the user is setting up cross signing, but has existing keys", - name: "labelExistingMatrixKeysFound"); + "Existing signing keys have been found!", + desc: "Text that is shown when the user is setting up cross signing, but has existing keys", + name: "labelExistingMatrixKeysFound", + ); String get labelAskUseExistingMatrixKeys => Intl.message( - "Would you like to use the existing keys?", - desc: - "Text that is shown when the user is setting up cross signing, but has existing keys and asks the user if they would like to use those keys", - name: "labelAskUseExistingMatrixKeys"); + "Would you like to use the existing keys?", + desc: "Text that is shown when the user is setting up cross signing, but has existing keys and asks the user if they would like to use those keys", + name: "labelAskUseExistingMatrixKeys", + ); String get labelMatrixRecoveryKeyExplanation => Intl.message( - "This is your recovery key. You can use it to verify your session if you lose access to all other sessions. Keep it somewhere secure!", - desc: "Gives a brief description about the function on the recovery key", - name: "labelMatrixRecoveryKeyExplanation"); + "This is your recovery key. You can use it to verify your session if you lose access to all other sessions. Keep it somewhere secure!", + desc: "Gives a brief description about the function on the recovery key", + name: "labelMatrixRecoveryKeyExplanation", + ); String get labelMatrixRecoveryKeyPromptExplanation => Intl.message( - "To unlock your old messages, please enter your recovery key that has been generated in a previous session. Your recovery key is NOT your password.", - name: "labelMatrixRecoveryKeyPromptExplanation", - desc: - "Shown when a user is attempting to recover their old messages, explains that they need the recovery key"); - - String get promptMatrixRecoveryKeyInput => Intl.message("Recovery key", - desc: "Placeholder text for the recovery key input box", - name: "promptMatrixRecoveryKeyInput"); - - String get promptConfirmWipingCrossSigningKeys => - Intl.message("Are you sure you want to wipe your cross signing keys?", - desc: "Asks the user if they are sure they want to wipe the keys", - name: "promptConfirmWipingCrossSigningKeys"); + "To unlock your old messages, please enter your recovery key that has been generated in a previous session. Your recovery key is NOT your password.", + name: "labelMatrixRecoveryKeyPromptExplanation", + desc: "Shown when a user is attempting to recover their old messages, explains that they need the recovery key", + ); + + String get promptMatrixRecoveryKeyInput => Intl.message( + "Recovery key", + desc: "Placeholder text for the recovery key input box", + name: "promptMatrixRecoveryKeyInput", + ); + + String get promptConfirmWipingCrossSigningKeys => Intl.message( + "Are you sure you want to wipe your cross signing keys?", + desc: "Asks the user if they are sure they want to wipe the keys", + name: "promptConfirmWipingCrossSigningKeys", + ); String get labelMatrixSecurityPhraseShouldNotBePassword => Intl.message( - "Your security phrase should be different to your account password", - desc: "Tells the user to not use their password as their security phrase", - name: "labelMatrixSecurityPhraseShouldNotBePassword"); + "Your security phrase should be different to your account password", + desc: "Tells the user to not use their password as their security phrase", + name: "labelMatrixSecurityPhraseShouldNotBePassword", + ); String get errorMatrixPassphraseMustContainUpperAndLowercase => Intl.message( - "Passphrase must contain atleast 1 Uppercase and 1 Lowercase letter", - desc: "Explains constraints of recovery passphrase", - name: "errorMatrixPassphraseMustContainUpperAndLowercase"); - - String get errorMatrixPassphraseMustContainNumber => - Intl.message("Passphrase must contain atleast 1 number", - desc: "Explains constraints of recovery passphrase", - name: "errorMatrixPassphraseMustContainNumber"); - - String get errorMatrixPassphraseMustContainSymbol => - Intl.message("Passphrase must contain atleast 1 symbol", - desc: "Explains constraints of recovery passphrase", - name: "errorMatrixPassphraseMustContainSymbol"); - - String get erroMatrixPassphraseMustBeLonger => - Intl.message("Passphrase must be atleast 10 characters long", - desc: "Explains constraints of recovery passphrase", - name: "erroMatrixPassphraseMustBeLonger"); - - String get labelMatrixConfirmSecurityPhrase => - Intl.message("Confirm security phrase:", - desc: "Prompts the user to input their passphrase again", - name: "labelMatrixConfirmSecurityPhrase"); - - String get placeholderMatrixConfirmSecurityPhrase => - Intl.message("Confirm security phrase", - desc: "Placeholder text for the confirm passphrase text input", - name: "placeholderMatrixConfirmSecurityPhrase"); + "Passphrase must contain atleast 1 Uppercase and 1 Lowercase letter", + desc: "Explains constraints of recovery passphrase", + name: "errorMatrixPassphraseMustContainUpperAndLowercase", + ); + + String get errorMatrixPassphraseMustContainNumber => Intl.message( + "Passphrase must contain atleast 1 number", + desc: "Explains constraints of recovery passphrase", + name: "errorMatrixPassphraseMustContainNumber", + ); + + String get errorMatrixPassphraseMustContainSymbol => Intl.message( + "Passphrase must contain atleast 1 symbol", + desc: "Explains constraints of recovery passphrase", + name: "errorMatrixPassphraseMustContainSymbol", + ); + + String get erroMatrixPassphraseMustBeLonger => Intl.message( + "Passphrase must be atleast 10 characters long", + desc: "Explains constraints of recovery passphrase", + name: "erroMatrixPassphraseMustBeLonger", + ); + + String get labelMatrixConfirmSecurityPhrase => Intl.message( + "Confirm security phrase:", + desc: "Prompts the user to input their passphrase again", + name: "labelMatrixConfirmSecurityPhrase", + ); + + String get placeholderMatrixConfirmSecurityPhrase => Intl.message( + "Confirm security phrase", + desc: "Placeholder text for the confirm passphrase text input", + name: "placeholderMatrixConfirmSecurityPhrase", + ); String get errorMatrixPassphrasesDontMatch => Intl.message( - "Passphrases do not match", - desc: - "Error when the user enters passphrase twice and the two dont match", - name: "errorMatrixPassphrasesDontMatch"); - - String get labelMatrixPromptPassphrase => Intl.message("Security phrase:", - desc: "Prompt the user to enter passphrase", - name: "labelMatrixPromptPassphrase"); - - String get placeholderMatrixEnterSecutiyPhrase => - Intl.message("Security phrase", - desc: "Placeholder text for the passphrase text box", - name: "placeholderMatrixEnterSecutiyPhrase"); - - String get labelMatrixExistingMessageBackupFound => - Intl.message("Existing backup found!", - desc: "Message to explain that existing backup has been found", - name: "labelMatrixExistingMessageBackupFound"); + "Passphrases do not match", + desc: "Error when the user enters passphrase twice and the two dont match", + name: "errorMatrixPassphrasesDontMatch", + ); + + String get labelMatrixPromptPassphrase => Intl.message( + "Security phrase:", + desc: "Prompt the user to enter passphrase", + name: "labelMatrixPromptPassphrase", + ); + + String get placeholderMatrixEnterSecutiyPhrase => Intl.message( + "Security phrase", + desc: "Placeholder text for the passphrase text box", + name: "placeholderMatrixEnterSecutiyPhrase", + ); + + String get labelMatrixExistingMessageBackupFound => Intl.message( + "Existing backup found!", + desc: "Message to explain that existing backup has been found", + name: "labelMatrixExistingMessageBackupFound", + ); String get labelMatrixAskWipeBackupToContinue => Intl.message( - "If you are changing your cross signing keys, you will need to wipe your existing backup... Continue?", - desc: - "Asks the user if they want to wipe their existing backup to continue changing their cross signing keys", - name: "labelMatrixAskWipeBackupToContinue"); + "If you are changing your cross signing keys, you will need to wipe your existing backup... Continue?", + desc: "Asks the user if they want to wipe their existing backup to continue changing their cross signing keys", + name: "labelMatrixAskWipeBackupToContinue", + ); String get labelMatrixWarnResetKeysIsPermanent => Intl.message( - "Resetting your keys is permanent, and will result in a loss of your chat history backup. You almost definitely dont want to do this!", - desc: - "Explains that resetting keys is permanent, should emphasize that this isnt really a great idea", - name: "labelMatrixWarnResetKeysIsPermanent"); + "Resetting your keys is permanent, and will result in a loss of your chat history backup. You almost definitely dont want to do this!", + desc: "Explains that resetting keys is permanent, should emphasize that this isnt really a great idea", + name: "labelMatrixWarnResetKeysIsPermanent", + ); - String get labelMatrixAskEnableMessageBackup => - Intl.message("Would you like to enable online key backup?", - desc: "Asks the user if they want to enable online backup", - name: "labelMatrixAskEnableMessageBackup"); + String get labelMatrixAskEnableMessageBackup => Intl.message( + "Would you like to enable online key backup?", + desc: "Asks the user if they want to enable online backup", + name: "labelMatrixAskEnableMessageBackup", + ); String get labelMatrixExplainOnlineKeyBackup => Intl.message( - "Online key backup will allow you to retreive message history in the event that you lose access to all your sessions", - desc: "Explains what the message backup does", - name: "labelMatrixExplainOnlineKeyBackup"); + "Online key backup will allow you to retreive message history in the event that you lose access to all your sessions", + desc: "Explains what the message backup does", + name: "labelMatrixExplainOnlineKeyBackup", + ); @override void initState() { passphraseController.addListener(() { setState(() { passphraseValidity = TextUtils.isValidPassword( - passphraseController.text, - forceDigits: true, - forceLength: 10, - forceSpecialCharacter: true); + passphraseController.text, + forceDigits: true, + forceLength: 10, + forceSpecialCharacter: true, + ); }); }); @@ -294,43 +330,48 @@ class _MatrixCrossSigningViewState extends State { child: m.Padding( padding: const EdgeInsets.fromLTRB(0, 12, 0, 12), child: m.Center( - child: Text( - widget.recoveryKey!, - style: const TextStyle( + child: Text( + widget.recoveryKey!, + style: const TextStyle( fontSize: 12, fontFamily: "Code", - fontFeatures: [FontFeature.disable("calt")]), - )), + fontFeatures: [FontFeature.disable("calt")], + ), + ), + ), ), ), ), tiamat.Button( - text: copyBackupCodeText, - onTap: () { - services.Clipboard.setData( - services.ClipboardData(text: widget.recoveryKey!)); - setState(() { - copyBackupCodeText = CommonStrings.promptCopyComplete; - }); - }), + text: copyBackupCodeText, + onTap: () { + services.Clipboard.setData( + services.ClipboardData(text: widget.recoveryKey!), + ); + setState(() { + copyBackupCodeText = CommonStrings.promptCopyComplete; + }); + }, + ), ], ), tiamat.Button.secondary( - text: CommonStrings.promptConfirm, - isLoading: isActionLoading, - onTap: () async { - setState(() { - isActionLoading = true; - }); - - await ErrorUtils.tryRun(context, () async { - await widget.onAskSetupCrossSigning?.call(); - }); - - setState(() { - isActionLoading = false; - }); - }) + text: CommonStrings.promptConfirm, + isLoading: isActionLoading, + onTap: () async { + setState(() { + isActionLoading = true; + }); + + await ErrorUtils.tryRun(context, () async { + await widget.onAskSetupCrossSigning?.call(); + }); + + setState(() { + isActionLoading = false; + }); + }, + ), ], ); } @@ -351,30 +392,29 @@ class _MatrixCrossSigningViewState extends State { placeholder: promptMatrixRecoveryKeyInput, controller: keyInputController, obscureText: true, - ) + ), ], ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), tiamat.Button( - text: CommonStrings.promptConfirm, - isLoading: isActionLoading, - onTap: () async { - setState(() { - isActionLoading = true; - }); + text: CommonStrings.promptConfirm, + isLoading: isActionLoading, + onTap: () async { + setState(() { + isActionLoading = true; + }); - await Future.delayed(Duration(milliseconds: 300)); + await Future.delayed(Duration(milliseconds: 300)); - await ErrorUtils.tryRun(context, () async { - await widget.openExistingSsss?.call(keyInputController.text); - }); + await ErrorUtils.tryRun(context, () async { + await widget.openExistingSsss?.call(keyInputController.text); + }); - setState(() { - isActionLoading = false; - }); - }) + setState(() { + isActionLoading = false; + }); + }, + ), ], ), ); @@ -392,14 +432,10 @@ class _MatrixCrossSigningViewState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text.label(promptConfirmWipingCrossSigningKeys), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), ], ), - const SizedBox( - height: 50, - ), + const SizedBox(height: 50), Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ @@ -409,15 +445,15 @@ class _MatrixCrossSigningViewState extends State { onTap: () => widget.wipeCrossSigning?.call(true), ), ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), SizedBox( - child: tiamat.Button.secondary( - text: promptAbortWipingMatrixKeys, - onTap: () => widget.wipeCrossSigning?.call(false))) + child: tiamat.Button.secondary( + text: promptAbortWipingMatrixKeys, + onTap: () => widget.wipeCrossSigning?.call(false), + ), + ), ], - ) + ), ], ), ); @@ -425,110 +461,102 @@ class _MatrixCrossSigningViewState extends State { Widget askNewSsss() { return Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - tiamat.Text.body(labelMatrixRecoveryKeyCreateExplanation), - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - SizedBox( - height: 40, - child: tiamat.Button( - text: promptGenerateMatrixRecoveryKey, - onTap: () => widget.onSetNewSsss?.call(null), - ), - ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox( - width: 100, - height: 10, - child: tiamat.Seperator(), - ), - tiamat.Text.labelLow(CommonStrings.labelOr), - const SizedBox( - width: 100, - height: 10, - child: tiamat.Seperator(), - ), - ], - ), - Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: tiamat.Text.label( - labelMatrixSecurityPhraseShouldNotBePassword), - ), - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 4), - child: tiamat.Text.labelLow(labelMatrixPromptPassphrase), - ), - tiamat.TextInput( - controller: passphraseController, - placeholder: placeholderMatrixEnterSecutiyPhrase, - obscureText: true, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + tiamat.Text.body(labelMatrixRecoveryKeyCreateExplanation), + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox( + height: 40, + child: tiamat.Button( + text: promptGenerateMatrixRecoveryKey, + onTap: () => widget.onSetNewSsss?.call(null), ), - if (passphraseValidity == NewPasswordResult.noMixedCase) - tiamat.Text.error( - errorMatrixPassphraseMustContainUpperAndLowercase), - if (passphraseValidity == NewPasswordResult.noNumbers) - tiamat.Text.error(errorMatrixPassphraseMustContainNumber), - if (passphraseValidity == NewPasswordResult.noSymbols) - tiamat.Text.error(errorMatrixPassphraseMustContainSymbol), - if (passphraseValidity == NewPasswordResult.tooShort) - tiamat.Text.error(erroMatrixPassphraseMustBeLonger), - Padding( - padding: const EdgeInsets.fromLTRB(0, 8, 0, 4), - child: tiamat.Text.labelLow(labelMatrixConfirmSecurityPhrase), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(width: 100, height: 10, child: tiamat.Seperator()), + tiamat.Text.labelLow(CommonStrings.labelOr), + const SizedBox(width: 100, height: 10, child: tiamat.Seperator()), + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: tiamat.Text.label( + labelMatrixSecurityPhraseShouldNotBePassword, ), - tiamat.TextInput( - controller: passphraseConfirmController, - obscureText: true, - placeholder: placeholderMatrixConfirmSecurityPhrase, + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 4), + child: tiamat.Text.labelLow(labelMatrixPromptPassphrase), + ), + tiamat.TextInput( + controller: passphraseController, + placeholder: placeholderMatrixEnterSecutiyPhrase, + obscureText: true, + ), + if (passphraseValidity == NewPasswordResult.noMixedCase) + tiamat.Text.error( + errorMatrixPassphraseMustContainUpperAndLowercase, ), - if (passphrasesMatch == false) - tiamat.Text.error(errorMatrixPassphrasesDontMatch), - Padding( - padding: const EdgeInsets.fromLTRB(0, 8, 0, 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - SizedBox( - height: 40, - child: tiamat.Button( - text: promptSetMatrixPassphrase, - onTap: () { - if (passphraseValidity == NewPasswordResult.valid && - passphrasesMatch == true) { - widget.onSetNewSsss - ?.call(passphraseController.text); - } - }, - ), + if (passphraseValidity == NewPasswordResult.noNumbers) + tiamat.Text.error(errorMatrixPassphraseMustContainNumber), + if (passphraseValidity == NewPasswordResult.noSymbols) + tiamat.Text.error(errorMatrixPassphraseMustContainSymbol), + if (passphraseValidity == NewPasswordResult.tooShort) + tiamat.Text.error(erroMatrixPassphraseMustBeLonger), + Padding( + padding: const EdgeInsets.fromLTRB(0, 8, 0, 4), + child: tiamat.Text.labelLow(labelMatrixConfirmSecurityPhrase), + ), + tiamat.TextInput( + controller: passphraseConfirmController, + obscureText: true, + placeholder: placeholderMatrixConfirmSecurityPhrase, + ), + if (passphrasesMatch == false) + tiamat.Text.error(errorMatrixPassphrasesDontMatch), + Padding( + padding: const EdgeInsets.fromLTRB(0, 8, 0, 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox( + height: 40, + child: tiamat.Button( + text: promptSetMatrixPassphrase, + onTap: () { + if (passphraseValidity == NewPasswordResult.valid && + passphrasesMatch == true) { + widget.onSetNewSsss?.call(passphraseController.text); + } + }, ), - ], - ), + ), + ], ), - ], - ), - ]); + ), + ], + ), + ], + ); } Widget loading() { return const m.SizedBox( width: 500, height: 200, - child: Center( - child: m.CircularProgressIndicator(), - ), + child: Center(child: m.CircularProgressIndicator()), ); } @@ -544,15 +572,11 @@ class _MatrixCrossSigningViewState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text.label(labelExistingMatrixKeysFound), - const SizedBox( - height: 20, - ), + const SizedBox(height: 20), tiamat.Text.label(labelAskUseExistingMatrixKeys), ], ), - const SizedBox( - height: 50, - ), + const SizedBox(height: 50), Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ @@ -562,15 +586,15 @@ class _MatrixCrossSigningViewState extends State { onTap: () => widget.useExistingKeys?.call(true), ), ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), SizedBox( - child: tiamat.Button.secondary( - text: promptCreateNewMatrixKeys, - onTap: () => widget.useExistingKeys?.call(false))) + child: tiamat.Button.secondary( + text: promptCreateNewMatrixKeys, + onTap: () => widget.useExistingKeys?.call(false), + ), + ), ], - ) + ), ], ), ); @@ -584,27 +608,23 @@ class _MatrixCrossSigningViewState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text.label(labelAskUseExistingMatrixKeys), - const SizedBox( - height: 20, - ), + const SizedBox(height: 20), tiamat.Text.label(labelMatrixWarnResetKeysIsPermanent), ], ), - const SizedBox( - height: 50, - ), + const SizedBox(height: 50), Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ SizedBox( - width: 200, - child: tiamat.Button( - text: promptUseExistingMatrixKeys, - onTap: () => widget.wipeSsss?.call(false))), - const SizedBox( - height: 10, + width: 200, + child: tiamat.Button( + text: promptUseExistingMatrixKeys, + onTap: () => widget.wipeSsss?.call(false), + ), ), + const SizedBox(height: 10), SizedBox( width: 200, child: tiamat.Button.danger( @@ -613,7 +633,7 @@ class _MatrixCrossSigningViewState extends State { ), ), ], - ) + ), ], ); } @@ -626,15 +646,11 @@ class _MatrixCrossSigningViewState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text.label(labelMatrixAskEnableMessageBackup), - const SizedBox( - height: 20, - ), + const SizedBox(height: 20), tiamat.Text.label(labelMatrixExplainOnlineKeyBackup), ], ), - const SizedBox( - height: 50, - ), + const SizedBox(height: 50), Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.stretch, @@ -646,62 +662,62 @@ class _MatrixCrossSigningViewState extends State { onTap: () => widget.onAskSetupOnlineBackup?.call(true), ), ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), SizedBox( - width: 200, - child: tiamat.Button.secondary( - text: CommonStrings.promptPoliteNo, - onTap: () => widget.onAskSetupOnlineBackup?.call(false))) + width: 200, + child: tiamat.Button.secondary( + text: CommonStrings.promptPoliteNo, + onTap: () => widget.onAskSetupOnlineBackup?.call(false), + ), + ), ], - ) + ), ], ); } Widget done(BuildContext context) { return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: [ - const m.Padding( - padding: EdgeInsets.all(20.0), - child: Center( - child: m.Icon( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + const m.Padding( + padding: EdgeInsets.all(20.0), + child: Center( + child: m.Icon( m.Icons.verified_user_rounded, color: m.Colors.green, size: 100, - )), + ), ), - tiamat.Button.success( - text: CommonStrings.promptDone, - onTap: () => m.Navigator.pop(context), - ) - ]); + ), + tiamat.Button.success( + text: CommonStrings.promptDone, + onTap: () => m.Navigator.pop(context), + ), + ], + ); } Widget error(BuildContext context) { return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: [ - const m.Padding( - padding: EdgeInsets.all(20.0), - child: Center( - child: m.Icon( - m.Icons.error, - color: m.Colors.red, - size: 100, - )), + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + const m.Padding( + padding: EdgeInsets.all(20.0), + child: Center( + child: m.Icon(m.Icons.error, color: m.Colors.red, size: 100), ), - tiamat.Button.secondary( - text: CommonStrings.promptBack, - onTap: () => m.Navigator.pop(context), - ) - ]); + ), + tiamat.Button.secondary( + text: CommonStrings.promptBack, + onTap: () => m.Navigator.pop(context), + ), + ], + ); } Widget askWipeOnlineKeybackup() { @@ -712,15 +728,11 @@ class _MatrixCrossSigningViewState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text.label(labelMatrixExistingMessageBackupFound), - const SizedBox( - height: 20, - ), + const SizedBox(height: 20), tiamat.Text.label(labelMatrixAskWipeBackupToContinue), ], ), - const SizedBox( - height: 50, - ), + const SizedBox(height: 50), Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.stretch, @@ -732,16 +744,16 @@ class _MatrixCrossSigningViewState extends State { onTap: () => widget.wipeExistingBackup?.call(true), ), ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), SizedBox( - width: 200, - child: tiamat.Button.secondary( - text: CommonStrings.promptPoliteNo, - onTap: () => widget.wipeExistingBackup?.call(false))) + width: 200, + child: tiamat.Button.secondary( + text: CommonStrings.promptPoliteNo, + onTap: () => widget.wipeExistingBackup?.call(false), + ), + ), ], - ) + ), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/account/security/matrix/matrix_security_tab.dart b/commet/lib/ui/pages/settings/categories/account/security/matrix/matrix_security_tab.dart index 863a63e65..85fb8acb6 100644 --- a/commet/lib/ui/pages/settings/categories/account/security/matrix/matrix_security_tab.dart +++ b/commet/lib/ui/pages/settings/categories/account/security/matrix/matrix_security_tab.dart @@ -46,45 +46,59 @@ class _MatrixSecurityTabState extends State { supportedActions?.contains("org.matrix.device_delete") == true && accountManagementUri != null; - String get labelMatrixCrossSigning => Intl.message("Cross signing", - desc: "Title label for matrix cross signing", - name: "labelMatrixCrossSigning"); + String get labelMatrixCrossSigning => Intl.message( + "Cross signing", + desc: "Title label for matrix cross signing", + name: "labelMatrixCrossSigning", + ); String get labelMatrixCrossSigningAndBackup => Intl.message( - "Cross Signing & Backup", - desc: "Header label for matrix cross signing and message backup section", - name: "labelMatrixCrossSigningAndBackup"); - - String get labelMatrixAccountSessions => Intl.message("Sessions", - desc: "Title label for account sessions", - name: "labelMatrixAccountSessions"); - - String get labelMatrixCrossSigningExplanation => - Intl.message("Setup to verify and keep track of all your sessions", - desc: "Explains what matrix cross signing does", - name: "labelMatrixCrossSigningExplanation"); - - String get labelMatrixResetCrossSigningTitle => - Intl.message("Reset cross signing", - desc: "Title for the popup dialog when resetting cross signing", - name: "labelMatrixResetCrossSigningTitle"); - - String get labelMatrixMessageBackup => Intl.message("Message backup", - desc: "TItle label for matrix message backup settings", - name: "labelMatrixMessageBackup"); + "Cross Signing & Backup", + desc: "Header label for matrix cross signing and message backup section", + name: "labelMatrixCrossSigningAndBackup", + ); + + String get labelMatrixAccountSessions => Intl.message( + "Sessions", + desc: "Title label for account sessions", + name: "labelMatrixAccountSessions", + ); + + String get labelMatrixCrossSigningExplanation => Intl.message( + "Setup to verify and keep track of all your sessions", + desc: "Explains what matrix cross signing does", + name: "labelMatrixCrossSigningExplanation", + ); + + String get labelMatrixResetCrossSigningTitle => Intl.message( + "Reset cross signing", + desc: "Title for the popup dialog when resetting cross signing", + name: "labelMatrixResetCrossSigningTitle", + ); + + String get labelMatrixMessageBackup => Intl.message( + "Message backup", + desc: "TItle label for matrix message backup settings", + name: "labelMatrixMessageBackup", + ); String get labelMatrixMessageBackupExplanation => Intl.message( - "Maintains a backup of your message history, in case you lose all your sessions. Your messages will be encrypted before uploading", - desc: "Explains what matrix message backup does", - name: "labelMatrixMessageBackupExplanation"); - - String get promptSetupMatrixMessageBackup => Intl.message("Setup backup", - desc: "Text on the button to begin the setup process for message backup", - name: "promptSetupMatrixMessageBackup"); - - String get labelRestoreMatrixBackupTitle => Intl.message("Restore backup", - desc: "Title of the popup dialog for restoring message backup", - name: "labelRestoreMatrixBackupTitle"); + "Maintains a backup of your message history, in case you lose all your sessions. Your messages will be encrypted before uploading", + desc: "Explains what matrix message backup does", + name: "labelMatrixMessageBackupExplanation", + ); + + String get promptSetupMatrixMessageBackup => Intl.message( + "Setup backup", + desc: "Text on the button to begin the setup process for message backup", + name: "promptSetupMatrixMessageBackup", + ); + + String get labelRestoreMatrixBackupTitle => Intl.message( + "Restore backup", + desc: "Title of the popup dialog for restoring message backup", + name: "labelRestoreMatrixBackupTitle", + ); @override void initState() { @@ -92,9 +106,11 @@ class _MatrixSecurityTabState extends State { checkState(); getDevices(); - widget.client.hasServerDisabledEncryption().then((v) => setState(() { - encryptionDisabled = v; - })); + widget.client.hasServerDisabledEncryption().then( + (v) => setState(() { + encryptionDisabled = v; + }), + ); super.initState(); } @@ -113,12 +129,13 @@ class _MatrixSecurityTabState extends State { if (supportsLegacyUIA == null) { try { - await widget.client.matrixClient - .request(RequestType.DELETE, "/client/v3/devices/_", data: { - "auth": { - "type": "m.login.dummy", - } - }); + await widget.client.matrixClient.request( + RequestType.DELETE, + "/client/v3/devices/_", + data: { + "auth": {"type": "m.login.dummy"}, + }, + ); } catch (e) { if (e case MatrixException mx) { if (mx.error == MatrixError.M_FORBIDDEN) { @@ -133,16 +150,19 @@ class _MatrixSecurityTabState extends State { if (supportsLegacyUIA != true) { if (authMetadata == null) { try { - authMetadata = await widget.client.matrixClient - .request(RequestType.GET, "/client/v1/auth_metadata"); + authMetadata = await widget.client.matrixClient.request( + RequestType.GET, + "/client/v1/auth_metadata", + ); } catch (e, s) { Log.onError(e, s); } } } - gotDevices - ?.sort((a, b) => (b.lastSeenTs ?? 0).compareTo(a.lastSeenTs ?? 0)); + gotDevices?.sort( + (a, b) => (b.lastSeenTs ?? 0).compareTo(a.lastSeenTs ?? 0), + ); if (mounted) setState(() { @@ -171,7 +191,8 @@ class _MatrixSecurityTabState extends State { child: devices == null ? SizedBox( height: 300, - child: Center(child: const CircularProgressIndicator())) + child: Center(child: const CircularProgressIndicator()), + ) : Column( children: [ if (supportsLegacyUIA == true && inactiveDevices.isNotEmpty) @@ -179,8 +200,9 @@ class _MatrixSecurityTabState extends State { padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), child: Container( decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainerLowest, - borderRadius: BorderRadius.circular(8)), + color: ColorScheme.of(context).surfaceContainerLowest, + borderRadius: BorderRadius.circular(8), + ), child: Padding( padding: const EdgeInsets.all(8.0), child: Row( @@ -208,7 +230,7 @@ class _MatrixSecurityTabState extends State { removeInactiveDevices(); }, ), - ) + ), ], ), ), @@ -228,8 +250,8 @@ class _MatrixSecurityTabState extends State { removeSession: supportsLegacyUIA == true ? () => removeDeviceUIA(device.deviceId) : canRemoveDeviceOAuth - ? () => removeDeviceOAuth(device.deviceId) - : null, + ? () => removeDeviceOAuth(device.deviceId) + : null, ), ); }, @@ -249,17 +271,20 @@ class _MatrixSecurityTabState extends State { } void removeInactiveDevices() async { - var confirm = await AdaptiveDialog.confirmation(context, - dangerous: true, - prompt: - "Are you sure you want to log out of ${inactiveDevices.length} sessions?"); + var confirm = await AdaptiveDialog.confirmation( + context, + dangerous: true, + prompt: + "Are you sure you want to log out of ${inactiveDevices.length} sessions?", + ); if (confirm != true) return; await widget.client.matrixClient.uiaRequestBackground((auth) async { await widget.client.matrixClient.deleteDevices( - inactiveDevices.map((i) => i.deviceId).toList(), - auth: auth); + inactiveDevices.map((i) => i.deviceId).toList(), + auth: auth, + ); }); getDevices(); @@ -267,13 +292,16 @@ class _MatrixSecurityTabState extends State { void removeDeviceOAuth(String deviceID) { LinkUtils.open( - accountManagementUri!.replace(queryParameters: { + accountManagementUri!.replace( + queryParameters: { "action": "org.matrix.device_delete", - "device_id": deviceID - }), - context: context, - filterTrackingParameters: false, - bypassConfirmation: false); + "device_id": deviceID, + }, + ), + context: context, + filterTrackingParameters: false, + bypassConfirmation: false, + ); } void onUpdated() { @@ -284,51 +312,61 @@ class _MatrixSecurityTabState extends State { Panel crossSigningPanel() { return Panel( - header: labelMatrixCrossSigningAndBackup, - mode: TileType.surfaceContainerLow, - child: Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 8, 8), - child: Column( - spacing: 4, - children: [ - if (encryptionDisabled) - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), - child: Container( - decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainerLowest, - borderRadius: BorderRadius.circular(8)), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: AlertView(Alert(AlertType.info, - messageGetter: () => - "Your homeserver has force-disabled encryption", - titleGetter: () => "Encryption Disabled")), + header: labelMatrixCrossSigningAndBackup, + mode: TileType.surfaceContainerLow, + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 8, 8), + child: Column( + spacing: 4, + children: [ + if (encryptionDisabled) + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), + child: Container( + decoration: BoxDecoration( + color: ColorScheme.of(context).surfaceContainerLowest, + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: AlertView( + Alert( + AlertType.info, + messageGetter: () => + "Your homeserver has force-disabled encryption", + titleGetter: () => "Encryption Disabled", + ), ), ), ), - if (!isVerified) - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), - child: Container( - decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainerLowest, - borderRadius: BorderRadius.circular(8)), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: AlertView(Alert(AlertType.warning, - messageGetter: () => - "Your current session is not verified. You will not be able to participate in encrypted chats.", - titleGetter: () => "Unverified")), + ), + if (!isVerified) + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), + child: Container( + decoration: BoxDecoration( + color: ColorScheme.of(context).surfaceContainerLowest, + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: AlertView( + Alert( + AlertType.warning, + messageGetter: () => "Your current session is not verified. You will not be able to participate in encrypted chats.", + titleGetter: () => "Unverified", + ), ), ), ), - crossSigning(), - const tiamat.Seperator(), - messageBackup() - ], - ), - )); + ), + crossSigning(), + const tiamat.Seperator(), + messageBackup(), + ], + ), + ), + ); } Widget crossSigning() { @@ -341,34 +379,39 @@ class _MatrixSecurityTabState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text.label(labelMatrixCrossSigning), - tiamat.Text.labelLow(labelMatrixCrossSigningExplanation) + tiamat.Text.labelLow(labelMatrixCrossSigningExplanation), ], ), ), Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 0, 0), - child: crossSigningEnabled - ? tiamat.Button.danger( - text: CommonStrings.promptReset, - onTap: () => AdaptiveDialog.show(context, - builder: (_) => MatrixCrossSigningPage( - client: widget.client, - mode: MatrixCrossSigningMode.resetCrossSigning, - onComplete: checkState, - ), - dismissible: true, - title: labelMatrixResetCrossSigningTitle), - ) - : tiamat.Button.secondary( - text: CommonStrings.promptEnable, - onTap: () => AdaptiveDialog.show(context, - builder: (_) => MatrixCrossSigningPage( - client: widget.client, - onComplete: checkState, - ), - dismissible: true, - title: labelMatrixCrossSigning), - )), + padding: const EdgeInsets.fromLTRB(16, 0, 0, 0), + child: crossSigningEnabled + ? tiamat.Button.danger( + text: CommonStrings.promptReset, + onTap: () => AdaptiveDialog.show( + context, + builder: (_) => MatrixCrossSigningPage( + client: widget.client, + mode: MatrixCrossSigningMode.resetCrossSigning, + onComplete: checkState, + ), + dismissible: true, + title: labelMatrixResetCrossSigningTitle, + ), + ) + : tiamat.Button.secondary( + text: CommonStrings.promptEnable, + onTap: () => AdaptiveDialog.show( + context, + builder: (_) => MatrixCrossSigningPage( + client: widget.client, + onComplete: checkState, + ), + dismissible: true, + title: labelMatrixCrossSigning, + ), + ), + ), ], ); } @@ -383,37 +426,42 @@ class _MatrixSecurityTabState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text.label(labelMatrixMessageBackup), - tiamat.Text.labelLow(labelMatrixMessageBackupExplanation) + tiamat.Text.labelLow(labelMatrixMessageBackupExplanation), ], ), ), Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 0, 0), - child: messageBackupEnabled == true - ? tiamat.Button.secondary( - text: CommonStrings.promptRestore, - onTap: () => AdaptiveDialog.show(context, - builder: (_) => MatrixCrossSigningPage( - client: widget.client, - onComplete: checkState, - mode: MatrixCrossSigningMode.restoreBackup, - ), - dismissible: true, - title: labelRestoreMatrixBackupTitle), - ) - : messageBackupEnabled == false - ? tiamat.Button.secondary( - text: CommonStrings.promptEnable, - onTap: () => AdaptiveDialog.show(context, - builder: (_) => MatrixCrossSigningPage( - client: widget.client, - onComplete: checkState, - mode: MatrixCrossSigningMode.enableBackup, - ), - dismissible: true, - title: promptSetupMatrixMessageBackup), - ) - : const CircularProgressIndicator()) + padding: const EdgeInsets.fromLTRB(16, 0, 0, 0), + child: messageBackupEnabled == true + ? tiamat.Button.secondary( + text: CommonStrings.promptRestore, + onTap: () => AdaptiveDialog.show( + context, + builder: (_) => MatrixCrossSigningPage( + client: widget.client, + onComplete: checkState, + mode: MatrixCrossSigningMode.restoreBackup, + ), + dismissible: true, + title: labelRestoreMatrixBackupTitle, + ), + ) + : messageBackupEnabled == false + ? tiamat.Button.secondary( + text: CommonStrings.promptEnable, + onTap: () => AdaptiveDialog.show( + context, + builder: (_) => MatrixCrossSigningPage( + client: widget.client, + onComplete: checkState, + mode: MatrixCrossSigningMode.enableBackup, + ), + dismissible: true, + title: promptSetupMatrixMessageBackup, + ), + ) + : const CircularProgressIndicator(), + ), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/account/security/matrix/session/matrix_session.dart b/commet/lib/ui/pages/settings/categories/account/security/matrix/session/matrix_session.dart index 5ed6f7906..a3ac097f1 100644 --- a/commet/lib/ui/pages/settings/categories/account/security/matrix/session/matrix_session.dart +++ b/commet/lib/ui/pages/settings/categories/account/security/matrix/session/matrix_session.dart @@ -7,8 +7,14 @@ import 'package:matrix/matrix.dart'; import '../../../../../../matrix/verification/matrix_verification_page.dart'; class MatrixSession extends StatefulWidget { - const MatrixSession(this.device, this.matrixClient, - {super.key, this.onUpdated, this.inactive = false, this.removeSession}); + const MatrixSession( + this.device, + this.matrixClient, { + super.key, + this.onUpdated, + this.inactive = false, + this.removeSession, + }); final Device device; final Client matrixClient; final Function? onUpdated; @@ -37,7 +43,9 @@ class _MatrixSessionState extends State { } bool isVerified() { - var keys = widget.matrixClient.userDeviceKeys[widget.matrixClient.userID] + var keys = widget + .matrixClient + .userDeviceKeys[widget.matrixClient.userID] ?.deviceKeys[widget.device.deviceId]; return keys?.verified ?? false; } @@ -47,16 +55,20 @@ class _MatrixSessionState extends State { } void beginVerification() async { - var keys = widget.matrixClient.userDeviceKeys[widget.matrixClient.userID] + var keys = widget + .matrixClient + .userDeviceKeys[widget.matrixClient.userID] ?.deviceKeys[widget.device.deviceId]; var request = await keys!.startVerification(); previousOnUpdate = request.onUpdate; request.onUpdate = onRequestUpdate; if (mounted) - AdaptiveDialog.show(context, - builder: (_) => MatrixVerificationPage(request: request), - title: "Verification Request"); + AdaptiveDialog.show( + context, + builder: (_) => MatrixVerificationPage(request: request), + title: "Verification Request", + ); } void onRequestUpdate() { diff --git a/commet/lib/ui/pages/settings/categories/account/security/matrix/session/matrix_session_view.dart b/commet/lib/ui/pages/settings/categories/account/security/matrix/session/matrix_session_view.dart index 9eb2000ce..9e6778533 100644 --- a/commet/lib/ui/pages/settings/categories/account/security/matrix/session/matrix_session_view.dart +++ b/commet/lib/ui/pages/settings/categories/account/security/matrix/session/matrix_session_view.dart @@ -5,17 +5,18 @@ import 'package:intl/intl.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class MatrixSessionView extends StatelessWidget { - const MatrixSessionView( - {this.displayName, - required this.deviceId, - this.lastSeenIp, - this.lastSeenTimestamp, - super.key, - this.verified = false, - this.isThisDevice = false, - this.inactive = false, - this.beginVerification, - this.removeSession}); + const MatrixSessionView({ + this.displayName, + required this.deviceId, + this.lastSeenIp, + this.lastSeenTimestamp, + super.key, + this.verified = false, + this.isThisDevice = false, + this.inactive = false, + this.beginVerification, + this.removeSession, + }); final String? displayName; final String deviceId; @@ -27,16 +28,19 @@ class MatrixSessionView extends StatelessWidget { final Function? beginVerification; final Function? removeSession; - String get promptMatrixVerifySession => Intl.message("Verify", - desc: "Text on the button to verify a session", - name: "promptMatrixVerifySession"); + String get promptMatrixVerifySession => Intl.message( + "Verify", + desc: "Text on the button to verify a session", + name: "promptMatrixVerifySession", + ); @override Widget build(BuildContext context) { return DecoratedBox( decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerLow, - borderRadius: BorderRadius.circular(5)), + color: Theme.of(context).colorScheme.surfaceContainerLow, + borderRadius: BorderRadius.circular(5), + ), child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -80,15 +84,14 @@ class MatrixSessionView extends StatelessWidget { ), if (lastSeenTimestamp != null) tiamat.Text.tiny( - "Last Seen: ${DateFormat(DateFormat.YEAR_MONTH_WEEKDAY_DAY).format(DateTime.fromMillisecondsSinceEpoch(lastSeenTimestamp!))}"), + "Last Seen: ${DateFormat(DateFormat.YEAR_MONTH_WEEKDAY_DAY).format(DateTime.fromMillisecondsSinceEpoch(lastSeenTimestamp!))}", + ), if (lastSeenIp != null) const Padding( padding: EdgeInsets.fromLTRB(10, 0, 10, 0), child: SizedBox( width: 10, - child: tiamat.Seperator( - padding: 0, - ), + child: tiamat.Seperator(padding: 0), ), ), if (lastSeenIp != null) tiamat.Text.tiny(lastSeenIp!), @@ -96,7 +99,7 @@ class MatrixSessionView extends StatelessWidget { ), ], ), - if (MediaQuery.of(context).desktop) verifyButton() + if (MediaQuery.of(context).desktop) verifyButton(), ], ), if (MediaQuery.of(context).mobile) Align(child: verifyButton()), @@ -123,7 +126,7 @@ class MatrixSessionView extends StatelessWidget { size: 24, onPressed: () => removeSession?.call(), ), - ) + ), ], ); } @@ -131,8 +134,11 @@ class MatrixSessionView extends StatelessWidget { IconData getIcon() { if (displayName == null) return Icons.device_unknown; - if (["ios", "android", "mobile"] - .any((element) => displayName!.toLowerCase().contains(element))) { + if ([ + "ios", + "android", + "mobile", + ].any((element) => displayName!.toLowerCase().contains(element))) { return Icons.smartphone; } diff --git a/commet/lib/ui/pages/settings/categories/account/security/security_tab.dart b/commet/lib/ui/pages/settings/categories/account/security/security_tab.dart index 2d5afc443..573edadec 100644 --- a/commet/lib/ui/pages/settings/categories/account/security/security_tab.dart +++ b/commet/lib/ui/pages/settings/categories/account/security/security_tab.dart @@ -36,17 +36,14 @@ class _SecuritySettingsTabState extends State { }); }, ), - pickSecurityPage(selectedClient) + pickSecurityPage(selectedClient), ], ); } Widget pickSecurityPage(Client client) { if (client is MatrixClient) { - return MatrixSecurityTab( - client, - key: client.key, - ); + return MatrixSecurityTab(client, key: client.key); } return const Placeholder(); diff --git a/commet/lib/ui/pages/settings/categories/account/settings_category_account.dart b/commet/lib/ui/pages/settings/categories/account/settings_category_account.dart index a94f92d4c..1c95b3331 100644 --- a/commet/lib/ui/pages/settings/categories/account/settings_category_account.dart +++ b/commet/lib/ui/pages/settings/categories/account/settings_category_account.dart @@ -14,88 +14,107 @@ import 'account_management/account_management_tab.dart'; import 'security/security_tab.dart'; class SettingsCategoryAccount implements SettingsCategory { - String get labelSettingsTabManageAccounts => Intl.message("Manage Accounts", - name: "labelSettingsTabManageAccounts", - desc: "Label for the Manage Accounts settings"); + String get labelSettingsTabManageAccounts => Intl.message( + "Manage Accounts", + name: "labelSettingsTabManageAccounts", + desc: "Label for the Manage Accounts settings", + ); - String get labelSettingsTabProfile => Intl.message("Profile", - name: "labelSettingsTabProfile", - desc: "Label for the Profile settings page"); + String get labelSettingsTabProfile => Intl.message( + "Profile", + name: "labelSettingsTabProfile", + desc: "Label for the Profile settings page", + ); - String get labelSettingsTabPrivacy => Intl.message("Privacy", - name: "labelSettingsTabPrivacy", - desc: "Label for the Privacy settings page"); + String get labelSettingsTabPrivacy => Intl.message( + "Privacy", + name: "labelSettingsTabPrivacy", + desc: "Label for the Privacy settings page", + ); - String get labelSettingsTabSecurity => Intl.message("Security", - name: "labelSettingsTabSecurity", - desc: "Label for the Security settings page"); + String get labelSettingsTabSecurity => Intl.message( + "Security", + name: "labelSettingsTabSecurity", + desc: "Label for the Security settings page", + ); - String get labelSettingsTabEmoticons => Intl.message("Emoticons", - name: "labelSettingsTabEmoticons", - desc: "Label for the Emoticons settings page"); + String get labelSettingsTabEmoticons => Intl.message( + "Emoticons", + name: "labelSettingsTabEmoticons", + desc: "Label for the Emoticons settings page", + ); - String get labelSettingsTabDeveloper => Intl.message("Developer", - name: "labelSettingsTabDeveloper", - desc: "Label for the Developer settings page"); + String get labelSettingsTabDeveloper => Intl.message( + "Developer", + name: "labelSettingsTabDeveloper", + desc: "Label for the Developer settings page", + ); - String get labelSettingsCategoryAccount => Intl.message("Account", - name: "labelSettingsCategoryAccount", - desc: "Label for the settings category Account"); + String get labelSettingsCategoryAccount => Intl.message( + "Account", + name: "labelSettingsCategoryAccount", + desc: "Label for the settings category Account", + ); @override String get title => labelSettingsCategoryAccount; @override List get tabs => List.from([ - SettingsTab( - label: labelSettingsTabManageAccounts, - icon: Icons.person, - pageBuilder: (context) { - return AccountManagementSettingsTab( - clientManager: Provider.of(context), - ); - }), - SettingsTab( - label: labelSettingsTabProfile, - icon: Icons.account_circle, - pageBuilder: (context) { - return ProfileEditTab( - clientManager: Provider.of(context), - ); - }), - SettingsTab( - label: labelSettingsTabPrivacy, - icon: Icons.public, - pageBuilder: (context) { - return AccountSettingsTab( - clientManager: Provider.of(context), - ); - }), - SettingsTab( - label: labelSettingsTabSecurity, - icon: Icons.security, - pageBuilder: (context) { - return SecuritySettingsTab( - clientManager: Provider.of(context), - ); - }), - SettingsTab( - label: labelSettingsTabEmoticons, - icon: Icons.emoji_emotions, - pageBuilder: (context) { - return AccountEmojiTab( - clientManager: Provider.of(context)); - }, - ), - if (preferences.developerMode.value) - SettingsTab( - label: labelSettingsTabDeveloper, - icon: Icons.code, - pageBuilder: (context) { - return AccountStateTab( - clientManager: Provider.of(context), - ); - }, - ) - ]); + SettingsTab( + label: labelSettingsTabManageAccounts, + icon: Icons.person, + pageBuilder: (context) { + return AccountManagementSettingsTab( + clientManager: Provider.of(context), + ); + }, + ), + SettingsTab( + label: labelSettingsTabProfile, + icon: Icons.account_circle, + pageBuilder: (context) { + return ProfileEditTab( + clientManager: Provider.of(context), + ); + }, + ), + SettingsTab( + label: labelSettingsTabPrivacy, + icon: Icons.public, + pageBuilder: (context) { + return AccountSettingsTab( + clientManager: Provider.of(context), + ); + }, + ), + SettingsTab( + label: labelSettingsTabSecurity, + icon: Icons.security, + pageBuilder: (context) { + return SecuritySettingsTab( + clientManager: Provider.of(context), + ); + }, + ), + SettingsTab( + label: labelSettingsTabEmoticons, + icon: Icons.emoji_emotions, + pageBuilder: (context) { + return AccountEmojiTab( + clientManager: Provider.of(context), + ); + }, + ), + if (preferences.developerMode.value) + SettingsTab( + label: labelSettingsTabDeveloper, + icon: Icons.code, + pageBuilder: (context) { + return AccountStateTab( + clientManager: Provider.of(context), + ); + }, + ), + ]); } diff --git a/commet/lib/ui/pages/settings/categories/app/advanced_settings_page.dart b/commet/lib/ui/pages/settings/categories/app/advanced_settings_page.dart index 4de5494b2..107824eef 100644 --- a/commet/lib/ui/pages/settings/categories/app/advanced_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/app/advanced_settings_page.dart @@ -14,23 +14,29 @@ class AdvancedSettingsPage extends StatefulWidget { } class _AdvancedSettingsPageState extends State { - String get labelSettingsDeveloperMode => Intl.message("Developer mode", - desc: "Header for the settings to enable developer mode", - name: "labelSettingsDeveloperMode"); + String get labelSettingsDeveloperMode => Intl.message( + "Developer mode", + desc: "Header for the settings to enable developer mode", + name: "labelSettingsDeveloperMode", + ); - String get labelSettingsDeveloperModeExplanation => - Intl.message("Shows extra information, useful for developers", - desc: "Explains what developer mode does", - name: "labelSettingsDeveloperModeExplanation"); + String get labelSettingsDeveloperModeExplanation => Intl.message( + "Shows extra information, useful for developers", + desc: "Explains what developer mode does", + name: "labelSettingsDeveloperModeExplanation", + ); - String get labelStickerCompatibility => Intl.message("Sticker compatibility", - desc: "Header for the settings to enable sticker compatibility mode", - name: "labelStickerCompatibility"); + String get labelStickerCompatibility => Intl.message( + "Sticker compatibility", + desc: "Header for the settings to enable sticker compatibility mode", + name: "labelStickerCompatibility", + ); String get labelSettingsStickerCompatibilityExplanation => Intl.message( - "In some matrix clients, sending a sticker as 'm.sticker' will cause the sticker to not load correctly. Enabling this setting will send stickers as 'm.image' which will allow them to render correctly", - desc: "Explains what sticker compatibility mode does", - name: "labelSettingsStickerCompatibilityExplanation"); + "In some matrix clients, sending a sticker as 'm.sticker' will cause the sticker to not load correctly. Enabling this setting will send stickers as 'm.image' which will allow them to render correctly", + desc: "Explains what sticker compatibility mode does", + name: "labelSettingsStickerCompatibilityExplanation", + ); @override void initState() { @@ -50,39 +56,38 @@ class _AdvancedSettingsPageState extends State { description: labelSettingsDeveloperModeExplanation, ), ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), Panel( - header: labelStickerCompatibility, - mode: TileType.surfaceContainerLow, - child: BooleanPreferenceToggle( - preference: preferences.stickerCompatibilityMode, - title: labelStickerCompatibility, - description: labelSettingsStickerCompatibilityExplanation, - )), - const SizedBox( - height: 10, + header: labelStickerCompatibility, + mode: TileType.surfaceContainerLow, + child: BooleanPreferenceToggle( + preference: preferences.stickerCompatibilityMode, + title: labelStickerCompatibility, + description: labelSettingsStickerCompatibilityExplanation, + ), ), + const SizedBox(height: 10), Panel( - mode: tiamat.TileType.surfaceContainerLow, - header: "Override Layout", - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - tiamat.Text.labelLow( - "You may need to restart the app for this to take effect"), - tiamat.DropdownSelector( - items: [null, "desktop", "mobile"], - itemBuilder: (item) => - tiamat.Text.label(item ?? "No Override"), - onItemSelected: (item) async { - await preferences.layoutOverride.set(item); - setState(() {}); - }, - value: preferences.layoutOverride.value) - ], - )) + mode: tiamat.TileType.surfaceContainerLow, + header: "Override Layout", + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + tiamat.Text.labelLow( + "You may need to restart the app for this to take effect", + ), + tiamat.DropdownSelector( + items: [null, "desktop", "mobile"], + itemBuilder: (item) => tiamat.Text.label(item ?? "No Override"), + onItemSelected: (item) async { + await preferences.layoutOverride.set(item); + setState(() {}); + }, + value: preferences.layoutOverride.value, + ), + ], + ), + ), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/app/appearance_settings_page.dart b/commet/lib/ui/pages/settings/categories/app/appearance_settings_page.dart index 4d0c6eb52..56d6b1382 100644 --- a/commet/lib/ui/pages/settings/categories/app/appearance_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/app/appearance_settings_page.dart @@ -19,77 +19,91 @@ class AppearanceSettingsPage extends StatefulWidget { } class _AppearanceSettingsPageState extends State { - String get labelSettingsAppTheme => Intl.message("Theme", - name: "labelSettingsAppTheme", - desc: "Label for theme section of app appearance"); + String get labelSettingsAppTheme => Intl.message( + "Theme", + name: "labelSettingsAppTheme", + desc: "Label for theme section of app appearance", + ); - String get labelAppScale => Intl.message("App Scale", - name: 'labelAppScale', - desc: - "Label for the setting which controls the UI scale of the overall app"); + String get labelAppScale => Intl.message( + "App Scale", + name: 'labelAppScale', + desc: + "Label for the setting which controls the UI scale of the overall app", + ); - String get labelUseRoomAvatars => Intl.message("Use room avatars", - name: "labelUseRoomAvatars", - desc: "Label for enabling using room avatars instead of icons"); + String get labelUseRoomAvatars => Intl.message( + "Use room avatars", + name: "labelUseRoomAvatars", + desc: "Label for enabling using room avatars instead of icons", + ); - String get labelEnableRoomIconsDescription => - Intl.message("Show room avatar images instead of icons", - name: "labelEnableRoomIconsDescription", - desc: "Description for the enable room icons setting"); + String get labelEnableRoomIconsDescription => Intl.message( + "Show room avatar images instead of icons", + name: "labelEnableRoomIconsDescription", + desc: "Description for the enable room icons setting", + ); - String get labelUseRoomAvatarPlaceholders => - Intl.message("Use placeholder avatars", - name: "labelUseRoomAvatarPlaceholders", - desc: "Label for enabling generic icons in the appearance settings"); + String get labelUseRoomAvatarPlaceholders => Intl.message( + "Use placeholder avatars", + name: "labelUseRoomAvatarPlaceholders", + desc: "Label for enabling generic icons in the appearance settings", + ); String get labelUseRoomAvatarPlaceholdersDescription => Intl.message( - "When a room does not have an avatar set, or using them is disabled, fallback to a generic color + first letter placeholder for the image", - name: "labelUseRoomAvatarPlaceholdersDescription", - desc: "Description for the enable generic icons setting"); + "When a room does not have an avatar set, or using them is disabled, fallback to a generic color + first letter placeholder for the image", + name: "labelUseRoomAvatarPlaceholdersDescription", + desc: "Description for the enable generic icons setting", + ); String get labelShowRoomPreviewsInSpaceSidebar => Intl.message( - "Show unjoined rooms in sidebar", - name: "labelShowRoomPreviewsInSpaceSidebar", - desc: "Label for enabling using the preview list in the space sidebar"); + "Show unjoined rooms in sidebar", + name: "labelShowRoomPreviewsInSpaceSidebar", + desc: "Label for enabling using the preview list in the space sidebar", + ); String get labelShowRoomPreviewsInSpaceSidebarDescription => Intl.message( - "When there are rooms which you have not joined in a space, show them in the sidebar with the rest of the rooms in the space", - name: "labelShowRoomPreviewsInSpaceSidebarDescription", - desc: - "Description for enabling using the preview list in the space sidebar"); + "When there are rooms which you have not joined in a space, show them in the sidebar with the rest of the rooms in the space", + name: "labelShowRoomPreviewsInSpaceSidebarDescription", + desc: + "Description for enabling using the preview list in the space sidebar", + ); - String get labelShowRoomStateEvents => Intl.message("Show state events", - name: "labelShowRoomStateEvents", - desc: - "Label for enabling visibility of state events in the room timeline"); + String get labelShowRoomStateEvents => Intl.message( + "Show state events", + name: "labelShowRoomStateEvents", + desc: "Label for enabling visibility of state events in the room timeline", + ); String get labelShowRoomStateEventsDescription => Intl.message( - "Show changes to the room state, such as members joining and leaving, in the chat timeline", - name: "labelShowRoomStateEventsDescription", - desc: - "Description for enabling using visibility of room state events in the timeline"); + "Show changes to the room state, such as members joining and leaving, in the chat timeline", + name: "labelShowRoomStateEventsDescription", + desc: "Description for enabling using visibility of room state events in the timeline", + ); - String get labelCollapseStateEvents => Intl.message("Collapse state events", - name: "labelCollapseStateEvents", - desc: - "Label for enabling collapsing of state events in the room timeline"); + String get labelCollapseStateEvents => Intl.message( + "Collapse state events", + name: "labelCollapseStateEvents", + desc: "Label for enabling collapsing of state events in the room timeline", + ); String get labelCollapseStateEventsDescription => Intl.message( - "Group changes to room state in to a single timeline event", - name: "labelCollapseStateEventsDescription", - desc: - "Description for enabling using collapsing of room state events in the timeline"); + "Group changes to room state in to a single timeline event", + name: "labelCollapseStateEventsDescription", + desc: "Description for enabling using collapsing of room state events in the timeline", + ); - String get labelShowRoomsInSidebar => Intl.message("Show rooms in sidebar", - name: "labelShowRoomsInSidebar", - desc: - "Label for the toggle which shows an extra entry for rooms which are not contained in a space in the sidebar"); + String get labelShowRoomsInSidebar => Intl.message( + "Show rooms in sidebar", + name: "labelShowRoomsInSidebar", + desc: "Label for the toggle which shows an extra entry for rooms which are not contained in a space in the sidebar", + ); String get labelShowRoomsInSidebarDescription => Intl.message( - "Add an entry to the sidebar that shows all rooms which are not contained in a space", - name: "labelShowRoomsInSidebarDescription", - desc: - "Description for the toggle which shows an extra entry for rooms which are not contained in a space in the sidebar"); + "Add an entry to the sidebar that shows all rooms which are not contained in a space", + name: "labelShowRoomsInSidebarDescription", + desc: "Description for the toggle which shows an extra entry for rooms which are not contained in a space in the sidebar", + ); @override void initState() { @@ -101,9 +115,7 @@ class _AppearanceSettingsPageState extends State { return Column( children: [ themeSettings(context), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), Panel( header: "Scaling", mode: TileType.surfaceContainerLow, @@ -118,8 +130,8 @@ class _AppearanceSettingsPageState extends State { onChanged: (p0) { ScaledWidgetsFlutterBinding.instance.scaleFactor = (deviceSize) { - return p0; - }; + return p0; + }; }, title: labelAppScale, description: "Resizes the overall interface of the app", @@ -131,13 +143,11 @@ class _AppearanceSettingsPageState extends State { preference: preferences.textScale, title: "Text Scale", description: "Multiply the size of text", - ) + ), ], ), ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), Panel( header: "Other Options", mode: TileType.surfaceContainerLow, @@ -178,7 +188,7 @@ class _AppearanceSettingsPageState extends State { preference: preferences.collapseStateEvents, title: labelCollapseStateEvents, description: labelCollapseStateEventsDescription, - ) + ), ], ), ), @@ -193,8 +203,9 @@ class _AppearanceSettingsPageState extends State { Panel( header: labelSettingsAppTheme, mode: TileType.surfaceContainerLow, - child: Column(children: [ - Padding( + child: Column( + children: [ + Padding( padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), child: BooleanPreferenceToggle( preference: preferences.shouldFollowSystemTheme, @@ -204,8 +215,9 @@ class _AppearanceSettingsPageState extends State { var theme = await preferences.resolveTheme(); if (context.mounted) ThemeChanger.setTheme(context, theme); }, - )), - Padding( + ), + ), + Padding( padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), child: BooleanPreferenceToggle( preference: preferences.shouldFollowSystemColors, @@ -215,10 +227,12 @@ class _AppearanceSettingsPageState extends State { var theme = await preferences.resolveTheme(); if (context.mounted) ThemeChanger.setTheme(context, theme); }, - )), - const Seperator(), - const ThemeListWidget(), - ]), + ), + ), + const Seperator(), + const ThemeListWidget(), + ], + ), ), ], ); @@ -249,17 +263,18 @@ class _UIScaleSelectorState extends State { children: [ SizedBox(width: 30, child: tiamat.Text(value.toStringAsPrecision(2))), Expanded( - child: Slider( - min: 0.5, - max: preferences.developerMode.value ? 3 : 2, - value: value, - divisions: preferences.developerMode.value ? 25 : 15, - onChanged: (value) { - setState(() { - this.value = value; - }); - }, - )), + child: Slider( + min: 0.5, + max: preferences.developerMode.value ? 3 : 2, + value: value, + divisions: preferences.developerMode.value ? 25 : 15, + onChanged: (value) { + setState(() { + this.value = value; + }); + }, + ), + ), Button.secondary( text: CommonStrings.promptApply, onTap: () { @@ -269,7 +284,7 @@ class _UIScaleSelectorState extends State { return newValue; }; }, - ) + ), ], ), ); diff --git a/commet/lib/ui/pages/settings/categories/app/boolean_preference_toggle.dart b/commet/lib/ui/pages/settings/categories/app/boolean_preference_toggle.dart index acf1e3f27..6c22e218b 100644 --- a/commet/lib/ui/pages/settings/categories/app/boolean_preference_toggle.dart +++ b/commet/lib/ui/pages/settings/categories/app/boolean_preference_toggle.dart @@ -5,12 +5,13 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class BooleanPreferenceToggle extends StatefulWidget { - const BooleanPreferenceToggle( - {required this.preference, - required this.title, - this.description, - this.onChanged, - super.key}); + const BooleanPreferenceToggle({ + required this.preference, + required this.title, + this.description, + this.onChanged, + super.key, + }); final BoolPreference preference; final Function(bool)? onChanged; @@ -41,11 +42,12 @@ class _BooleanPreferenceToggleState extends State { } class NullableBooleanPreferenceToggle extends StatefulWidget { - const NullableBooleanPreferenceToggle( - {required this.preference, - required this.title, - this.description, - super.key}); + const NullableBooleanPreferenceToggle({ + required this.preference, + required this.title, + this.description, + super.key, + }); final NullableBoolPreference preference; final String title; @@ -74,7 +76,7 @@ class _NullableBooleanPreferenceToggleState children: [ tiamat.Text.labelEmphasised(widget.title), if (widget.description != null) - tiamat.Text.labelLow(widget.description!) + tiamat.Text.labelLow(widget.description!), ], ), ), @@ -87,7 +89,7 @@ class _NullableBooleanPreferenceToggleState setState(() {}); }, ), - ) + ), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/app/boolean_toggle.dart b/commet/lib/ui/pages/settings/categories/app/boolean_toggle.dart index 0d2266a6f..8bcc5bef6 100644 --- a/commet/lib/ui/pages/settings/categories/app/boolean_toggle.dart +++ b/commet/lib/ui/pages/settings/categories/app/boolean_toggle.dart @@ -3,13 +3,14 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class BooleanToggle extends StatefulWidget { - const BooleanToggle( - {required this.setValue, - required this.getValue, - required this.title, - this.description, - this.onChanged, - super.key}); + const BooleanToggle({ + required this.setValue, + required this.getValue, + required this.title, + this.description, + this.onChanged, + super.key, + }); final Future Function(bool) setValue; final bool Function() getValue; @@ -45,7 +46,7 @@ class _BooleanToggleState extends State { children: [ tiamat.Text.labelEmphasised(widget.title), if (widget.description != null) - tiamat.Text.labelLow(widget.description!) + tiamat.Text.labelLow(widget.description!), ], ), ), @@ -71,7 +72,7 @@ class _BooleanToggleState extends State { widget.onChanged?.call(value); }, ), - ) + ), ], ), ); diff --git a/commet/lib/ui/pages/settings/categories/app/double_preference_slider.dart b/commet/lib/ui/pages/settings/categories/app/double_preference_slider.dart index 8703571a2..af55fb554 100644 --- a/commet/lib/ui/pages/settings/categories/app/double_preference_slider.dart +++ b/commet/lib/ui/pages/settings/categories/app/double_preference_slider.dart @@ -5,17 +5,18 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class DoublePreferenceSlider extends StatefulWidget { - const DoublePreferenceSlider( - {required this.preference, - required this.min, - required this.max, - required this.title, - this.units, - this.description, - this.numDecimals = 1, - this.requiresConfirmationButton = false, - this.onChanged, - super.key}); + const DoublePreferenceSlider({ + required this.preference, + required this.min, + required this.max, + required this.title, + this.units, + this.description, + this.numDecimals = 1, + this.requiresConfirmationButton = false, + this.onChanged, + super.key, + }); final DoublePreference preference; final Function(double)? onChanged; @@ -45,10 +46,12 @@ class _DoublePreferenceSliderState extends State { Widget build(BuildContext context) { return Container( decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainer.withAlpha(100), - border: BoxBorder.all( - color: ColorScheme.of(context).secondary.withAlpha(20)), - borderRadius: BorderRadius.circular(8)), + color: ColorScheme.of(context).surfaceContainer.withAlpha(100), + border: BoxBorder.all( + color: ColorScheme.of(context).secondary.withAlpha(20), + ), + borderRadius: BorderRadius.circular(8), + ), child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -60,15 +63,17 @@ class _DoublePreferenceSliderState extends State { Row( children: [ tiamat.Text.labelLow( - "${value.toStringAsFixed(widget.numDecimals)}${widget.units ?? ""}"), + "${value.toStringAsFixed(widget.numDecimals)}${widget.units ?? ""}", + ), Expanded( child: tiamat.Slider( value: value, min: widget.min, max: widget.max, onChanged: (newValue) { - var strValue = - newValue.toStringAsFixed(widget.numDecimals); + var strValue = newValue.toStringAsFixed( + widget.numDecimals, + ); var finalValue = double.parse(strValue); setState(() { value = finalValue; @@ -88,9 +93,9 @@ class _DoublePreferenceSliderState extends State { widget.preference.set(value); widget.onChanged?.call(value); }, - ) + ), ], - ) + ), ], ), ), diff --git a/commet/lib/ui/pages/settings/categories/app/experiments_settings_page.dart b/commet/lib/ui/pages/settings/categories/app/experiments_settings_page.dart index 84ae59d22..911e2c406 100644 --- a/commet/lib/ui/pages/settings/categories/app/experiments_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/app/experiments_settings_page.dart @@ -33,9 +33,8 @@ class _ExperimentsSettingsPageState extends State { BooleanPreferenceToggle( preference: preferences.experimentEnableE2eeElementCall, title: "Encrypted Element Call", - description: - "Allow use of the experimental support for end to end encryption in element call", - ) + description: "Allow use of the experimental support for end to end encryption in element call", + ), ], ), ), diff --git a/commet/lib/ui/pages/settings/categories/app/general_settings_page.dart b/commet/lib/ui/pages/settings/categories/app/general_settings_page.dart index 8df54d0bd..642ab4f12 100644 --- a/commet/lib/ui/pages/settings/categories/app/general_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/app/general_settings_page.dart @@ -17,90 +17,105 @@ class GeneralSettingsPage extends StatefulWidget { } class GeneralSettingsPageState extends State { - String get labelThirdPartyServicesTitle => - Intl.message("Third party services", - desc: "Header for the third party services section in settings", - name: "labelThirdPartyServicesTitle"); - - String get labelGifSearchToggle => Intl.message("Gif search", - desc: "Label for the toggle for enabling and disabling gif search", - name: "labelGifSearchToggle"); - - String labelGifSearchDescriptionGeneric(proxyUrl, serviceName) => Intl.message( - "Enable use of $serviceName GIF search. Requests will be proxied via $proxyUrl", - desc: "Explains that gifs will be fetched via proxy", - args: [proxyUrl, serviceName], - name: "labelGifSearchDescriptionGeneric"); + String get labelThirdPartyServicesTitle => Intl.message( + "Third party services", + desc: "Header for the third party services section in settings", + name: "labelThirdPartyServicesTitle", + ); + + String get labelGifSearchToggle => Intl.message( + "Gif search", + desc: "Label for the toggle for enabling and disabling gif search", + name: "labelGifSearchToggle", + ); + + String labelGifSearchDescriptionGeneric( + proxyUrl, + serviceName, + ) => Intl.message( + "Enable use of $serviceName GIF search. Requests will be proxied via $proxyUrl", + desc: "Explains that gifs will be fetched via proxy", + args: [proxyUrl, serviceName], + name: "labelGifSearchDescriptionGeneric", + ); String get labelUrlPreviewInEncryptedChatTitle => Intl.message( - "URL Preview in Encrypted Chats", - desc: - "Label for the toggle for enabling and disabling use of url previews in encrypted chats", - name: "labelUrlPreviewInEncryptedChatTitle"); + "URL Preview in Encrypted Chats", + desc: "Label for the toggle for enabling and disabling use of url previews in encrypted chats", + name: "labelUrlPreviewInEncryptedChatTitle", + ); String get labelUrlPreviewInEncryptedChatDescription => Intl.message( - "This will expose any URLs sent in your encrypted chats to your homeserver in order to fetch the preview", - desc: - "description for the toggle for enabling and disabling use of url previews in encrypted chats", - name: "labelUrlPreviewInEncryptedChatDescription"); + "This will expose any URLs sent in your encrypted chats to your homeserver in order to fetch the preview", + desc: "description for the toggle for enabling and disabling use of url previews in encrypted chats", + name: "labelUrlPreviewInEncryptedChatDescription", + ); - String get labelAppBehaviourTitle => Intl.message("App Behaviour", - desc: "Header for the app behaviour section in settings", - name: "labelAppBehaviourTitle"); + String get labelAppBehaviourTitle => Intl.message( + "App Behaviour", + desc: "Header for the app behaviour section in settings", + name: "labelAppBehaviourTitle", + ); String get labelAskBeforeDeletingMessageToggle => Intl.message( - "Ask before deleting messages", - desc: - "Label for the toggle for enabling and disabling message deletion confirmation", - name: "labelAskBeforeDeletingMessageToggle"); + "Ask before deleting messages", + desc: "Label for the toggle for enabling and disabling message deletion confirmation", + name: "labelAskBeforeDeletingMessageToggle", + ); String get labelAskBeforeDeletingMessageDescription => Intl.message( - "Enables the pop-up asking for confirmation when deleting a message.", - desc: - "Label describing what 'asking before deleting messages' even means", - name: "labelAskBeforeDeletingMessageDescription"); + "Enables the pop-up asking for confirmation when deleting a message.", + desc: "Label describing what 'asking before deleting messages' even means", + name: "labelAskBeforeDeletingMessageDescription", + ); - String get labelMessageEffectsTitle => Intl.message("Message Effects", - desc: - "Header for the settings tile for message effects, such as confetti", - name: "labelMessageEffectsTitle"); + String get labelMessageEffectsTitle => Intl.message( + "Message Effects", + desc: "Header for the settings tile for message effects, such as confetti", + name: "labelMessageEffectsTitle", + ); String get labelMessageEffectsDescription => Intl.message( - "Messages can be sent with additional effects, such as confetti", - desc: "Label describing what message effects are", - name: "labelMessageEffectsDescription"); - - String get labelMediaPreviewSettingsTitle => Intl.message("Media Preview", - desc: "Header for the settings tile for for media preview toggles", - name: "labelMediaPreviewSettingsTitle"); - - String get labelMediaSettings => Intl.message("Media", - desc: "Header for the settings tile for for media", - name: "labelMediaSettings"); + "Messages can be sent with additional effects, such as confetti", + desc: "Label describing what message effects are", + name: "labelMessageEffectsDescription", + ); + + String get labelMediaPreviewSettingsTitle => Intl.message( + "Media Preview", + desc: "Header for the settings tile for for media preview toggles", + name: "labelMediaPreviewSettingsTitle", + ); + + String get labelMediaSettings => Intl.message( + "Media", + desc: "Header for the settings tile for for media", + name: "labelMediaSettings", + ); String get labelMediaPreviewPrivateRoomsToggle => Intl.message( - "Private Rooms", - desc: - "Short label for the private rooms toggle in media previews section", - name: "labelMediaPreviewPrivateRoomsToggle", - ); + "Private Rooms", + desc: "Short label for the private rooms toggle in media previews section", + name: "labelMediaPreviewPrivateRoomsToggle", + ); String get labelMediaPreviewPrivateRoomsToggleDescription => Intl.message( - "Toggle previewing of images, videos, stickers and urls in private chats", - desc: "Label describing toggle of media previews for private rooms", - name: "labelMediaPreviewPrivateRoomsToggleDescription"); + "Toggle previewing of images, videos, stickers and urls in private chats", + desc: "Label describing toggle of media previews for private rooms", + name: "labelMediaPreviewPrivateRoomsToggleDescription", + ); String get labelMediaPreviewPublicRoomsToggle => Intl.message( - "Public Rooms", - desc: - "Short label for the private rooms toggle in media previews section", - name: "labelMediaPreviewPublicRoomsToggle", - ); + "Public Rooms", + desc: "Short label for the private rooms toggle in media previews section", + name: "labelMediaPreviewPublicRoomsToggle", + ); String get labelMediaPreviewPublicRoomsToggleDescription => Intl.message( - "Toggle previewing of images, videos, stickers and urls in public chat rooms", - desc: "Label describing toggle of media previews for public rooms", - name: "labelMediaPreviewPublicRoomsToggleDescription"); + "Toggle previewing of images, videos, stickers and urls in public chat rooms", + desc: "Label describing toggle of media previews for public rooms", + name: "labelMediaPreviewPublicRoomsToggleDescription", + ); @override void initState() { @@ -114,75 +129,71 @@ class GeneralSettingsPageState extends State { Panel( header: labelThirdPartyServicesTitle, mode: TileType.surfaceContainerLow, - child: Column(children: [ - BooleanPreferenceToggle( - preference: preferences.tenorGifSearchEnabled, - title: labelGifSearchToggle, - description: labelGifSearchDescriptionGeneric( - preferences.proxyUrl.value, "KLIPY"), - ), - const SizedBox( - height: 10, - ), - BooleanPreferenceToggle( - preference: preferences.urlPreviewInE2EEChat, - title: labelUrlPreviewInEncryptedChatTitle, - description: labelUrlPreviewInEncryptedChatDescription, - ), - if (UpdateChecker.shouldCheckForUpdates) - Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), - child: CheckForUpdatesSettingWidget(), + child: Column( + children: [ + BooleanPreferenceToggle( + preference: preferences.tenorGifSearchEnabled, + title: labelGifSearchToggle, + description: labelGifSearchDescriptionGeneric( + preferences.proxyUrl.value, + "KLIPY", + ), ), - ]), - ), - const SizedBox( - height: 10, + const SizedBox(height: 10), + BooleanPreferenceToggle( + preference: preferences.urlPreviewInE2EEChat, + title: labelUrlPreviewInEncryptedChatTitle, + description: labelUrlPreviewInEncryptedChatDescription, + ), + if (UpdateChecker.shouldCheckForUpdates) + Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), + child: CheckForUpdatesSettingWidget(), + ), + ], + ), ), + const SizedBox(height: 10), Panel( header: labelAppBehaviourTitle, mode: TileType.surfaceContainerLow, - child: Column(children: [ - BooleanPreferenceToggle( - preference: preferences.askBeforeDeletingMessageEnabled, - title: labelAskBeforeDeletingMessageToggle, - description: labelAskBeforeDeletingMessageDescription, - ), - BooleanPreferenceToggle( - preference: preferences.autoFocusMessageTextBox, - title: "Autofocus Message Input", - description: - "Automatically focus on the message input text field when opening a chat", - ), - BooleanPreferenceToggle( - preference: preferences.selectAutoCompleteSuggestion, - title: "Select first auto-complete suggestion", - description: - "When typing a message, if there are any auto-complete suggestions, the first one will be highlighted by default", - ), - BooleanPreferenceToggle( - preference: preferences.automaticallyOpenSpace, - title: "Always open space", - description: - "When navigating to a room from outside of a space, also open the space the room is in, if any", - ), - BooleanPreferenceToggle( - preference: preferences.openRoomsAtLastReadMessage, - title: "Open at last read message", - description: - "When opening a room, jump to the last message you read", - ), - BooleanPreferenceToggle( - preference: preferences.pauseAnimationsWhenNotFocused, - title: "Pause animations when unfocused", - description: - "When the app is in the background, pause animations to reduce CPU usage", - ) - ]), - ), - const SizedBox( - height: 10, + child: Column( + children: [ + BooleanPreferenceToggle( + preference: preferences.askBeforeDeletingMessageEnabled, + title: labelAskBeforeDeletingMessageToggle, + description: labelAskBeforeDeletingMessageDescription, + ), + BooleanPreferenceToggle( + preference: preferences.autoFocusMessageTextBox, + title: "Autofocus Message Input", + description: "Automatically focus on the message input text field when opening a chat", + ), + BooleanPreferenceToggle( + preference: preferences.selectAutoCompleteSuggestion, + title: "Select first auto-complete suggestion", + description: "When typing a message, if there are any auto-complete suggestions, the first one will be highlighted by default", + ), + BooleanPreferenceToggle( + preference: preferences.automaticallyOpenSpace, + title: "Always open space", + description: "When navigating to a room from outside of a space, also open the space the room is in, if any", + ), + BooleanPreferenceToggle( + preference: preferences.openRoomsAtLastReadMessage, + title: "Open at last read message", + description: + "When opening a room, jump to the last message you read", + ), + BooleanPreferenceToggle( + preference: preferences.pauseAnimationsWhenNotFocused, + title: "Pause animations when unfocused", + description: "When the app is in the background, pause animations to reduce CPU usage", + ), + ], + ), ), + const SizedBox(height: 10), Panel( header: labelMessageEffectsTitle, mode: TileType.surfaceContainerLow, @@ -192,46 +203,43 @@ class GeneralSettingsPageState extends State { description: labelMessageEffectsDescription, ), ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), Panel( header: labelMediaSettings, mode: TileType.surfaceContainerLow, - child: Column(children: [ - BooleanPreferenceToggle( - preference: preferences.previewMediaInPrivateRooms, - title: labelMediaPreviewPrivateRoomsToggle, - description: labelMediaPreviewPrivateRoomsToggleDescription, - ), - BooleanPreferenceToggle( - preference: preferences.previewMediaInPublicRooms, - title: labelMediaPreviewPublicRoomsToggle, - description: labelMediaPreviewPublicRoomsToggleDescription, - ), - if (MediaQuery.of(context).mobile) ...[ - Seperator(), + child: Column( + children: [ BooleanPreferenceToggle( - preference: preferences.autoRotateImages, - title: "Rotate Images", - description: - "When showing images in fullscreen, automatically rotate the image to best fill the screen", + preference: preferences.previewMediaInPrivateRooms, + title: labelMediaPreviewPrivateRoomsToggle, + description: labelMediaPreviewPrivateRoomsToggleDescription, ), BooleanPreferenceToggle( - preference: preferences.autoRotateVideos, - title: "Rotate Videos", - description: - "When showing videos in fullscreen, automatically rotate the video to best fill the screen", + preference: preferences.previewMediaInPublicRooms, + title: labelMediaPreviewPublicRoomsToggle, + description: labelMediaPreviewPublicRoomsToggleDescription, + ), + if (MediaQuery.of(context).mobile) ...[ + Seperator(), + BooleanPreferenceToggle( + preference: preferences.autoRotateImages, + title: "Rotate Images", + description: "When showing images in fullscreen, automatically rotate the image to best fill the screen", + ), + BooleanPreferenceToggle( + preference: preferences.autoRotateVideos, + title: "Rotate Videos", + description: "When showing videos in fullscreen, automatically rotate the video to best fill the screen", + ), + ], + Seperator(), + StringListPreferenceEditor( + preference: preferences.allowedRemoteVideoHosts, + title: "Allowed Video Hosts", + description: "Allowed web hosts for displaying external videos, such as in URL Previews. Your IP address will be revealed to these servers when accessing the video", ), ], - Seperator(), - StringListPreferenceEditor( - preference: preferences.allowedRemoteVideoHosts, - title: "Allowed Video Hosts", - description: - "Allowed web hosts for displaying external videos, such as in URL Previews. Your IP address will be revealed to these servers when accessing the video", - ) - ]), + ), ), ], ); diff --git a/commet/lib/ui/pages/settings/categories/app/notification_settings/notification_settings_page.dart b/commet/lib/ui/pages/settings/categories/app/notification_settings/notification_settings_page.dart index c99163d66..e30ac13f7 100644 --- a/commet/lib/ui/pages/settings/categories/app/notification_settings/notification_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/app/notification_settings/notification_settings_page.dart @@ -29,10 +29,11 @@ class _NotificationSettingsPageState extends State { GlobalKey pushGatewayKey = GlobalKey(); bool isPushGatewayLoading = false; - String get notificationSettingsNotSupported => - Intl.message("Push notifications are not supported on this system", - name: "notificationSettingsNotSupported", - desc: "Message to display when push notifications are not supported"); + String get notificationSettingsNotSupported => Intl.message( + "Push notifications are not supported on this system", + name: "notificationSettingsNotSupported", + desc: "Message to display when push notifications are not supported", + ); @override void initState() { @@ -58,24 +59,21 @@ class _NotificationSettingsPageState extends State { if (notifier is UnifiedPushNotifier) Column( children: [ - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), Panel( - mode: tiamat.TileType.surfaceContainerLow, - header: "Unified Push", - child: Column( - children: [ - UnifiedPushSetupView( - onToggled: (_) => setState(() {}), - ), - if (preferences.unifiedPushEnabled.value == true) - pushGatewaySelector(), - ], - )), - const SizedBox( - height: 10, + mode: tiamat.TileType.surfaceContainerLow, + header: "Unified Push", + child: Column( + children: [ + UnifiedPushSetupView( + onToggled: (_) => setState(() {}), + ), + if (preferences.unifiedPushEnabled.value == true) + pushGatewaySelector(), + ], + ), ), + const SizedBox(height: 10), ], ), ], @@ -97,8 +95,7 @@ class _NotificationSettingsPageState extends State { BooleanPreferenceToggle( preference: preferences.silenceNotifications, title: "Silence Notifications", - description: - "When another device or client is active, silence notifications on this device", + description: "When another device or client is active, silence notifications on this device", ), if (PlatformUtils.isLinux || PlatformUtils.isWindows) Column( @@ -112,20 +109,16 @@ class _NotificationSettingsPageState extends State { BooleanPreferenceToggle( preference: preferences.suppressNotificationWhenRoomFocused, title: "Hide notifications for current room", - description: - "When receiving a message, if you have the chat selected and the app is in focus, dont show the notification", + description: "When receiving a message, if you have the chat selected and the app is in focus, dont show the notification", ), if (PlatformUtils.isLinux) Column( children: [ - SizedBox( - height: 20, - ), + SizedBox(height: 20), BooleanPreferenceToggle( preference: preferences.showNotificationBadgesInTaskbar, title: "Notification Badges", - description: - "Show a badge with the number of unread messages in the system taskbar", + description: "Show a badge with the number of unread messages in the system taskbar", onChanged: (enabled) { if (enabled) { NotificationManager.notifier?.enableBadges(); @@ -141,8 +134,9 @@ class _NotificationSettingsPageState extends State { "Apply user formatting in message notifications", ), AnimatedOpacity( - opacity: - preferences.formatNotificationBody.value ? 1 : 0.3, + opacity: preferences.formatNotificationBody.value + ? 1 + : 0.3, duration: Durations.short4, child: IgnorePointer( ignoring: @@ -152,14 +146,12 @@ class _NotificationSettingsPageState extends State { BooleanPreferenceToggle( preference: preferences.showMediaInNotifications, title: "Show Images", - description: - "Show images in notifications, if allowed by 'General > Media Preview' settings", + description: "Show images in notifications, if allowed by 'General > Media Preview' settings", ), BooleanPreferenceToggle( preference: preferences.previewUrlInNotifications, title: "Preview Urls", - description: - "Fetch URL previews to show extra information about links in notifications", + description: "Fetch URL previews to show extra information about links in notifications", ), ], ), @@ -167,9 +159,7 @@ class _NotificationSettingsPageState extends State { ), ], ), - SizedBox( - height: 20, - ), + SizedBox(height: 20), DoublePreferenceSlider( preference: preferences.notificationsVolume, min: 0, @@ -196,20 +186,21 @@ class _NotificationSettingsPageState extends State { crossAxisAlignment: CrossAxisAlignment.end, children: [ tiamat.DropdownTextField( - key: pushGatewayKey, - initialValue: preferences.pushGateway, - textEditorPlaceholder: "push.example.com", - editableEntryPlaceholder: "Custom push gateway", - items: [ - "push.commet.chat", - if (notifier is UnifiedPushNotifier) - "matrix.gateway.unifiedpush.org" - ]), + key: pushGatewayKey, + initialValue: preferences.pushGateway, + textEditorPlaceholder: "push.example.com", + editableEntryPlaceholder: "Custom push gateway", + items: [ + "push.commet.chat", + if (notifier is UnifiedPushNotifier) + "matrix.gateway.unifiedpush.org", + ], + ), tiamat.Button( text: CommonStrings.promptApply, isLoading: isPushGatewayLoading, onTap: onPushGatewaySelected, - ) + ), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/app/notification_settings/notifier_component_view/matrix_notifier_component_view.dart b/commet/lib/ui/pages/settings/categories/app/notification_settings/notifier_component_view/matrix_notifier_component_view.dart index 8b9514902..f2b06e1c9 100644 --- a/commet/lib/ui/pages/settings/categories/app/notification_settings/notifier_component_view/matrix_notifier_component_view.dart +++ b/commet/lib/ui/pages/settings/categories/app/notification_settings/notifier_component_view/matrix_notifier_component_view.dart @@ -34,45 +34,54 @@ class _MatrixNotifierComponentViewState @override Widget build(BuildContext context) { if (pushers == null) { - return const Center( - child: CircularProgressIndicator(), - ); + return const Center(child: CircularProgressIndicator()); } - final ourPushers = pushers!.where((e) => - e.deviceDisplayName == - widget.component.client.getMatrixClient().clientName); + final ourPushers = pushers!.where( + (e) => + e.deviceDisplayName == + widget.component.client.getMatrixClient().clientName, + ); - final otherPushers = pushers!.where((e) => - e.deviceDisplayName != - widget.component.client.getMatrixClient().clientName); + final otherPushers = pushers!.where( + (e) => + e.deviceDisplayName != + widget.component.client.getMatrixClient().clientName, + ); - return Column(children: [ - Panel( - header: "This Device", - mode: TileType.surfaceContainerLowest, - child: Column( + return Column( + children: [ + Panel( + header: "This Device", + mode: TileType.surfaceContainerLowest, + child: Column( children: ourPushers - .map((e) => Padding( + .map( + (e) => Padding( padding: const EdgeInsets.fromLTRB(0, 4, 0, 4), - child: buildPusher(e))) - .toList()), - ), - const SizedBox( - height: 10, - ), - Panel( - header: "Other Devices", - mode: TileType.surfaceContainerLowest, - child: Column( + child: buildPusher(e), + ), + ) + .toList(), + ), + ), + const SizedBox(height: 10), + Panel( + header: "Other Devices", + mode: TileType.surfaceContainerLowest, + child: Column( children: otherPushers - .map((e) => Padding( - padding: const EdgeInsets.fromLTRB(0, 4, 0, 4), - child: buildPusher(e), - )) - .toList()), - ), - ]); + .map( + (e) => Padding( + padding: const EdgeInsets.fromLTRB(0, 4, 0, 4), + child: buildPusher(e), + ), + ) + .toList(), + ), + ), + ], + ); } Widget buildPusher(matrix.Pusher pusher) { @@ -82,10 +91,11 @@ class _MatrixNotifierComponentViewState var uri = Uri.parse(pusher.pushkey); if (uri.scheme == "http" || uri.scheme == "https") { var redacted = Uri( - host: uri.host, - port: uri.port, - scheme: uri.scheme, - path: "${uri.path.substring(0, 6)}..."); + host: uri.host, + port: uri.port, + scheme: uri.scheme, + path: "${uri.path.substring(0, 6)}...", + ); keyDisplay = Uri.decodeFull(redacted.toString()); } @@ -103,10 +113,14 @@ class _MatrixNotifierComponentViewState tiamat.Text.label(pusher.appDisplayName), tiamat.Text.labelLow(pusher.appId), tiamat.Text.labelLow("key: $keyDisplay"), - tiamat.Text.labelLow("device: ${pusher.deviceDisplayName}", - maxLines: 1, overflow: TextOverflow.ellipsis), tiamat.Text.labelLow( - "data: ${const JsonEncoder.withIndent(" ").convert(pusher.data.toJson())}"), + "device: ${pusher.deviceDisplayName}", + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + tiamat.Text.labelLow( + "data: ${const JsonEncoder.withIndent(" ").convert(pusher.data.toJson())}", + ), tiamat.Text.labelLow("kind: ${pusher.kind}"), ], ), diff --git a/commet/lib/ui/pages/settings/categories/app/notification_settings/notifier_component_view/notifier_component_view.dart b/commet/lib/ui/pages/settings/categories/app/notification_settings/notifier_component_view/notifier_component_view.dart index 0edecb75d..41e55f998 100644 --- a/commet/lib/ui/pages/settings/categories/app/notification_settings/notifier_component_view/notifier_component_view.dart +++ b/commet/lib/ui/pages/settings/categories/app/notification_settings/notifier_component_view/notifier_component_view.dart @@ -4,8 +4,10 @@ import 'package:commet/ui/pages/settings/categories/app/notification_settings/no import 'package:flutter/material.dart'; class PushNotificationComponentDebugView extends StatefulWidget { - const PushNotificationComponentDebugView(this.pushNotificationComponent, - {super.key}); + const PushNotificationComponentDebugView( + this.pushNotificationComponent, { + super.key, + }); final PushNotificationComponent pushNotificationComponent; @override State createState() => @@ -18,11 +20,10 @@ class _PushNotificationComponentDebugViewState Widget build(BuildContext context) { if (widget.pushNotificationComponent is MatrixPushNotificationComponent) { return MatrixNotifierComponentView( - widget.pushNotificationComponent as MatrixPushNotificationComponent); + widget.pushNotificationComponent as MatrixPushNotificationComponent, + ); } - return const Placeholder( - color: Colors.red, - ); + return const Placeholder(color: Colors.red); } } diff --git a/commet/lib/ui/pages/settings/categories/app/notification_settings/notifier_debug_view.dart b/commet/lib/ui/pages/settings/categories/app/notification_settings/notifier_debug_view.dart index 28cc6702d..46304fb7a 100644 --- a/commet/lib/ui/pages/settings/categories/app/notification_settings/notifier_debug_view.dart +++ b/commet/lib/ui/pages/settings/categories/app/notification_settings/notifier_debug_view.dart @@ -38,7 +38,8 @@ class _NotifierDebugViewState extends State { PushNotificationComponentDebugView( component!, key: ValueKey( - "push_notification_debug_view:${component!.client.identifier}"), + "push_notification_debug_view:${component!.client.identifier}", + ), ), ], ); diff --git a/commet/lib/ui/pages/settings/categories/app/settings_category_app.dart b/commet/lib/ui/pages/settings/categories/app/settings_category_app.dart index 1019427ac..e312843a2 100644 --- a/commet/lib/ui/pages/settings/categories/app/settings_category_app.dart +++ b/commet/lib/ui/pages/settings/categories/app/settings_category_app.dart @@ -18,116 +18,143 @@ import 'package:flutter/material.dart' as m; import 'package:intl/intl.dart'; class SettingsCategoryApp implements SettingsCategory { - String get labelSettingsAppGeneral => Intl.message("General", - name: "labelSettingsAppGeneral", - desc: "Label for the App General settings page"); + String get labelSettingsAppGeneral => Intl.message( + "General", + name: "labelSettingsAppGeneral", + desc: "Label for the App General settings page", + ); - String get labelSettingsAppAppearance => Intl.message("Appearance", - name: "labelSettingsAppAppearance", - desc: "Label for the App Appearance settings page"); + String get labelSettingsAppAppearance => Intl.message( + "Appearance", + name: "labelSettingsAppAppearance", + desc: "Label for the App Appearance settings page", + ); - String get labelSettingsWindowBehaviour => Intl.message("Window Behaviour", - name: "labelSettingsWindowBehaviour", - desc: "Label for the Window Behaviour settings page"); + String get labelSettingsWindowBehaviour => Intl.message( + "Window Behaviour", + name: "labelSettingsWindowBehaviour", + desc: "Label for the Window Behaviour settings page", + ); - String get labelSettingsAppAdvanced => Intl.message("Advanced", - name: "labelSettingsAppAdvanced", - desc: "Label for the App Advanced settings page"); + String get labelSettingsAppAdvanced => Intl.message( + "Advanced", + name: "labelSettingsAppAdvanced", + desc: "Label for the App Advanced settings page", + ); - String get labelSettingsAppExperiments => Intl.message("Experiments", - name: "labelSettingsAppExperiments", - desc: "Label for the App Experiments settings page"); + String get labelSettingsAppExperiments => Intl.message( + "Experiments", + name: "labelSettingsAppExperiments", + desc: "Label for the App Experiments settings page", + ); - String get labelSettingsAppNotifications => Intl.message("Notifications", - name: "labelSettingsAppNotifications", - desc: "Label for the App notifications settings page"); + String get labelSettingsAppNotifications => Intl.message( + "Notifications", + name: "labelSettingsAppNotifications", + desc: "Label for the App notifications settings page", + ); - String get labelSettingsShortcuts => Intl.message("Shortcuts", - name: "labelSettingsShortcuts", - desc: "Label for the Keyboard shortcuts settings page"); + String get labelSettingsShortcuts => Intl.message( + "Shortcuts", + name: "labelSettingsShortcuts", + desc: "Label for the Keyboard shortcuts settings page", + ); - String get labelSettingsAppDeveloperUtils => Intl.message("Developer Utils", - name: "labelSettingsAppDeveloperUtils", - desc: - "Label for the developer utils settings page, usually hidden unless developer mode is turned on"); + String get labelSettingsAppDeveloperUtils => Intl.message( + "Developer Utils", + name: "labelSettingsAppDeveloperUtils", + desc: "Label for the developer utils settings page, usually hidden unless developer mode is turned on", + ); - String get labelSettingsCategoryApp => Intl.message("App Settings", - name: "labelSettingsCategoryApp", - desc: "Label for the settings category of the overall App settings/"); + String get labelSettingsCategoryApp => Intl.message( + "App Settings", + name: "labelSettingsCategoryApp", + desc: "Label for the settings category of the overall App settings/", + ); String get labelSettingsCategoryVoiceAndVideo => Intl.message( - "Voice and Video", - name: "labelSettingsCategoryVoiceAndVideo", - desc: "Label for the settings category related to voice and video calls"); + "Voice and Video", + name: "labelSettingsCategoryVoiceAndVideo", + desc: "Label for the settings category related to voice and video calls", + ); @override String get title => labelSettingsCategoryApp; @override List get tabs => List.from([ - SettingsTab( - label: labelSettingsAppGeneral, - icon: m.Icons.settings, - pageBuilder: (context) { - return const GeneralSettingsPage(); - }), - SettingsTab( - label: labelSettingsAppAppearance, - icon: m.Icons.style, - pageBuilder: (context) { - return const AppearanceSettingsPage(); - }), - if (clientManager?.clients - .any((e) => e.getComponent() != null) == - true) - SettingsTab( - label: labelSettingsCategoryVoiceAndVideo, - icon: m.Icons.call, - pageBuilder: (context) { - return const VoipSettingsPage(); - }), - if (PlatformUtils.isLinux || PlatformUtils.isWindows) - SettingsTab( - label: labelSettingsShortcuts, - icon: m.Icons.keyboard_alt_outlined, - pageBuilder: (context) { - return const ShortcutSettingsPage(); - }), - if (BuildConfig.DESKTOP) - SettingsTab( - label: labelSettingsWindowBehaviour, - icon: m.Icons.window, - pageBuilder: (context) { - return const WindowSettingsPage(); - }), - // We really only need to configure on unified push - if (BuildConfig.LINUX || BuildConfig.ANDROID) - SettingsTab( - label: labelSettingsAppNotifications, - icon: m.Icons.notifications, - pageBuilder: (context) { - return const NotificationSettingsPage(); - }), - SettingsTab( - label: labelSettingsAppAdvanced, - icon: m.Icons.code, - pageBuilder: (context) { - return const AdvancedSettingsPage(); - }), - if (Experiments.hasExperiments) - SettingsTab( - label: labelSettingsAppExperiments, - icon: m.Icons.science, - pageBuilder: (context) { - return const ExperimentsSettingsPage(); - }), - if (preferences.developerMode.value) - SettingsTab( - label: labelSettingsAppDeveloperUtils, - icon: m.Icons.bug_report, - pageBuilder: (context) { - return const DeveloperSettingsPage(); - }, - ), - ]); + SettingsTab( + label: labelSettingsAppGeneral, + icon: m.Icons.settings, + pageBuilder: (context) { + return const GeneralSettingsPage(); + }, + ), + SettingsTab( + label: labelSettingsAppAppearance, + icon: m.Icons.style, + pageBuilder: (context) { + return const AppearanceSettingsPage(); + }, + ), + if (clientManager?.clients.any( + (e) => e.getComponent() != null, + ) == + true) + SettingsTab( + label: labelSettingsCategoryVoiceAndVideo, + icon: m.Icons.call, + pageBuilder: (context) { + return const VoipSettingsPage(); + }, + ), + if (PlatformUtils.isLinux || PlatformUtils.isWindows) + SettingsTab( + label: labelSettingsShortcuts, + icon: m.Icons.keyboard_alt_outlined, + pageBuilder: (context) { + return const ShortcutSettingsPage(); + }, + ), + if (BuildConfig.DESKTOP) + SettingsTab( + label: labelSettingsWindowBehaviour, + icon: m.Icons.window, + pageBuilder: (context) { + return const WindowSettingsPage(); + }, + ), + // We really only need to configure on unified push + if (BuildConfig.LINUX || BuildConfig.ANDROID) + SettingsTab( + label: labelSettingsAppNotifications, + icon: m.Icons.notifications, + pageBuilder: (context) { + return const NotificationSettingsPage(); + }, + ), + SettingsTab( + label: labelSettingsAppAdvanced, + icon: m.Icons.code, + pageBuilder: (context) { + return const AdvancedSettingsPage(); + }, + ), + if (Experiments.hasExperiments) + SettingsTab( + label: labelSettingsAppExperiments, + icon: m.Icons.science, + pageBuilder: (context) { + return const ExperimentsSettingsPage(); + }, + ), + if (preferences.developerMode.value) + SettingsTab( + label: labelSettingsAppDeveloperUtils, + icon: m.Icons.bug_report, + pageBuilder: (context) { + return const DeveloperSettingsPage(); + }, + ), + ]); } diff --git a/commet/lib/ui/pages/settings/categories/app/shortcut_settings/keyboard_hook_shortcuts_settings_page.dart b/commet/lib/ui/pages/settings/categories/app/shortcut_settings/keyboard_hook_shortcuts_settings_page.dart index a5a803e63..a8b05a869 100644 --- a/commet/lib/ui/pages/settings/categories/app/shortcut_settings/keyboard_hook_shortcuts_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/app/shortcut_settings/keyboard_hook_shortcuts_settings_page.dart @@ -16,24 +16,25 @@ class KeyboardHookShortcutsSettingsPage extends StatefulWidget { _KeyboardHookShortcutsSettingsPageState(); static String get labelConfigureKeyboardShortcuts => Intl.message( - "Configure Shortcuts", - name: "labelConfigureKeyboardShortcuts", - desc: - "Label for the tile containing settings to configure system wide keyboard shortcuts, for muting, unmuting etc"); + "Configure Shortcuts", + name: "labelConfigureKeyboardShortcuts", + desc: "Label for the tile containing settings to configure system wide keyboard shortcuts, for muting, unmuting etc", + ); } class _KeyboardHookShortcutsSettingsPageState extends State { String get promptShortcutsPressAKeyCombination => Intl.message( - "Press a key combination", - name: "promptShortcutsPressAKeyCombination", - desc: - "Prompt the user to input a key combination, which is recorded and used to activate a shortcut"); + "Press a key combination", + name: "promptShortcutsPressAKeyCombination", + desc: "Prompt the user to input a key combination, which is recorded and used to activate a shortcut", + ); - String get promptShortcutsClearKeyboardShortcut => - Intl.message("Clear Shortcut", - name: "promptShortcutsClearKeyboardShortcut", - desc: "Prompt the user to clear a key combination shortcut"); + String get promptShortcutsClearKeyboardShortcut => Intl.message( + "Clear Shortcut", + name: "promptShortcutsClearKeyboardShortcut", + desc: "Prompt the user to clear a key combination shortcut", + ); @override Widget build(BuildContext context) { @@ -51,56 +52,64 @@ class _KeyboardHookShortcutsSettingsPageState clipBehavior: Clip.antiAlias, child: InkWell( onTap: () async { - var key = await AdaptiveDialog.show(context, - dismissible: false, builder: (context) { - HotKey? hotkey = shortcut.value.hotkey; + var key = await AdaptiveDialog.show( + context, + dismissible: false, + builder: (context) { + HotKey? hotkey = shortcut.value.hotkey; - return Column( - spacing: 8, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - tiamat.Text.largeTitle( - promptShortcutsPressAKeyCombination), - SizedBox( - height: 50, - child: Center( - child: HotKeyRecorder( + return Column( + spacing: 8, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + tiamat.Text.largeTitle( + promptShortcutsPressAKeyCombination, + ), + SizedBox( + height: 50, + child: Center( + child: HotKeyRecorder( initalHotKey: hotkey, onHotKeyRecorded: (k) { hotkey = k; - }), + }, + ), + ), ), - ), - tiamat.Button( - text: CommonStrings.promptSubmit, - onTap: () => Navigator.of(context).pop(hotkey), - ), - tiamat.Button.secondary( - text: promptShortcutsClearKeyboardShortcut, - onTap: () => Navigator.of(context).pop(null), - ) - ], - ); - }); + tiamat.Button( + text: CommonStrings.promptSubmit, + onTap: () => Navigator.of(context).pop(hotkey), + ), + tiamat.Button.secondary( + text: promptShortcutsClearKeyboardShortcut, + onTap: () => Navigator.of(context).pop(null), + ), + ], + ); + }, + ); if (PlatformUtils.isLinux) { if (key?.modifiers?.contains(HotKeyModifier.shift) == true) { - await AdaptiveDialog.show(context, - title: "Warning", - builder: (_) => SizedBox( - width: 500, - child: Column( - children: [ - tiamat.Text.label( - "Hotkeys using 'Shift' as a modifier may be unreliable on Linux, consider using a different key combination"), - tiamat.Button.secondary( - text: "Okay!", - onTap: () => Navigator.of(context).pop(), - ) - ], - ), - )); + await AdaptiveDialog.show( + context, + title: "Warning", + builder: (_) => SizedBox( + width: 500, + child: Column( + children: [ + tiamat.Text.label( + "Hotkeys using 'Shift' as a modifier may be unreliable on Linux, consider using a different key combination", + ), + tiamat.Button.secondary( + text: "Okay!", + onTap: () => Navigator.of(context).pop(), + ), + ], + ), + ), + ); } } @@ -120,12 +129,12 @@ class _KeyboardHookShortcutsSettingsPageState children: [ tiamat.Text(shortcut.value.getDisplayName()), if (shortcut.value.hotkey != null) - HotKeyVirtualView(hotKey: shortcut.value.hotkey!) + HotKeyVirtualView(hotKey: shortcut.value.hotkey!), ], ), ), ), - ) + ), ], ), ); diff --git a/commet/lib/ui/pages/settings/categories/app/shortcut_settings/outsource_shortcut_settings_page.dart b/commet/lib/ui/pages/settings/categories/app/shortcut_settings/outsource_shortcut_settings_page.dart index 88838d483..9ef52a363 100644 --- a/commet/lib/ui/pages/settings/categories/app/shortcut_settings/outsource_shortcut_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/app/shortcut_settings/outsource_shortcut_settings_page.dart @@ -9,14 +9,15 @@ class OutsourceShortcutSettingsPage extends StatelessWidget { const OutsourceShortcutSettingsPage({super.key}); String get labelSystemKeyboardShortcutsOutsourceDescription => Intl.message( - "In your current environment, keyboard shortcuts must be configured in your system settings.", - name: "labelSystemKeyboardShortcutsOutsourceDescription", - ); + "In your current environment, keyboard shortcuts must be configured in your system settings.", + name: "labelSystemKeyboardShortcutsOutsourceDescription", + ); - String get promptSystemKeyboardShortcutsMoreInfo => Intl.message("More Info", - name: "promptSystemKeyboardShortcutsMoreInfo", - desc: - "Prompt for a button on the system keyboard shortcut page, which opens a webpage that provides further information about keyboard shortcuts setup"); + String get promptSystemKeyboardShortcutsMoreInfo => Intl.message( + "More Info", + name: "promptSystemKeyboardShortcutsMoreInfo", + desc: "Prompt for a button on the system keyboard shortcut page, which opens a webpage that provides further information about keyboard shortcuts setup", + ); @override Widget build(BuildContext context) { @@ -27,14 +28,13 @@ class OutsourceShortcutSettingsPage extends StatelessWidget { spacing: 20, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - tiamat.Text( - labelSystemKeyboardShortcutsOutsourceDescription, - ), + tiamat.Text(labelSystemKeyboardShortcutsOutsourceDescription), tiamat.Button.secondary( text: promptSystemKeyboardShortcutsMoreInfo, onTap: () => LinkUtils.open( - Uri.parse("https://commet.chat/info/keyboard-shortcuts")), - ) + Uri.parse("https://commet.chat/info/keyboard-shortcuts"), + ), + ), ], ), ); diff --git a/commet/lib/ui/pages/settings/categories/app/shortcut_settings/shortcut_settings_page.dart b/commet/lib/ui/pages/settings/categories/app/shortcut_settings/shortcut_settings_page.dart index 9f59e3f13..a1cd189ac 100644 --- a/commet/lib/ui/pages/settings/categories/app/shortcut_settings/shortcut_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/app/shortcut_settings/shortcut_settings_page.dart @@ -17,7 +17,7 @@ class ShortcutSettingsPage extends StatelessWidget { bool showOutsourceMenu = PlatformUtils.isDisplayServer(DisplayServer.Wayland) && - PlatformUtils.isDesktopEnvironment(DesktopEnvironment.KDEPlasma); + PlatformUtils.isDesktopEnvironment(DesktopEnvironment.KDEPlasma); bool showHooksMenu = !showOutsourceMenu; @@ -33,7 +33,7 @@ class ShortcutSettingsPage extends StatelessWidget { spacing: 8, children: [ if (showOutsourceMenu) OutsourceShortcutSettingsPage(), - if (showHooksMenu) KeyboardHookShortcutsSettingsPage() + if (showHooksMenu) KeyboardHookShortcutsSettingsPage(), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/app/string_list_preference_editor.dart b/commet/lib/ui/pages/settings/categories/app/string_list_preference_editor.dart index 5a003aacd..bc89968c6 100644 --- a/commet/lib/ui/pages/settings/categories/app/string_list_preference_editor.dart +++ b/commet/lib/ui/pages/settings/categories/app/string_list_preference_editor.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class StringListPreferenceEditor extends StatefulWidget { - const StringListPreferenceEditor( - {required this.preference, - required this.title, - this.description, - super.key}); + const StringListPreferenceEditor({ + required this.preference, + required this.title, + this.description, + super.key, + }); final StringListPreference preference; final String title; @@ -33,62 +34,68 @@ class _StringListPreferenceEditorState @override Widget build(BuildContext context) { return Container( - decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainer.withAlpha(100), - border: BoxBorder.all( - color: ColorScheme.of(context).secondary.withAlpha(20)), - borderRadius: BorderRadius.circular(8)), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - tiamat.Text(widget.title), - if (widget.description != null) - tiamat.Text.labelLow(widget.description!), - Padding( - padding: const EdgeInsets.fromLTRB(0, 8, 0, 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (items.isEmpty) - SizedBox( - height: 50, - child: - Center(child: tiamat.Text.labelLow("No Entries")), - ), - if (items.isNotEmpty) - Column( - spacing: 8, - crossAxisAlignment: CrossAxisAlignment.start, - children: items - .map((i) => Row( - spacing: 8, - children: [ - tiamat.IconButton( - size: 18, - icon: Icons.delete, - onPressed: () async { - if (await AdaptiveDialog.confirmation( - context) == - true) { - widget.preference.remove(i); + decoration: BoxDecoration( + color: ColorScheme.of(context).surfaceContainer.withAlpha(100), + border: BoxBorder.all( + color: ColorScheme.of(context).secondary.withAlpha(20), + ), + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + tiamat.Text(widget.title), + if (widget.description != null) + tiamat.Text.labelLow(widget.description!), + Padding( + padding: const EdgeInsets.fromLTRB(0, 8, 0, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (items.isEmpty) + SizedBox( + height: 50, + child: Center(child: tiamat.Text.labelLow("No Entries")), + ), + if (items.isNotEmpty) + Column( + spacing: 8, + crossAxisAlignment: CrossAxisAlignment.start, + children: items + .map( + (i) => Row( + spacing: 8, + children: [ + tiamat.IconButton( + size: 18, + icon: Icons.delete, + onPressed: () async { + if (await AdaptiveDialog.confirmation( + context, + ) == + true) { + widget.preference.remove(i); - setState(() { - items = widget.preference.value; - }); - } - }, - ), - tiamat.Text.labelLow(i), - ], - )) - .toList(), - ), - ], - ), - ) - ], - ))); + setState(() { + items = widget.preference.value; + }); + } + }, + ), + tiamat.Text.labelLow(i), + ], + ), + ) + .toList(), + ), + ], + ), + ), + ], + ), + ), + ); } } diff --git a/commet/lib/ui/pages/settings/categories/app/string_preference_options.dart b/commet/lib/ui/pages/settings/categories/app/string_preference_options.dart index dba587f74..39dff320f 100644 --- a/commet/lib/ui/pages/settings/categories/app/string_preference_options.dart +++ b/commet/lib/ui/pages/settings/categories/app/string_preference_options.dart @@ -4,13 +4,14 @@ import 'package:flutter/material.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class StringPreferenceOptionsPicker extends StatefulWidget { - const StringPreferenceOptionsPicker( - {required this.preference, - required this.title, - this.description, - this.onChanged, - required this.options, - super.key}); + const StringPreferenceOptionsPicker({ + required this.preference, + required this.title, + this.description, + this.onChanged, + required this.options, + super.key, + }); final StringPreference preference; final Function(bool)? onChanged; @@ -30,10 +31,12 @@ class _StringPreferenceOptionsPickerState Widget build(BuildContext context) { return Container( decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainer.withAlpha(100), - border: BoxBorder.all( - color: ColorScheme.of(context).secondary.withAlpha(20)), - borderRadius: BorderRadius.circular(8)), + color: ColorScheme.of(context).surfaceContainer.withAlpha(100), + border: BoxBorder.all( + color: ColorScheme.of(context).secondary.withAlpha(20), + ), + borderRadius: BorderRadius.circular(8), + ), child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -42,23 +45,22 @@ class _StringPreferenceOptionsPickerState tiamat.Text(widget.title), if (widget.description != null) tiamat.Text.labelLow(widget.description!), - SizedBox( - height: 8, - ), + SizedBox(height: 8), tiamat.DropdownSelector( - color: ColorScheme.of(context).surfaceContainerLow, - items: widget.options, - itemBuilder: (item) { - return tiamat.Text(item); - }, - onItemSelected: (item) { - setState(() { - if (item != null) { - widget.preference.set(item); - } - }); - }, - value: widget.preference.value) + color: ColorScheme.of(context).surfaceContainerLow, + items: widget.options, + itemBuilder: (item) { + return tiamat.Text(item); + }, + onItemSelected: (item) { + setState(() { + if (item != null) { + widget.preference.set(item); + } + }); + }, + value: widget.preference.value, + ), ], ), ), diff --git a/commet/lib/ui/pages/settings/categories/app/theme_settings/theme_settings_widget.dart b/commet/lib/ui/pages/settings/categories/app/theme_settings/theme_settings_widget.dart index f6669ea08..52a6d8207 100644 --- a/commet/lib/ui/pages/settings/categories/app/theme_settings/theme_settings_widget.dart +++ b/commet/lib/ui/pages/settings/categories/app/theme_settings/theme_settings_widget.dart @@ -32,8 +32,11 @@ class _ThemeEntry { return child; } - _ThemeEntry(this.name, this.setter, - {Widget Function(BuildContext context, Widget child)? builder}) { + _ThemeEntry( + this.name, + this.setter, { + Widget Function(BuildContext context, Widget child)? builder, + }) { this.builder = builder ?? defaultBuilder; } } @@ -42,36 +45,48 @@ class _ThemeListWidgetState extends State { late List<_ThemeEntry> entries; StreamSubscription? customThemesDirSub; - String get labelThemeDark => Intl.message("Dark Theme", - name: "labelThemeDark", desc: "Label for the dark theme"); + String get labelThemeDark => Intl.message( + "Dark Theme", + name: "labelThemeDark", + desc: "Label for the dark theme", + ); - String get labelThemeLight => Intl.message("Light Theme", - name: "labelThemeLight", desc: "Label for the light theme"); + String get labelThemeLight => Intl.message( + "Light Theme", + name: "labelThemeLight", + desc: "Label for the light theme", + ); - String get labelThemeAmoled => Intl.message("Amoled", - name: "labelThemeAmoled", desc: "Label for the light theme"); + String get labelThemeAmoled => Intl.message( + "Amoled", + name: "labelThemeAmoled", + desc: "Label for the light theme", + ); List<_ThemeEntry> get defaultThemes => [ - _ThemeEntry(labelThemeLight, (BuildContext context) async { - preferences.theme.set("light"); - var theme = await preferences.resolveTheme( - overrideBrightness: Brightness.light); - if (context.mounted) ThemeChanger.setTheme(context, theme); - }), - _ThemeEntry(labelThemeDark, (BuildContext context) async { - preferences.theme.set("dark"); - var theme = await preferences.resolveTheme( - overrideBrightness: Brightness.dark); - if (context.mounted) ThemeChanger.setTheme(context, theme); - }), - _ThemeEntry(labelThemeAmoled, (BuildContext context) async { - preferences.theme.set("amoled"); - var theme = await preferences.resolveTheme( - overrideBrightness: Brightness.dark); - - if (context.mounted) ThemeChanger.setTheme(context, theme); - }), - ]; + _ThemeEntry(labelThemeLight, (BuildContext context) async { + preferences.theme.set("light"); + var theme = await preferences.resolveTheme( + overrideBrightness: Brightness.light, + ); + if (context.mounted) ThemeChanger.setTheme(context, theme); + }), + _ThemeEntry(labelThemeDark, (BuildContext context) async { + preferences.theme.set("dark"); + var theme = await preferences.resolveTheme( + overrideBrightness: Brightness.dark, + ); + if (context.mounted) ThemeChanger.setTheme(context, theme); + }), + _ThemeEntry(labelThemeAmoled, (BuildContext context) async { + preferences.theme.set("amoled"); + var theme = await preferences.resolveTheme( + overrideBrightness: Brightness.dark, + ); + + if (context.mounted) ThemeChanger.setTheme(context, theme); + }), + ]; @override void initState() { @@ -89,8 +104,9 @@ class _ThemeListWidgetState extends State { void initCustomThemes() async { loadCustomThemes(); var dir = await ThemeConfig.getCustomThemesDir(); - customThemesDirSub = - dir.watch(recursive: true).listen(onCustomThemesDirUpdated); + customThemesDirSub = dir + .watch(recursive: true) + .listen(onCustomThemesDirUpdated); } void loadCustomThemes() async { @@ -135,8 +151,9 @@ class _ThemeListWidgetState extends State { return tiamat.ContextMenu( items: [ ContextMenuItem( - text: CommonStrings.promptDelete, - onPressed: () => ThemeConfig.removeTheme(e)), + text: CommonStrings.promptDelete, + onPressed: () => ThemeConfig.removeTheme(e), + ), ], child: child, ); @@ -163,9 +180,9 @@ class _ThemeListWidgetState extends State { children: [ for (var entry in entries) entry.builder( - context, - tiamat.TextButton(entry.name, - onTap: () => entry.setter(context))), + context, + tiamat.TextButton(entry.name, onTap: () => entry.setter(context)), + ), Padding( padding: const EdgeInsets.all(8.0), child: Row( @@ -175,9 +192,10 @@ class _ThemeListWidgetState extends State { icon: Icons.add, onPressed: () async { var result = await FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: ["zip"], - dialogTitle: "Pick theme archive file"); + type: FileType.custom, + allowedExtensions: ["zip"], + dialogTitle: "Pick theme archive file", + ); var file = result?.files.firstOrNull; if (file?.path == null) { @@ -190,7 +208,7 @@ class _ThemeListWidgetState extends State { ), ], ), - ) + ), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_debug_matrix_client.dart b/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_debug_matrix_client.dart index 6dc8f517d..b3be74ad3 100644 --- a/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_debug_matrix_client.dart +++ b/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_debug_matrix_client.dart @@ -61,18 +61,20 @@ class _VoipDebugMatrixClientState extends State { if (loading) { return const SizedBox( height: 500, - child: Center( - child: CircularProgressIndicator(), - ), + child: Center(child: CircularProgressIndicator()), ); } return Column( children: [ if (homeserverHasTurnServer == false) - AlertView(Alert(AlertType.warning, + AlertView( + Alert( + AlertType.warning, messageGetter: () => "Your homeserver (${widget.client.getMatrixClient().homeserver}) does not have a TURN server configured", - titleGetter: () => "TURN Error")), + titleGetter: () => "TURN Error", + ), + ), tiamat.Panel( mode: tiamat.TileType.surfaceContainerLow, header: "TURN Server (Homeserver Configuration)", @@ -83,7 +85,7 @@ class _VoipDebugMatrixClientState extends State { testTurnServer(), ], ), - ) + ), ], ); } @@ -99,7 +101,7 @@ class _VoipDebugMatrixClientState extends State { onTap: testTurn, ), ), - if (connection != null) showTestConnectionInfo() + if (connection != null) showTestConnectionInfo(), ], ); } @@ -112,7 +114,8 @@ class _VoipDebugMatrixClientState extends State { tiamat.Text.labelLow("username: ${credentials!.username}"), tiamat.Text.labelLow("password: ${"•" * credentials!.password.length}"), const tiamat.Seperator(), - for (var item in credentials!.uris) tiamat.Text.labelLow(item.toString()) + for (var item in credentials!.uris) + tiamat.Text.labelLow(item.toString()), ], ); } @@ -132,10 +135,14 @@ class _VoipDebugMatrixClientState extends State { child: tiamat.Panel( mode: tiamat.TileType.surfaceContainerLow, header: "Connecting with config:", - child: tiamat.Text.tiny(const JsonEncoder.withIndent(' ') - .convert(connectionConfiguration!) - .replaceAll(credentials?.password ?? "", - "•" * (credentials?.password.length ?? 0))), + child: tiamat.Text.tiny( + const JsonEncoder.withIndent(' ') + .convert(connectionConfiguration!) + .replaceAll( + credentials?.password ?? "", + "•" * (credentials?.password.length ?? 0), + ), + ), ), ), if (foundCandidates.isNotEmpty) @@ -143,33 +150,38 @@ class _VoipDebugMatrixClientState extends State { header: "Candidates", mode: tiamat.TileType.surfaceContainerLowest, child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - for (var candidate in foundCandidates) - Padding( - padding: const EdgeInsets.all(8), - child: tiamat.Text.label( - candidate.candidate ?? "ERROR")), - if (gatheringState == - webrtc.RTCIceGatheringState - .RTCIceGatheringStateGathering) - const Align( - alignment: Alignment.topCenter, - child: CircularProgressIndicator(), - ) - ]), + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + for (var candidate in foundCandidates) + Padding( + padding: const EdgeInsets.all(8), + child: tiamat.Text.label( + candidate.candidate ?? "ERROR", + ), + ), + if (gatheringState == + webrtc + .RTCIceGatheringState + .RTCIceGatheringStateGathering) + const Align( + alignment: Alignment.topCenter, + child: CircularProgressIndicator(), + ), + ], + ), ), if (description != null) Padding( padding: const EdgeInsets.fromLTRB(0, 8, 0, 8), child: tiamat.Panel( - header: "Offer", - mode: tiamat.TileType.surfaceContainerLowest, - child: tiamat.Text.tiny(description!.sdp ?? "")), - ) + header: "Offer", + mode: tiamat.TileType.surfaceContainerLowest, + child: tiamat.Text.tiny(description!.sdp ?? ""), + ), + ), ], ), - ) + ), ], ); } @@ -183,7 +195,7 @@ class _VoipDebugMatrixClientState extends State { { 'username': credentials!.username, 'credential': credentials!.password, - 'urls': List.from(credentials!.uris) + 'urls': List.from(credentials!.uris), }, ]; @@ -205,7 +217,7 @@ class _VoipDebugMatrixClientState extends State { 'audio': { 'echoCancellation': true, 'noiseSuppression': true, - 'autoGainControl': false + 'autoGainControl': false, }, 'video': false, }; @@ -213,8 +225,9 @@ class _VoipDebugMatrixClientState extends State { connection!.onIceCandidate = onIceCandidate; connection!.onIceGatheringState = onIceGatheringState; - var media = - await webrtc.navigator.mediaDevices.getUserMedia(mediaConstraints); + var media = await webrtc.navigator.mediaDevices.getUserMedia( + mediaConstraints, + ); for (var track in media.getTracks()) { await connection!.addTrack(track, media); } diff --git a/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_debug_settings.dart b/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_debug_settings.dart index 7931d7252..56c16c635 100644 --- a/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_debug_settings.dart +++ b/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_debug_settings.dart @@ -41,7 +41,7 @@ class _VoipDebugSettingsState extends State { selectedClient as MatrixClient, key: ValueKey(selectedClient.identifier), ), - ) + ), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_settings_page.dart b/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_settings_page.dart index c0abd3918..e41f8f458 100644 --- a/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_settings_page.dart @@ -31,116 +31,130 @@ class _VoipSettingsPage extends State { List? speakers = []; List? cameras = []; - String get headerVoipSettingsCallConnection => Intl.message("Call Connection", - name: "headerVoipSettingsCallConnection", - desc: - "Header for the settings tile containing configuration relating to the initial connection of a call"); - - String get headerVoipSettingsOverlay => Intl.message("Overlay", - name: "headerVoipSettingsOverlay", - desc: - "Header for the settings tile containing configuration for the voip overlay"); - - String get labelVoipSettingsStunFallback => Intl.message("Use STUN Fallback", - name: "labelVoipSettingsStunFallback", - desc: - "label for the setting to enable STUN callback for connecting calls"); - - String labelVoipSettingsStunFallbackDescription(String stunServer) => - Intl.message( - "Calls cannot be connected without a STUN server. If your homeserver does not provide a STUN server, fall back to using '${stunServer}'. Your IP address will be revealed to this server when establishing calls", - args: [stunServer], - name: "labelVoipSettingsStunFallbackDescription"); - - String get headerVoipSettingsDevices => Intl.message("Devices", - name: "headerVoipSettingsDevices", - desc: - "Header for settings tile containing device configuration, for default audio / video inputs"); - - String get headerVoipSettingsStreamSettings => Intl.message("Stream Settings", - name: "headerVoipSettingsStreamSettings", - desc: "Header for settings tile containing stream quality configuration"); - - String get labelVoipUseSimulcast => Intl.message("Use Simulcast", - name: "labelVoipUseSimulcast", - desc: "label for setting toggle to enable use of Simulcast"); + String get headerVoipSettingsCallConnection => Intl.message( + "Call Connection", + name: "headerVoipSettingsCallConnection", + desc: "Header for the settings tile containing configuration relating to the initial connection of a call", + ); + + String get headerVoipSettingsOverlay => Intl.message( + "Overlay", + name: "headerVoipSettingsOverlay", + desc: "Header for the settings tile containing configuration for the voip overlay", + ); + + String get labelVoipSettingsStunFallback => Intl.message( + "Use STUN Fallback", + name: "labelVoipSettingsStunFallback", + desc: "label for the setting to enable STUN callback for connecting calls", + ); + + String labelVoipSettingsStunFallbackDescription( + String stunServer, + ) => Intl.message( + "Calls cannot be connected without a STUN server. If your homeserver does not provide a STUN server, fall back to using '${stunServer}'. Your IP address will be revealed to this server when establishing calls", + args: [stunServer], + name: "labelVoipSettingsStunFallbackDescription", + ); + + String get headerVoipSettingsDevices => Intl.message( + "Devices", + name: "headerVoipSettingsDevices", + desc: "Header for settings tile containing device configuration, for default audio / video inputs", + ); + + String get headerVoipSettingsStreamSettings => Intl.message( + "Stream Settings", + name: "headerVoipSettingsStreamSettings", + desc: "Header for settings tile containing stream quality configuration", + ); + + String get labelVoipUseSimulcast => Intl.message( + "Use Simulcast", + name: "labelVoipUseSimulcast", + desc: "label for setting toggle to enable use of Simulcast", + ); String get labelVoipUseSimulcastDescription => Intl.message( - "Uploads your streams at multiple different levels of quality, so other users can decide which to use. This will use more bandwidth and system resources.", - name: "labelVoipUseSimulcastDescription", - desc: "description for setting toggle to enable use of Simulcast"); + "Uploads your streams at multiple different levels of quality, so other users can decide which to use. This will use more bandwidth and system resources.", + name: "labelVoipUseSimulcastDescription", + desc: "description for setting toggle to enable use of Simulcast", + ); String get labelVoipStreamMaximumBitrate => Intl.message( - "Stream Maximum Bitrate", - name: "labelVoipStreamMaximumBitrate", - desc: - "label for setting slider to set the maximum bitrate that can be used when streaming"); + "Stream Maximum Bitrate", + name: "labelVoipStreamMaximumBitrate", + desc: "label for setting slider to set the maximum bitrate that can be used when streaming", + ); String get labelVoipStreamMaximumBitrateDescription => Intl.message( - "Determines the overall quality of your stream. Higher is better, but also uses more resources", - name: "labelVoipStreamMaximumBitrateDescription", - ); + "Determines the overall quality of your stream. Higher is better, but also uses more resources", + name: "labelVoipStreamMaximumBitrateDescription", + ); - String get labelVoipStreamFramerate => Intl.message("Stream Framerate", - name: "labelVoipStreamFramerate", - desc: - "label for setting slider to set the framerate at which the screen should be captured when streaming"); + String get labelVoipStreamFramerate => Intl.message( + "Stream Framerate", + name: "labelVoipStreamFramerate", + desc: "label for setting slider to set the framerate at which the screen should be captured when streaming", + ); String get labelVoipStreamFramerateDescription => Intl.message( - "Target frames per second for screen sharing. Higher has smoother motion, but maybe reduce visual clarity.", - name: "labelVoipStreamFramerateDescription", - ); + "Target frames per second for screen sharing. Higher has smoother motion, but maybe reduce visual clarity.", + name: "labelVoipStreamFramerateDescription", + ); String get labelVoipStreamPreferredCodec => Intl.message( - "Preferred Stream Codec", - name: "labelVoipStreamPreferredCodec", - ); + "Preferred Stream Codec", + name: "labelVoipStreamPreferredCodec", + ); String get labelVoipStreamPreferredCodecDescription => Intl.message( - "Choose which format to encode your stream in. Different codecs may run faster on certain devices, and may be unsupported on others. Most devices should support vp8 and h264.", - name: "labelVoipStreamPreferredCodecDescription", - desc: - "Explains the preferred stream codec setting. This is just a preference, and the picked codec may not be used if the user's device does not support it"); + "Choose which format to encode your stream in. Different codecs may run faster on certain devices, and may be unsupported on others. Most devices should support vp8 and h264.", + name: "labelVoipStreamPreferredCodecDescription", + desc: "Explains the preferred stream codec setting. This is just a preference, and the picked codec may not be used if the user's device does not support it", + ); - String get labelVoipStreamResolution => Intl.message( - "Stream Resolution", - name: "labelVoipStreamResolution", - ); + String get labelVoipStreamResolution => + Intl.message("Stream Resolution", name: "labelVoipStreamResolution"); String get labelVoipStreamResolutionDescription => Intl.message( - "The resolution of your stream, higher is better", - name: "labelVoipStreamResolutionDescription", - ); - - String get headerVoipSettingsAudioSettings => Intl.message("Audio Settings", - name: "headerVoipSettingsAudioSettings", - desc: - "Header for settings tile containing stream audio quality configuration"); - - String get labelVoipAudioBitrateSettings => Intl.message("Audio Bitrate", - name: "labelVoipAudioBitrateSettings", - desc: - "label for the slider to adjust the bitrate of outgoing audio on a call"); + "The resolution of your stream, higher is better", + name: "labelVoipStreamResolutionDescription", + ); + + String get headerVoipSettingsAudioSettings => Intl.message( + "Audio Settings", + name: "headerVoipSettingsAudioSettings", + desc: "Header for settings tile containing stream audio quality configuration", + ); + + String get labelVoipAudioBitrateSettings => Intl.message( + "Audio Bitrate", + name: "labelVoipAudioBitrateSettings", + desc: "label for the slider to adjust the bitrate of outgoing audio on a call", + ); String get labelVoipAudioBitrateSettingsDescription => Intl.message( - "Adjust the bitrate of your outgoing audio. Higher is better", - name: "labelVoipAudioBitrateSettingsDescription", - desc: - "describes the behavior for the slider to adjust the bitrate of outgoing audio on a call"); + "Adjust the bitrate of your outgoing audio. Higher is better", + name: "labelVoipAudioBitrateSettingsDescription", + desc: "describes the behavior for the slider to adjust the bitrate of outgoing audio on a call", + ); @override void initState() { super.initState(); sub = preferences.onSettingChanged.listen((event) => setState(() {})); - WebrtcDefaultDevices.getDevices().then((v) => setState(() { - Log.i(v); - devices = v; + WebrtcDefaultDevices.getDevices().then( + (v) => setState(() { + Log.i(v); + devices = v; - microphones = v.where((i) => i.kind == "audioinput").toList(); - speakers = v.where((i) => i.kind == "audiooutput").toList(); - cameras = v.where((i) => i.kind == "videoinput").toList(); - })); + microphones = v.where((i) => i.kind == "audioinput").toList(); + speakers = v.where((i) => i.kind == "audiooutput").toList(); + cameras = v.where((i) => i.kind == "videoinput").toList(); + }), + ); } @override @@ -161,7 +175,8 @@ class _VoipSettingsPage extends State { preference: preferences.useFallbackTurnServer, title: labelVoipSettingsStunFallback, description: labelVoipSettingsStunFallbackDescription( - preferences.fallbackTurnServer.value), + preferences.fallbackTurnServer.value, + ), ), ), tiamat.Panel( @@ -170,8 +185,7 @@ class _VoipSettingsPage extends State { child: BooleanPreferenceToggle( preference: preferences.useVoipOverlay, title: "Enable Overlay", - description: - "When in a call, add an overlay on your screen to show the call participants", + description: "When in a call, add an overlay on your screen to show the call participants", onChanged: (p0) { if (p0 == false) { clientManager?.callManager.removeOverlay(); @@ -187,9 +201,10 @@ class _VoipSettingsPage extends State { child: devicePicker(), ), tiamat.Panel( - header: headerVoipSettingsAudioSettings, - mode: tiamat.TileType.surfaceContainerLow, - child: Column(children: [ + header: headerVoipSettingsAudioSettings, + mode: tiamat.TileType.surfaceContainerLow, + child: Column( + children: [ DoublePreferenceSlider( preference: preferences.streamAudioBitrate, title: labelVoipAudioBitrateSettings, @@ -199,59 +214,60 @@ class _VoipSettingsPage extends State { max: 128, units: "Kbps", ), - ])), + ], + ), + ), tiamat.Panel( - header: headerVoipSettingsStreamSettings, - mode: tiamat.TileType.surfaceContainerLow, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 12, - children: [ - BooleanPreferenceToggle( - preference: preferences.doSimulcast, - title: labelVoipUseSimulcast, - description: labelVoipUseSimulcastDescription), - DoublePreferenceSlider( - preference: preferences.streamBitrate, - min: 1, - max: 32, - units: "Mbps", - title: labelVoipStreamMaximumBitrate, - description: labelVoipStreamMaximumBitrateDescription, - ), - DoublePreferenceSlider( - preference: preferences.streamFramerate, - min: 5, - max: 60, - numDecimals: 0, - units: "FPS", - title: labelVoipStreamFramerate, - description: labelVoipStreamFramerateDescription, - ), - StringPreferenceOptionsPicker( - preference: preferences.streamCodec, - title: labelVoipStreamPreferredCodec, - description: labelVoipStreamPreferredCodecDescription, - options: [ - "h264", - "h265", - "vp9", - "vp8", - "av1", - ]), - if (preferences.developerMode.value) - StringPreferenceOptionsPicker( - preference: preferences.streamResolution, - title: labelVoipStreamResolution, - description: labelVoipStreamResolutionDescription, - options: [ - "640x360", - "960x540", - "1280x720", - "1920x1080", - "2560x1440", - ]) - ])), + header: headerVoipSettingsStreamSettings, + mode: tiamat.TileType.surfaceContainerLow, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 12, + children: [ + BooleanPreferenceToggle( + preference: preferences.doSimulcast, + title: labelVoipUseSimulcast, + description: labelVoipUseSimulcastDescription, + ), + DoublePreferenceSlider( + preference: preferences.streamBitrate, + min: 1, + max: 32, + units: "Mbps", + title: labelVoipStreamMaximumBitrate, + description: labelVoipStreamMaximumBitrateDescription, + ), + DoublePreferenceSlider( + preference: preferences.streamFramerate, + min: 5, + max: 60, + numDecimals: 0, + units: "FPS", + title: labelVoipStreamFramerate, + description: labelVoipStreamFramerateDescription, + ), + StringPreferenceOptionsPicker( + preference: preferences.streamCodec, + title: labelVoipStreamPreferredCodec, + description: labelVoipStreamPreferredCodecDescription, + options: ["h264", "h265", "vp9", "vp8", "av1"], + ), + if (preferences.developerMode.value) + StringPreferenceOptionsPicker( + preference: preferences.streamResolution, + title: labelVoipStreamResolution, + description: labelVoipStreamResolutionDescription, + options: [ + "640x360", + "960x540", + "1280x720", + "1920x1080", + "2560x1440", + ], + ), + ], + ), + ), if (preferences.developerMode.value) const Padding( padding: EdgeInsets.fromLTRB(0, 8, 0, 0), @@ -266,51 +282,58 @@ class _VoipSettingsPage extends State { } Widget devicePicker() { - return Column(spacing: 8, children: [ - if (microphones != null && !PlatformUtils.isAndroid) - buildPicker( - "Default Audio Input", - preferences.voipDefaultAudioInput.value, - microphones!, - onSelected: (device) async { - await preferences.voipDefaultAudioInput.set(device?.label); - - WebrtcDefaultDevices.selectInputDevice(); - - setState(() {}); - }, - ), - if (speakers != null) - buildPicker( - "Audio Output", - preferences.voipDefaultAudioOutput.value, - speakers!, - onSelected: (device) async { - await preferences.voipDefaultAudioOutput.set(device?.label); - - WebrtcDefaultDevices.selectOutputDevice(); - setState(() {}); - }, - ), - // if (cameras != null) - // buildPicker( - // "Video Input", - // preferences.voipDefaultVideoInput, - // cameras!, - // onSelected: (device) { - // setState(() { - // preferences.setVoipDefaultVideoInput(device?.label); - // }); - // }, - // ), - ]); + return Column( + spacing: 8, + children: [ + if (microphones != null && !PlatformUtils.isAndroid) + buildPicker( + "Default Audio Input", + preferences.voipDefaultAudioInput.value, + microphones!, + onSelected: (device) async { + await preferences.voipDefaultAudioInput.set(device?.label); + + WebrtcDefaultDevices.selectInputDevice(); + + setState(() {}); + }, + ), + if (speakers != null) + buildPicker( + "Audio Output", + preferences.voipDefaultAudioOutput.value, + speakers!, + onSelected: (device) async { + await preferences.voipDefaultAudioOutput.set(device?.label); + + WebrtcDefaultDevices.selectOutputDevice(); + setState(() {}); + }, + ), + // if (cameras != null) + // buildPicker( + // "Video Input", + // preferences.voipDefaultVideoInput, + // cameras!, + // onSelected: (device) { + // setState(() { + // preferences.setVoipDefaultVideoInput(device?.label); + // }); + // }, + // ), + ], + ); } Widget buildPicker( - String label, String? selected, List microphones, - {Function(webrtc.MediaDeviceInfo? device)? onSelected}) { - var selectedDevice = - microphones.firstWhereOrNull((i) => i.label == selected); + String label, + String? selected, + List microphones, { + Function(webrtc.MediaDeviceInfo? device)? onSelected, + }) { + var selectedDevice = microphones.firstWhereOrNull( + (i) => i.label == selected, + ); List items = [null, ...microphones]; @@ -319,16 +342,17 @@ class _VoipSettingsPage extends State { children: [ tiamat.Text.labelLow(label), tiamat.DropdownSelector( - items: items, - onItemSelected: onSelected, - itemBuilder: (item) { - if (item == null) { - return tiamat.Text.labelLow("No Default Selected"); - } else { - return tiamat.Text(item.label); - } - }, - value: selectedDevice), + items: items, + onItemSelected: onSelected, + itemBuilder: (item) { + if (item == null) { + return tiamat.Text.labelLow("No Default Selected"); + } else { + return tiamat.Text(item.label); + } + }, + value: selectedDevice, + ), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_turn_fallback_dialog.dart b/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_turn_fallback_dialog.dart index feaaf4bbe..50631b6f3 100644 --- a/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_turn_fallback_dialog.dart +++ b/commet/lib/ui/pages/settings/categories/app/voip_settings/voip_turn_fallback_dialog.dart @@ -24,18 +24,16 @@ class _VoipTurnFallbackDialogState extends State { mainAxisSize: MainAxisSize.min, children: [ Markdown( - padding: EdgeInsets.zero, - shrinkWrap: true, - data: - "Your homeserver `(${widget.homeserver})` is not configured to route calls. Would you like to fall back to a seperate server `(${preferences.fallbackTurnServer.value})` to handle routing?"), - const SizedBox( - height: 20, + padding: EdgeInsets.zero, + shrinkWrap: true, + data: + "Your homeserver `(${widget.homeserver})` is not configured to route calls. Would you like to fall back to a seperate server `(${preferences.fallbackTurnServer.value})` to handle routing?", ), + const SizedBox(height: 20), const tiamat.Text.labelLow( - "Without a server to route, calls cannot be connected. Your IP Address will be shared with the fallback server"), - const SizedBox( - height: 20, + "Without a server to route, calls cannot be connected. Your IP Address will be shared with the fallback server", ), + const SizedBox(height: 20), Row( children: [ Expanded( @@ -44,16 +42,15 @@ class _VoipTurnFallbackDialogState extends State { onTap: () => Navigator.of(context).pop(true), ), ), - const SizedBox( - width: 20, - ), + const SizedBox(width: 20), Expanded( child: tiamat.Button.secondary( - text: "Cancel call", - onTap: () => Navigator.of(context).pop(false)), + text: "Cancel call", + onTap: () => Navigator.of(context).pop(false), + ), ), ], - ) + ), ], ), ), diff --git a/commet/lib/ui/pages/settings/categories/app/window_settings.dart b/commet/lib/ui/pages/settings/categories/app/window_settings.dart index 4dbc00275..9cbb6ba83 100644 --- a/commet/lib/ui/pages/settings/categories/app/window_settings.dart +++ b/commet/lib/ui/pages/settings/categories/app/window_settings.dart @@ -13,20 +13,23 @@ class WindowSettingsPage extends StatefulWidget { } class _WindowSettingsPageState extends State { - String get labelSettingsWindowBehaviourTitle => - Intl.message("Window behaviour", - desc: "Header for the window behaviour section of settings", - name: "labelSettingsWindowBehaviourTitle"); - - String get labelSettingsMinimizeOnCloseToggle => - Intl.message("Minimize on close", - desc: "Label for the toggle to turn on and off minimize on close", - name: "labelSettingsMinimizeOnCloseToggle"); + String get labelSettingsWindowBehaviourTitle => Intl.message( + "Window behaviour", + desc: "Header for the window behaviour section of settings", + name: "labelSettingsWindowBehaviourTitle", + ); + + String get labelSettingsMinimizeOnCloseToggle => Intl.message( + "Minimize on close", + desc: "Label for the toggle to turn on and off minimize on close", + name: "labelSettingsMinimizeOnCloseToggle", + ); String get labelSettingsMinimizeOnCloseExplanation => Intl.message( - "When closing the window, the app will be minimized instead of exited", - desc: "Explains what the 'minimize on close' setting does", - name: "labelSettingsMinimizeOnCloseExplanation"); + "When closing the window, the app will be minimized instead of exited", + desc: "Explains what the 'minimize on close' setting does", + name: "labelSettingsMinimizeOnCloseExplanation", + ); @override void initState() { @@ -38,13 +41,15 @@ class _WindowSettingsPageState extends State { return Panel( header: labelSettingsWindowBehaviourTitle, mode: TileType.surfaceContainerLow, - child: Column(children: [ - BooleanPreferenceToggle( - preference: preferences.minimizeOnClose, - title: labelSettingsMinimizeOnCloseToggle, - description: labelSettingsMinimizeOnCloseExplanation, - ) - ]), + child: Column( + children: [ + BooleanPreferenceToggle( + preference: preferences.minimizeOnClose, + title: labelSettingsMinimizeOnCloseToggle, + description: labelSettingsMinimizeOnCloseExplanation, + ), + ], + ), ); } } diff --git a/commet/lib/ui/pages/settings/categories/developer/cumulative_diagnostics_widget.dart b/commet/lib/ui/pages/settings/categories/developer/cumulative_diagnostics_widget.dart index 8581f0491..667cb2ef1 100644 --- a/commet/lib/ui/pages/settings/categories/developer/cumulative_diagnostics_widget.dart +++ b/commet/lib/ui/pages/settings/categories/developer/cumulative_diagnostics_widget.dart @@ -20,9 +20,7 @@ class _CumulativeDiagnosticsWidgetState @override void initState() { measurements = widget.diagnostics.measurements.values.toList(); - measurements.sort( - (a, b) => b.totalDuration.compareTo(a.totalDuration), - ); + measurements.sort((a, b) => b.totalDuration.compareTo(a.totalDuration)); super.initState(); } @@ -30,41 +28,46 @@ class _CumulativeDiagnosticsWidgetState @override Widget build(BuildContext context) { return ExpansionTile( - title: tiamat.Text.labelEmphasised(widget.diagnostics.name), - initiallyExpanded: false, - backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, - children: measurements - .mapIndexed((e, i) => Container( - color: i % 2 == 0 - ? Theme.of(context).colorScheme.surfaceDim - : Theme.of(context).colorScheme.surfaceContainerHigh, - child: Padding( - padding: const EdgeInsets.fromLTRB(20, 2, 20, 2), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Padding( - padding: const EdgeInsets.fromLTRB(0, 2, 8, 2), - child: tiamat.Text.labelLow( - e.name, - color: Theme.of(context).colorScheme.onSurface, - ), - )), - tiamat.Text.labelLow( - [ - "${e.numCalls} calls", - "${(e.totalDuration.inMilliseconds / e.numCalls).round()}ms avg", - "${e.totalDuration.inMilliseconds}ms total", - ].join(" - "), - color: Theme.of(context).colorScheme.onSurfaceVariant, - ) - ], + title: tiamat.Text.labelEmphasised(widget.diagnostics.name), + initiallyExpanded: false, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, + children: measurements + .mapIndexed( + (e, i) => Container( + color: i % 2 == 0 + ? Theme.of(context).colorScheme.surfaceDim + : Theme.of(context).colorScheme.surfaceContainerHigh, + child: Padding( + padding: const EdgeInsets.fromLTRB(20, 2, 20, 2), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 2, 8, 2), + child: tiamat.Text.labelLow( + e.name, + color: Theme.of(context).colorScheme.onSurface, + ), + ), + ), + tiamat.Text.labelLow( + [ + "${e.numCalls} calls", + "${(e.totalDuration.inMilliseconds / e.numCalls).round()}ms avg", + "${e.totalDuration.inMilliseconds}ms total", + ].join(" - "), + color: Theme.of(context).colorScheme.onSurfaceVariant, ), - ), - )) - .toList()); + ], + ), + ), + ), + ) + .toList(), + ); } } diff --git a/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart b/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart index a3a9af2a7..bf471a8ea 100644 --- a/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; + import 'package:commet/client/components/push_notification/linux/linux_notifier.dart'; import 'package:commet/client/components/push_notification/notification_content.dart'; import 'package:commet/client/components/push_notification/notification_manager.dart'; @@ -40,84 +41,92 @@ class _DeveloperSettingsPageState extends State { @override Widget build(BuildContext context) { return Column( - children: [ - performance(), - benchmarks(), - windowSize(), - notificationTests(), - rendering(), - error(), - if (PlatformUtils.isAndroid) shortcuts(), - backgroundTasks(), - dumpDatabases(), - executeShellCommand(), - tiamat.Panel( - header: "Other Settings", - mode: TileType.surfaceContainerLow, - child: Column( - children: [ - if (!BuildConfig.MOBILE) - BooleanPreferenceToggle( - preference: preferences.disableTextCursorManagement, - title: "Disable Text Cursor Management", - description: - "As part of the implementaton for the rich text editor, we sometimes have to make automated changes to the text cursor. This disables that", + children: + [ + performance(), + benchmarks(), + windowSize(), + notificationTests(), + rendering(), + error(), + if (PlatformUtils.isAndroid) shortcuts(), + backgroundTasks(), + dumpDatabases(), + executeShellCommand(), + tiamat.Panel( + header: "Other Settings", + mode: TileType.surfaceContainerLow, + child: Column( + children: [ + if (!BuildConfig.MOBILE) + BooleanPreferenceToggle( + preference: preferences.disableTextCursorManagement, + title: "Disable Text Cursor Management", + description: "As part of the implementaton for the rich text editor, we sometimes have to make automated changes to the text cursor. This disables that", + ), + BooleanPreferenceToggle( + preference: preferences.useSharedIsolateInBackgroundTasks, + title: "Use shared database isolate in background", + ), + BooleanPreferenceToggle( + preference: preferences.debugTranslations, + title: "Debug Translations", + ), + BooleanPreferenceToggle( + preference: preferences.widgetDeveloperMode, + title: "Enable widget developer mode", + description: "Provides a debug view to log and inspect messages sent by widgets", + ), + DoublePreferenceSlider( + preference: preferences.customOnscreenKeyboardViewOffset, + title: "Keyboard Offset", + min: 0.0, + max: 1000, + description: "Amount to shift the app view up by when the onscreen keyboard is shown", + ), + ], ), - BooleanPreferenceToggle( - preference: preferences.useSharedIsolateInBackgroundTasks, - title: "Use shared database isolate in background"), - BooleanPreferenceToggle( - preference: preferences.debugTranslations, - title: "Debug Translations"), - BooleanPreferenceToggle( - preference: preferences.widgetDeveloperMode, - title: "Enable widget developer mode", - description: - "Provides a debug view to log and inspect messages sent by widgets", - ), - DoublePreferenceSlider( - preference: preferences.customOnscreenKeyboardViewOffset, - title: "Keyboard Offset", - min: 0.0, - max: 1000, - description: - "Amount to shift the app view up by when the onscreen keyboard is shown", ), - ], - ), - ) - ].map((e) { - return Padding( - padding: const EdgeInsets.fromLTRB(0, 3, 0, 3), - child: ClipRRect(borderRadius: BorderRadius.circular(10), child: e), - ); - }).toList()); + ].map((e) { + return Padding( + padding: const EdgeInsets.fromLTRB(0, 3, 0, 3), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: e, + ), + ); + }).toList(), + ); } Widget performance() { return ExpansionTile( - title: const tiamat.Text.labelEmphasised("Performance"), - initiallyExpanded: false, - backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, - children: [ - Diagnostics.general, - Diagnostics.initialLoadDatabaseDiagnostics, - Diagnostics.postLoadDatabaseDiagnostics, - ].map((e) => CumulativeDiagnosticsWidget(diagnostics: e)).toList()); + title: const tiamat.Text.labelEmphasised("Performance"), + initiallyExpanded: false, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, + children: [ + Diagnostics.general, + Diagnostics.initialLoadDatabaseDiagnostics, + Diagnostics.postLoadDatabaseDiagnostics, + ].map((e) => CumulativeDiagnosticsWidget(diagnostics: e)).toList(), + ); } Widget rendering() { return ExpansionTile( - title: const tiamat.Text.labelEmphasised("Rendering"), - backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Column(children: [ + title: const tiamat.Text.labelEmphasised("Rendering"), + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -136,108 +145,108 @@ class _DeveloperSettingsPageState extends State { preference: preferences.showPerformanceOverlay, title: "Show performance overlay", description: "Requires restart", - ) - ]), - ) - ]); + ), + ], + ), + ), + ], + ); } Widget benchmarks() { return ExpansionTile( - title: const tiamat.Text.labelEmphasised("Benchmarks"), - initiallyExpanded: false, - backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, - children: [ - Wrap( - spacing: 8, - runSpacing: 8, - children: [ - tiamat.Button( - text: "Timeline Viewer", - onTap: () => NavigationUtils.navigateTo( - context, const BenchmarkTimelineViewer()), + title: const tiamat.Text.labelEmphasised("Benchmarks"), + initiallyExpanded: false, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, + children: [ + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + tiamat.Button( + text: "Timeline Viewer", + onTap: () => NavigationUtils.navigateTo( + context, + const BenchmarkTimelineViewer(), ), - tiamat.Button( - text: "Notification Badges Stress Test", - onTap: () async { - for (int i = 0; i < 10000; i++) { - int v = i % 9; - (NotificationManager.notifier as LinuxNotifier?) - ?.service - .update(count: v, countVisible: v != 0); - - await Future.delayed(Duration(milliseconds: 100)); - - print("Notification Badge Stress Test: $i"); - } - }) - ], - ), - ]); + ), + tiamat.Button( + text: "Notification Badges Stress Test", + onTap: () async { + for (int i = 0; i < 10000; i++) { + int v = i % 9; + (NotificationManager.notifier as LinuxNotifier?)?.service + .update(count: v, countVisible: v != 0); + + await Future.delayed(Duration(milliseconds: 100)); + + print("Notification Badge Stress Test: $i"); + } + }, + ), + ], + ), + ], + ); } Widget windowSize() { return ExpansionTile( - title: const tiamat.Text.labelEmphasised("Window Size"), - initiallyExpanded: false, - backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, - children: [ - Wrap( - spacing: 8, - runSpacing: 8, - children: [ - tiamat.Button( - text: "Maximize", - onTap: () => windowManager.maximize(), - ), - tiamat.Button( - text: "1280x720", - onTap: () => windowManager.setSize(const Size(1280, 720)), - ), - tiamat.Button( - text: "1280x800 (Steamdeck)", - onTap: () => windowManager.setSize(const Size(1280, 800)), - ), - tiamat.Button( - text: "1920x1080", - onTap: () => windowManager.setSize(const Size(1920, 1080)), - ), - tiamat.Button( - text: "2560x1440", - onTap: () => windowManager.setSize(const Size(2560, 1440)), - ), - tiamat.Button( - text: "3840x2160", - onTap: () => windowManager.setSize(const Size(3840, 2160)), - ), - tiamat.Button( - text: "1170x2532 (iPhone 12 Pro)", - onTap: () => windowManager.setSize(const Size(1170, 2532)), - ), - ], - ), - const SizedBox( - height: 5, - ), - Wrap( - spacing: 8, - runSpacing: 8, - children: [ - tiamat.Button( - text: "1:1", - onTap: () => setAspectRatio(1), - ), - tiamat.Button( - text: "16:9", - onTap: () => setAspectRatio(16 / 9), - ), - ], - ) - ]); + title: const tiamat.Text.labelEmphasised("Window Size"), + initiallyExpanded: false, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, + children: [ + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + tiamat.Button( + text: "Maximize", + onTap: () => windowManager.maximize(), + ), + tiamat.Button( + text: "1280x720", + onTap: () => windowManager.setSize(const Size(1280, 720)), + ), + tiamat.Button( + text: "1280x800 (Steamdeck)", + onTap: () => windowManager.setSize(const Size(1280, 800)), + ), + tiamat.Button( + text: "1920x1080", + onTap: () => windowManager.setSize(const Size(1920, 1080)), + ), + tiamat.Button( + text: "2560x1440", + onTap: () => windowManager.setSize(const Size(2560, 1440)), + ), + tiamat.Button( + text: "3840x2160", + onTap: () => windowManager.setSize(const Size(3840, 2160)), + ), + tiamat.Button( + text: "1170x2532 (iPhone 12 Pro)", + onTap: () => windowManager.setSize(const Size(1170, 2532)), + ), + ], + ), + const SizedBox(height: 5), + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + tiamat.Button(text: "1:1", onTap: () => setAspectRatio(1)), + tiamat.Button(text: "16:9", onTap: () => setAspectRatio(16 / 9)), + ], + ), + ], + ); } void setAspectRatio(double ratio) async { @@ -248,30 +257,36 @@ class _DeveloperSettingsPageState extends State { Widget notificationTests() { return ExpansionTile( - title: const tiamat.Text.labelEmphasised("Notifications"), - backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, - children: [ - Wrap(spacing: 8, runSpacing: 8, children: [ + title: const tiamat.Text.labelEmphasised("Notifications"), + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, + children: [ + Wrap( + spacing: 8, + runSpacing: 8, + children: [ tiamat.Button( text: "Message Notification", onTap: () async { var client = clientManager!.clients.first; var room = client.rooms.first; var user = client.self!; - NotificationManager.notify(MessageNotificationContent( - senderName: user.displayName, - senderImage: user.avatar, - senderId: user.identifier, - roomName: room.displayName, - roomId: room.identifier, - roomImage: await room.getShortcutImage(), - content: "Test Message!", - clientId: client.identifier, - eventId: "fake_event_id", - isDirectMessage: true, - )); + NotificationManager.notify( + MessageNotificationContent( + senderName: user.displayName, + senderImage: user.avatar, + senderId: user.identifier, + roomName: room.displayName, + roomId: room.identifier, + roomImage: await room.getShortcutImage(), + content: "Test Message!", + clientId: client.identifier, + eventId: "fake_event_id", + isDirectMessage: true, + ), + ); }, ), tiamat.Button( @@ -284,41 +299,50 @@ class _DeveloperSettingsPageState extends State { var client = clientManager!.clients.first; var room = client.rooms.first; var user = client.self!; - NotificationManager.notify(CallNotificationContent( - title: "Incoming Call!", - senderImage: user.avatar, - senderId: user.identifier, - roomName: room.displayName, - roomId: room.identifier, - senderName: user.displayName, - senderImageId: "fake_call_avatar_id", - roomImage: await room.getShortcutImage(), - content: "Test Call Notification", - clientId: client.identifier, - callId: "fake_call_id", - isDirectMessage: true, - )); + NotificationManager.notify( + CallNotificationContent( + title: "Incoming Call!", + senderImage: user.avatar, + senderId: user.identifier, + roomName: room.displayName, + roomId: room.identifier, + senderName: user.displayName, + senderImageId: "fake_call_avatar_id", + roomImage: await room.getShortcutImage(), + content: "Test Call Notification", + clientId: client.identifier, + callId: "fake_call_id", + isDirectMessage: true, + ), + ); }, ), - ]) - ]); + ], + ), + ], + ); } Widget shortcuts() { return ExpansionTile( title: const tiamat.Text.labelEmphasised("Shortcuts"), backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, children: [ - Wrap(spacing: 8, runSpacing: 8, children: [ - tiamat.Button( - text: "Clear Shortcuts", - onTap: () async { - await shortcutsManager.clearAllShortcuts(); - }, - ), - ]) + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + tiamat.Button( + text: "Clear Shortcuts", + onTap: () async { + await shortcutsManager.clearAllShortcuts(); + }, + ), + ], + ), ], ); } @@ -327,24 +351,35 @@ class _DeveloperSettingsPageState extends State { return ExpansionTile( title: const tiamat.Text.labelEmphasised("Background Tasks"), backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, children: [ - Wrap(spacing: 8, runSpacing: 8, children: [ - tiamat.Button( + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + tiamat.Button( text: "With progress", - onTap: () => backgroundTaskManager - .addTask(FakeBackgroundTaskWithProgress())), - tiamat.Button( + onTap: () => backgroundTaskManager.addTask( + FakeBackgroundTaskWithProgress(), + ), + ), + tiamat.Button( text: "Indeterminate", - onTap: () => backgroundTaskManager.addTask(FakeBackgroundTask())), - tiamat.Button( + onTap: () => backgroundTaskManager.addTask(FakeBackgroundTask()), + ), + tiamat.Button( text: "Async task with crash", - onTap: () => backgroundTaskManager.addTask(AsyncTask(() async { - await Future.delayed(const Duration(seconds: 5)); - throw Exception("This background task failed!"); - }, "Async task"))), - ]) + onTap: () => backgroundTaskManager.addTask( + AsyncTask(() async { + await Future.delayed(const Duration(seconds: 5)); + throw Exception("This background task failed!"); + }, "Async task"), + ), + ), + ], + ), ], ); } @@ -353,23 +388,30 @@ class _DeveloperSettingsPageState extends State { return ExpansionTile( title: const tiamat.Text.labelEmphasised("Error"), backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, children: [ - Wrap(spacing: 8, runSpacing: 8, children: [ - tiamat.Button( + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + tiamat.Button( text: "Throw an error", onTap: () { // This should also throw an error! String? empty; empty!.split(" "); - }), - tiamat.Button( + }, + ), + tiamat.Button( text: "Print Something", onTap: () { print("Hello, world!"); - }), - ]) + }, + ), + ], + ), ], ); } @@ -378,11 +420,15 @@ class _DeveloperSettingsPageState extends State { return ExpansionTile( title: const tiamat.Text.labelEmphasised("Dangerous"), backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, children: [ - Wrap(spacing: 8, runSpacing: 8, children: [ - tiamat.Button( + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + tiamat.Button( text: "Launch Widget Runner", onTap: () async { var exe = Platform.resolvedExecutable; @@ -390,18 +436,18 @@ class _DeveloperSettingsPageState extends State { var process = await Process.start(exe, [ '--widget_runner', '--title="commet | Widget Runner"', - '--url=${"https://commet.chat"}' + '--url=${"https://commet.chat"}', ]); process.exitCode.then((i) { Log.i("Subprocess exited: $i"); }); - AdaptiveDialog.show(context, - builder: (context) => ProcessOutputViewer( - process, - showStdErr: true, - )).then((_) { + AdaptiveDialog.show( + context, + builder: (context) => + ProcessOutputViewer(process, showStdErr: true), + ).then((_) { process.kill(ProcessSignal.sigkill); }); @@ -412,34 +458,40 @@ class _DeveloperSettingsPageState extends State { await Future.delayed(Duration(seconds: 5)); } - }), - tiamat.Button( + }, + ), + tiamat.Button( text: "Launch Overlay", onTap: () async { var client = clientManager!.clients.first; VoipOverlay.spawn(client, client.rooms.first, context); - }), - tiamat.Button( - text: "Get Process List", - onTap: () async { - var list = await SystemProcessesUtils.getProcessList(); - AdaptiveDialog.show( - context, - builder: (context) { - return Codeblock( + }, + ), + tiamat.Button( + text: "Get Process List", + onTap: () async { + var list = await SystemProcessesUtils.getProcessList(); + AdaptiveDialog.show( + context, + builder: (context) { + return Codeblock( text: list - .map((i) => - "[${i.processId}] = ${i.command} ${i.args}") - .join("\n")); - }, - ); - }, - ), - tiamat.Button( + .map( + (i) => "[${i.processId}] = ${i.command} ${i.args}", + ) + .join("\n"), + ); + }, + ); + }, + ), + tiamat.Button( text: "Execute Shell Command", onTap: () async { - var text = await AdaptiveDialog.textPrompt(context, - title: "Execute Shell Command"); + var text = await AdaptiveDialog.textPrompt( + context, + title: "Execute Shell Command", + ); if (text != null) { var command = text.split(" "); var exe = command.first; @@ -447,11 +499,15 @@ class _DeveloperSettingsPageState extends State { var process = await Process.start(exe, args); - AdaptiveDialog.show(context, - builder: (context) => ProcessOutputViewer(process)); + AdaptiveDialog.show( + context, + builder: (context) => ProcessOutputViewer(process), + ); } - }), - ]) + }, + ), + ], + ), ], ); } @@ -460,11 +516,15 @@ class _DeveloperSettingsPageState extends State { return ExpansionTile( title: const tiamat.Text.labelEmphasised("Dump Databases"), backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, children: [ - Wrap(spacing: 8, runSpacing: 8, children: [ - tiamat.Button( + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + tiamat.Button( text: "Dump Databases", onTap: () async { var folder = await FilePicker.platform.getDirectoryPath(); @@ -487,16 +547,22 @@ class _DeveloperSettingsPageState extends State { var newFile = p.join(folder, dirname, name); (file as File).copy(newFile); } - }), - ]) + }, + ), + ], + ), ], ); } } class ProcessOutputViewer extends StatefulWidget { - const ProcessOutputViewer(this.process, - {super.key, this.showStdErr = false, this.showStdOut = true}); + const ProcessOutputViewer( + this.process, { + super.key, + this.showStdErr = false, + this.showStdOut = true, + }); final Process process; final bool showStdErr; final bool showStdOut; diff --git a/commet/lib/ui/pages/settings/categories/developer/log_page.dart b/commet/lib/ui/pages/settings/categories/developer/log_page.dart index 7da89897c..dd4d4c994 100644 --- a/commet/lib/ui/pages/settings/categories/developer/log_page.dart +++ b/commet/lib/ui/pages/settings/categories/developer/log_page.dart @@ -101,10 +101,15 @@ class _LogPageState extends State { child: InkWell( child: DecoratedBox( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), color: background), + borderRadius: BorderRadius.circular(5), + color: background, + ), child: InkWell( - onTap: () => AdaptiveDialog.show(context, - builder: (context) => logDetail(entry), title: entry.type.name), + onTap: () => AdaptiveDialog.show( + context, + builder: (context) => logDetail(entry), + title: entry.type.name, + ), child: Padding( padding: const EdgeInsets.fromLTRB(8, 4, 8, 4), child: Column( @@ -119,21 +124,19 @@ class _LogPageState extends State { ), Padding( padding: const EdgeInsets.all(2.0), - child: Icon( - icon, - size: 15, - color: color, - ), + child: Icon(icon, size: 15, color: color), ), tiamat.Text.labelLow(entry.type.name), const SizedBox(width: 10, child: tiamat.Seperator()), tiamat.Text.labelLow( - DateFormat(DateFormat.HOUR_MINUTE_SECOND) - .format(entry.time.toLocal())), + DateFormat(DateFormat.HOUR_MINUTE_SECOND) + .format(entry.time.toLocal()), + ), ], ), Text.rich( - TextSpan(children: buildAnsiStyledTest(entry.content))) + TextSpan(children: buildAnsiStyledTest(entry.content)), + ), ], ), ), @@ -157,10 +160,15 @@ class _LogPageState extends State { spans.add(TextSpan(text: sub, style: style)); style = entry.value; style = style.copyWith( - color: style.color != null - ? tiamat.Text.adjustColor(context, style.color!, - maxLightnessOnLight: 0.5, saturationMultiplier: 0.7) - : null); + color: style.color != null + ? tiamat.Text.adjustColor( + context, + style.color!, + maxLightnessOnLight: 0.5, + saturationMultiplier: 0.7, + ) + : null, + ); break; } } diff --git a/commet/lib/ui/pages/settings/categories/room/appearance/room_appearance_settings_view.dart b/commet/lib/ui/pages/settings/categories/room/appearance/room_appearance_settings_view.dart index e9eb0fb6f..8c95e74e4 100644 --- a/commet/lib/ui/pages/settings/categories/room/appearance/room_appearance_settings_view.dart +++ b/commet/lib/ui/pages/settings/categories/room/appearance/room_appearance_settings_view.dart @@ -15,20 +15,21 @@ import 'package:tiamat/config/style/theme_extensions.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class RoomAppearanceSettingsView extends StatefulWidget { - const RoomAppearanceSettingsView( - {required this.avatar, - required this.displayName, - required this.identifier, - required this.color, - required this.client, - this.onImagePicked, - this.onNameChanged, - this.topic, - this.setTopic, - this.canEditName = false, - this.canEditTopic = false, - this.canEditAvatar = false, - super.key}); + const RoomAppearanceSettingsView({ + required this.avatar, + required this.displayName, + required this.identifier, + required this.color, + required this.client, + this.onImagePicked, + this.onNameChanged, + this.topic, + this.setTopic, + this.canEditName = false, + this.canEditTopic = false, + this.canEditAvatar = false, + super.key, + }); final ImageProvider? avatar; final Client client; final String displayName; @@ -99,40 +100,44 @@ class _RoomAppearanceSettingsViewState clipBehavior: Clip.antiAlias, color: ColorScheme.of(context).surfaceContainer, child: InkWell( - onTap: widget.canEditTopic ? editTopic : null, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: MarkdownBody( - imageBuilder: (uri, title, alt) { - if (uri.scheme == "mxc" && - widget.client is MatrixClient) { - return SizedBox( - height: 50, - child: Image( - image: MatrixMxcImage( - doFullres: true, - doThumbnail: false, - autoLoadFullRes: true, - uri, - (widget.client as MatrixClient) - .matrixClient)), - ); - } + onTap: widget.canEditTopic ? editTopic : null, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: MarkdownBody( + imageBuilder: (uri, title, alt) { + if (uri.scheme == "mxc" && widget.client is MatrixClient) { + return SizedBox( + height: 50, + child: Image( + image: MatrixMxcImage( + doFullres: true, + doThumbnail: false, + autoLoadFullRes: true, + uri, + (widget.client as MatrixClient).matrixClient, + ), + ), + ); + } - return Container(); - }, - styleSheet: MarkdownStyleSheet( - a: TextTheme.of(context).bodyMedium?.copyWith( - color: Theme.of(context) - .extension() - ?.linkColor)), - onTapLink: (text, href, title) { - if (href != null) { - LinkUtils.open(Uri.parse(href), context: context); - } - }, - data: topic?.isNotEmpty == true ? topic! : "Set a topic"), - )), + return Container(); + }, + styleSheet: MarkdownStyleSheet( + a: TextTheme.of(context).bodyMedium?.copyWith( + color: Theme.of(context) + .extension() + ?.linkColor, + ), + ), + onTapLink: (text, href, title) { + if (href != null) { + LinkUtils.open(Uri.parse(href), context: context); + } + }, + data: topic?.isNotEmpty == true ? topic! : "Set a topic", + ), + ), + ), ), ], ); @@ -157,8 +162,12 @@ class _RoomAppearanceSettingsViewState } void editTopic() async { - var newTopic = await AdaptiveDialog.textPrompt(context, - multiline: true, title: "Set Topic", initialText: topic); + var newTopic = await AdaptiveDialog.textPrompt( + context, + multiline: true, + title: "Set Topic", + initialText: topic, + ); if (newTopic != null) { ErrorUtils.tryRun(context, () async { diff --git a/commet/lib/ui/pages/settings/categories/room/calendar/add_calendar_dialog.dart b/commet/lib/ui/pages/settings/categories/room/calendar/add_calendar_dialog.dart index bb2a1d1f0..40bdce88c 100644 --- a/commet/lib/ui/pages/settings/categories/room/calendar/add_calendar_dialog.dart +++ b/commet/lib/ui/pages/settings/categories/room/calendar/add_calendar_dialog.dart @@ -62,11 +62,13 @@ class _AddRemoteCalendarDialogState extends State { decoration: InputDecoration(labelText: "Calendar Url"), ), TextFormField( - onChanged: (value) => setState(() { - eventName = value; - }), - decoration: InputDecoration( - labelText: "Event Name Override (Optional)")), + onChanged: (value) => setState(() { + eventName = value; + }), + decoration: InputDecoration( + labelText: "Event Name Override (Optional)", + ), + ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -80,11 +82,13 @@ class _AddRemoteCalendarDialogState extends State { showSelectedIcon: false, segments: [ ButtonSegment( - value: CalendarSyncType.events, - label: Text("Events")), + value: CalendarSyncType.events, + label: Text("Events"), + ), ButtonSegment( - value: CalendarSyncType.unavailability, - label: Text("Unavailability")), + value: CalendarSyncType.unavailability, + label: Text("Unavailability"), + ), ], expandedInsets: EdgeInsets.all(0), selected: {eventType}, @@ -96,10 +100,10 @@ class _AddRemoteCalendarDialogState extends State { ), if (events != null && events!.isNotEmpty) Center( - child: - tiamat.Text.labelLow("Found ${events!.length} events")), + child: tiamat.Text.labelLow("Found ${events!.length} events"), + ), if (loading) Center(child: CircularProgressIndicator()), - if (error != null) tiamat.Text.error(error!) + if (error != null) tiamat.Text.error(error!), ], ), tiamat.Button( @@ -109,13 +113,18 @@ class _AddRemoteCalendarDialogState extends State { loading = true; }); - await widget.component.addSyncedCalendar(SyncedCalendar( - url, CalendarSource.ical, eventType, - overrideEventName: eventName.isNotEmpty ? eventName : null)); + await widget.component.addSyncedCalendar( + SyncedCalendar( + url, + CalendarSource.ical, + eventType, + overrideEventName: eventName.isNotEmpty ? eventName : null, + ), + ); Navigator.of(context).pop(); }, - ) + ), ], ), ); diff --git a/commet/lib/ui/pages/settings/categories/room/calendar/room_calendar_settings_page.dart b/commet/lib/ui/pages/settings/categories/room/calendar/room_calendar_settings_page.dart index 1117b5bfd..c4f6ae282 100644 --- a/commet/lib/ui/pages/settings/categories/room/calendar/room_calendar_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/room/calendar/room_calendar_settings_page.dart @@ -78,8 +78,9 @@ class _RoomCalendarSettingsPageState extends State { ), Padding( padding: const EdgeInsets.all(8.0), - child: - buildSyncEntry(syncedCalendarUrls[remoteCalendarId]!), + child: buildSyncEntry( + syncedCalendarUrls[remoteCalendarId]!, + ), ), ], ), @@ -97,45 +98,49 @@ class _RoomCalendarSettingsPageState extends State { width: 50, child: tiamat.IconButton( icon: Icons.add, - onPressed: () => AdaptiveDialog.pickOne( - context, - title: "Sync Calendar Source", - items: [ - // CalendarSource.room, - CalendarSource.ical, - ], - itemBuilder: (context, item, callback) { - var text = switch (item) { - CalendarSource.ical => "Calendar Url", - CalendarSource.room => "Room", - }; + onPressed: () => + AdaptiveDialog.pickOne( + context, + title: "Sync Calendar Source", + items: [ + // CalendarSource.room, + CalendarSource.ical, + ], + itemBuilder: (context, item, callback) { + var text = switch (item) { + CalendarSource.ical => "Calendar Url", + CalendarSource.room => "Room", + }; - var icon = switch (item) { - CalendarSource.ical => Icons.calendar_month, - CalendarSource.room => Icons.tag, - }; - return SizedBox( - height: 50, - child: tiamat.TextButton( - text, - icon: icon, - onTap: callback, - ), - ); - }, - ).then((type) { - switch (type) { - case CalendarSource.ical: - AdaptiveDialog.show(context, - builder: (context) => AddRemoteCalendarDialog( - widget.calendarComponent)); - case CalendarSource.room: - // TODO: Handle this case. - throw UnimplementedError(); - case _: - break; - } - }), + var icon = switch (item) { + CalendarSource.ical => Icons.calendar_month, + CalendarSource.room => Icons.tag, + }; + return SizedBox( + height: 50, + child: tiamat.TextButton( + text, + icon: icon, + onTap: callback, + ), + ); + }, + ).then((type) { + switch (type) { + case CalendarSource.ical: + AdaptiveDialog.show( + context, + builder: (context) => AddRemoteCalendarDialog( + widget.calendarComponent, + ), + ); + case CalendarSource.room: + // TODO: Handle this case. + throw UnimplementedError(); + case _: + break; + } + }), ), ), if (syncedCalendarUrls.isNotEmpty) @@ -175,28 +180,30 @@ class _RoomCalendarSettingsPageState extends State { }; var entryStyle = Theme.of(context).textTheme.bodyMedium!.copyWith( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.w400, - fontSize: 12, - ); + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.w400, + fontSize: 12, + ); return RichText( - text: TextSpan(children: [ - TextSpan(text: description), - TextSpan(text: " as ", style: entryStyle), - TextSpan( - text: switch (calendar.syncType) { - CalendarSyncType.events => "Events", - CalendarSyncType.unavailability => "Unavailability", - }, - ), - if (calendar.overrideEventName != null) - TextSpan(text: " with name ", style: entryStyle), - if (calendar.overrideEventName != null) - TextSpan(text: "'${calendar.overrideEventName!}'"), - if (preferences.developerMode.value) - TextSpan(text: " (${calendar.id})", style: entryStyle) - ]), + text: TextSpan( + children: [ + TextSpan(text: description), + TextSpan(text: " as ", style: entryStyle), + TextSpan( + text: switch (calendar.syncType) { + CalendarSyncType.events => "Events", + CalendarSyncType.unavailability => "Unavailability", + }, + ), + if (calendar.overrideEventName != null) + TextSpan(text: " with name ", style: entryStyle), + if (calendar.overrideEventName != null) + TextSpan(text: "'${calendar.overrideEventName!}'"), + if (preferences.developerMode.value) + TextSpan(text: " (${calendar.id})", style: entryStyle), + ], + ), ); } } diff --git a/commet/lib/ui/pages/settings/categories/room/developer/room_developer_settings_view.dart b/commet/lib/ui/pages/settings/categories/room/developer/room_developer_settings_view.dart index a296c635b..1005fb73f 100644 --- a/commet/lib/ui/pages/settings/categories/room/developer/room_developer_settings_view.dart +++ b/commet/lib/ui/pages/settings/categories/room/developer/room_developer_settings_view.dart @@ -11,28 +11,28 @@ class RoomDeveloperSettingsView extends StatelessWidget { @override Widget build(BuildContext context) { return Column( - children: - [jsonDump(context), notificationTests(context)].map((e) { - return Padding( - padding: const EdgeInsets.fromLTRB(0, 3, 0, 3), - child: ClipRRect(borderRadius: BorderRadius.circular(10), child: e), - ); - }).toList()); + children: [jsonDump(context), notificationTests(context)].map(( + e, + ) { + return Padding( + padding: const EdgeInsets.fromLTRB(0, 3, 0, 3), + child: ClipRRect(borderRadius: BorderRadius.circular(10), child: e), + ); + }).toList(), + ); } Widget jsonDump(BuildContext context) { return ExpansionTile( title: const tiamat.Text.labelEmphasised("Room State"), backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, children: [ SelectionArea( - child: Codeblock( - language: "json", - text: room.developerInfo, - ), - ) + child: Codeblock(language: "json", text: room.developerInfo), + ), ], ); } @@ -41,19 +41,24 @@ class RoomDeveloperSettingsView extends StatelessWidget { return ExpansionTile( title: const tiamat.Text.labelEmphasised("Shortcuts"), backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, children: [ - Wrap(spacing: 8, runSpacing: 8, children: [ - tiamat.Button( - text: "Register Shortcut", - onTap: () => shortcutsManager.createShortcutForRoom(room), - ), - tiamat.Button( - text: "Clear All Shortcuts", - onTap: () => shortcutsManager.clearAllShortcuts(), - ), - ]) + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + tiamat.Button( + text: "Register Shortcut", + onTap: () => shortcutsManager.createShortcutForRoom(room), + ), + tiamat.Button( + text: "Clear All Shortcuts", + onTap: () => shortcutsManager.clearAllShortcuts(), + ), + ], + ), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/room/emoji_packs/bulk_import_view.dart b/commet/lib/ui/pages/settings/categories/room/emoji_packs/bulk_import_view.dart index 01561a422..513be13e1 100644 --- a/commet/lib/ui/pages/settings/categories/room/emoji_packs/bulk_import_view.dart +++ b/commet/lib/ui/pages/settings/categories/room/emoji_packs/bulk_import_view.dart @@ -16,8 +16,13 @@ import 'package:tiamat/tiamat.dart' as tiamat; class EmoticonBulkImportDialog extends StatefulWidget { const EmoticonBulkImportDialog({super.key, this.importPack}); - final Function(String name, int avatarIndex, List names, - List imageDatas)? importPack; + final Function( + String name, + int avatarIndex, + List names, + List imageDatas, + )? + importPack; @override State createState() => @@ -132,17 +137,21 @@ class _EmoticonBulkImportDialogState extends State { Future loadSignalPack(Uri uri) async { var client = SignalStickerClient( - host: preferences.proxyUrl.value, rootPath: "/proxy/signal"); + host: preferences.proxyUrl.value, + rootPath: "/proxy/signal", + ); var packInfo = client.getPackFromUri(uri); var pack = await client.getPack(packInfo!); _packNameEditor.text = pack!.name; - names = ensureNoConflictingNames(pack.stickers - .map((e) => e.emoji) - .toList() - .map((e) => UnicodeEmojis.findShortcode(e)!) - .toList()); + names = ensureNoConflictingNames( + pack.stickers + .map((e) => e.emoji) + .toList() + .map((e) => UnicodeEmojis.findShortcode(e)!) + .toList(), + ); datas = List.generate(names!.length, (index) => null); images = List.generate(names!.length, (index) => null); @@ -173,15 +182,19 @@ class _EmoticonBulkImportDialogState extends State { } Future pickFolder() async { - var files = await FilePicker.platform - .pickFiles(type: FileType.image, withData: true, allowMultiple: true); + var files = await FilePicker.platform.pickFiles( + type: FileType.image, + withData: true, + allowMultiple: true, + ); setState(() { reset(); datas = files!.files.map((e) => e.bytes!).toList(); images = files.files.map((e) => Image.memory(e.bytes!).image).toList(); - names = - files.files.map((e) => p.basenameWithoutExtension(e.name)).toList(); + names = files.files + .map((e) => p.basenameWithoutExtension(e.name)) + .toList(); avatarIndex = 0; _controller.text = ""; }); @@ -189,10 +202,7 @@ class _EmoticonBulkImportDialogState extends State { @override Widget build(BuildContext context) { - bool loadingFinished = images?.any( - (element) => element == null, - ) == - false; + bool loadingFinished = images?.any((element) => element == null) == false; return ConstrainedBox( constraints: const BoxConstraints.expand(width: 800, height: 800), child: Column( @@ -201,11 +211,7 @@ class _EmoticonBulkImportDialogState extends State { children: [ sourceSelection(), if (loading) - const Expanded( - child: Center( - child: CircularProgressIndicator(), - ), - ), + const Expanded(child: Center(child: CircularProgressIndicator())), if (loading == false && names != null) Flexible( child: Padding( @@ -213,11 +219,12 @@ class _EmoticonBulkImportDialogState extends State { child: ClipRRect( borderRadius: BorderRadius.circular(10), child: MasonryGridView.extent( - itemCount: names!.length, - maxCrossAxisExtent: 200, - mainAxisSpacing: 8, - crossAxisSpacing: 8, - itemBuilder: entryBuilder), + itemCount: names!.length, + maxCrossAxisExtent: 200, + mainAxisSpacing: 8, + crossAxisSpacing: 8, + itemBuilder: entryBuilder, + ), ), ), ), @@ -230,14 +237,19 @@ class _EmoticonBulkImportDialogState extends State { text: "Import ${names!.length} Emoticons!", onTap: () { if (canCreatePack()) { - var finalNames = - names!.mapIndexed((e, i) => getFinalName(i)).toList(); - widget.importPack?.call(_packNameEditor.text, avatarIndex!, - finalNames, datas!.map((e) => e!).toList()); + var finalNames = names! + .mapIndexed((e, i) => getFinalName(i)) + .toList(); + widget.importPack?.call( + _packNameEditor.text, + avatarIndex!, + finalNames, + datas!.map((e) => e!).toList(), + ); } }, ), - ) + ), ], ), ); @@ -258,13 +270,8 @@ class _EmoticonBulkImportDialogState extends State { Padding( padding: const EdgeInsets.all(8), child: avatarIndex != null && images?[avatarIndex!] != null - ? tiamat.Avatar( - image: images![avatarIndex!], - radius: 50, - ) - : const Center( - child: CircularProgressIndicator(), - ), + ? tiamat.Avatar(image: images![avatarIndex!], radius: 50) + : const Center(child: CircularProgressIndicator()), ), Flexible( child: Column( @@ -289,9 +296,7 @@ class _EmoticonBulkImportDialogState extends State { maxLines: 1, ), ), - const SizedBox( - width: 10, - ), + const SizedBox(width: 10), Flexible( child: tiamat.TextInput( controller: _overrideNameEditor, @@ -312,53 +317,52 @@ class _EmoticonBulkImportDialogState extends State { Widget sourceSelection() { return Panel( - header: "Select pack source", - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - tiamat.TextInput( - placeholder: "Enter URL", - controller: _controller, - maxLines: 1, - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + header: "Select pack source", + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + tiamat.TextInput( + placeholder: "Enter URL", + controller: _controller, + maxLines: 1, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Flexible( + child: tiamat.Text.labelLow("Supports: sgnl:// and signal.art"), + ), + Flexible( + child: tiamat.Text.labelLow( + "Request will be proxied via ${preferences.proxyUrl.value}", + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - const Flexible( - child: tiamat.Text.labelLow( - "Supports: sgnl:// and signal.art")), - Flexible( - child: tiamat.Text.labelLow( - "Request will be proxied via ${preferences.proxyUrl.value}"), + const SizedBox( + width: 100, + height: 10, + child: tiamat.Seperator(), + ), + tiamat.Text.labelLow(CommonStrings.labelOr), + const SizedBox( + width: 100, + height: 10, + child: tiamat.Seperator(), ), ], ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox( - width: 100, - height: 10, - child: tiamat.Seperator(), - ), - tiamat.Text.labelLow(CommonStrings.labelOr), - const SizedBox( - width: 100, - height: 10, - child: tiamat.Seperator(), - ), - ], - ), - ), - tiamat.Button( - text: "Select Files", - onTap: pickFolder, - ), - ], - )); + ), + tiamat.Button(text: "Select Files", onTap: pickFolder), + ], + ), + ); } Widget entryBuilder(BuildContext context, int index) { @@ -370,7 +374,9 @@ class _EmoticonBulkImportDialogState extends State { return DecoratedBox( decoration: BoxDecoration( - color: background, borderRadius: BorderRadius.circular(5)), + color: background, + borderRadius: BorderRadius.circular(5), + ), child: ClipRRect( borderRadius: BorderRadius.circular(5), child: ConstrainedBox( @@ -383,13 +389,14 @@ class _EmoticonBulkImportDialogState extends State { fit: BoxFit.fill, image: images![index]!, ), - tiamat.Text.tiny(getFinalName(index)) + tiamat.Text.tiny(getFinalName(index)), ], ) : const SizedBox( width: 15, height: 15, - child: Center(child: CircularProgressIndicator())), + child: Center(child: CircularProgressIndicator()), + ), ), ), ); diff --git a/commet/lib/ui/pages/settings/categories/room/emoji_packs/room_emoji_pack_settings_view.dart b/commet/lib/ui/pages/settings/categories/room/emoji_packs/room_emoji_pack_settings_view.dart index c7bbf6e2f..53a62e7b9 100644 --- a/commet/lib/ui/pages/settings/categories/room/emoji_packs/room_emoji_pack_settings_view.dart +++ b/commet/lib/ui/pages/settings/categories/room/emoji_packs/room_emoji_pack_settings_view.dart @@ -14,8 +14,11 @@ import 'package:tiamat/tiamat.dart' as tiamat; import 'package:path/path.dart' as path; class RoomEmojiPackSettingsView extends StatefulWidget { - const RoomEmojiPackSettingsView( - {required this.component, this.editable = true, super.key}); + const RoomEmojiPackSettingsView({ + required this.component, + this.editable = true, + super.key, + }); final EmoticonComponent component; final bool editable; @override @@ -29,9 +32,11 @@ class _RoomEmojiPackSettingsViewState extends State { StreamSubscription? sub; bool canCreatePack = false; - String get promptImportPack => Intl.message("Import pack", - name: "promptImportPack", - desc: "Prompt to import a set of emoticons from an existing pack"); + String get promptImportPack => Intl.message( + "Import pack", + name: "promptImportPack", + desc: "Prompt to import a set of emoticons from an existing pack", + ); @override void initState() { @@ -62,8 +67,12 @@ class _RoomEmojiPackSettingsViewState extends State { builder: (context) { return EmoticonBulkImportDialog( importPack: (name, avatarIndex, names, imageDatas) { - widget.component - .importEmoticonPack(name, avatarIndex, names, imageDatas); + widget.component.importEmoticonPack( + name, + avatarIndex, + names, + imageDatas, + ); Navigator.pop(context); }, ); @@ -81,10 +90,12 @@ class _RoomEmojiPackSettingsViewState extends State { (e) => Padding( padding: const EdgeInsets.fromLTRB(0, 2, 0, 2), child: ExpansionTile( - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainer, - backgroundColor: - Theme.of(context).colorScheme.surfaceContainer, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainer, + backgroundColor: Theme.of(context) + .colorScheme + .surfaceContainer, title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -94,9 +105,10 @@ class _RoomEmojiPackSettingsViewState extends State { Padding( padding: const EdgeInsets.fromLTRB(0, 0, 8, 0), child: SizedBox( - width: 40, - height: 40, - child: Image(image: e.image!)), + width: 40, + height: 40, + child: Image(image: e.image!), + ), ), tiamat.Text.label(e.displayName), ], @@ -107,40 +119,44 @@ class _RoomEmojiPackSettingsViewState extends State { children: [ if (widget.editable) tiamat.IconButton( - size: 20, - icon: Icons.edit, - onPressed: () => AdaptiveDialog.show( - context, - builder: (context) => EmoticonCreator( - pack: e, - createPack: true, - onCreate: (name, usage, - newImageData) async { - await e.updatePack( - name: name, - usage: usage, - imageData: newImageData, - ); - return true; - }, - onDelete: () { - return widget.component - .deleteEmoticonPack(e); - }, - ))), + size: 20, + icon: Icons.edit, + onPressed: () => AdaptiveDialog.show( + context, + builder: (context) => EmoticonCreator( + pack: e, + createPack: true, + onCreate: + (name, usage, newImageData) async { + await e.updatePack( + name: name, + usage: usage, + imageData: newImageData, + ); + return true; + }, + onDelete: () { + return widget.component + .deleteEmoticonPack(e); + }, + ), + ), + ), if (e.isEmojiPack) Icon( - color: Theme.of(context) - .colorScheme - .secondaryContainer, - size: 20, - Icons.emoji_emotions), + color: Theme.of(context) + .colorScheme + .secondaryContainer, + size: 20, + Icons.emoji_emotions, + ), if (e.isStickerPack) Icon( - color: Theme.of(context) - .colorScheme - .secondaryContainer, - Icons.sticky_note_2_rounded), + color: Theme.of(context) + .colorScheme + .secondaryContainer, + Icons.sticky_note_2_rounded, + ), tiamat.IconToggle( icon: Icons.favorite, size: 17, @@ -153,7 +169,7 @@ class _RoomEmojiPackSettingsViewState extends State { ], ), ], - ) + ), ], ), children: [ @@ -163,7 +179,7 @@ class _RoomEmojiPackSettingsViewState extends State { pack: e, editable: widget.editable, ), - ) + ), ], ), ), @@ -177,47 +193,57 @@ class _RoomEmojiPackSettingsViewState extends State { mainAxisSize: MainAxisSize.min, children: [ tiamat.CircleButton( - icon: Icons.auto_awesome_motion, - onPressed: promptBulkImport), - const SizedBox( - width: 10, + icon: Icons.auto_awesome_motion, + onPressed: promptBulkImport, ), + const SizedBox(width: 10), tiamat.CircleButton( - icon: Icons.add, - onPressed: () => AdaptiveDialog.show(context, - builder: (context) => EmoticonCreator( - createPack: true, - creatingNew: true, - onCreate: (name, usage, newImageData) async { - await widget.component - .createEmoticonPack(name, newImageData); - - return true; - }, - ))), + icon: Icons.add, + onPressed: () => AdaptiveDialog.show( + context, + builder: (context) => EmoticonCreator( + createPack: true, + creatingNew: true, + onCreate: (name, usage, newImageData) async { + await widget.component.createEmoticonPack( + name, + newImageData, + ); + + return true; + }, + ), + ), + ), ], ), - ) + ), ], ); } } class EmoticonPackEditor extends StatelessWidget { - const EmoticonPackEditor( - {required this.pack, this.editable = false, super.key}); + const EmoticonPackEditor({ + required this.pack, + this.editable = false, + super.key, + }); final EmoticonPack pack; final bool editable; - String get createEmoticonDialogTitle => Intl.message("Create Emote", - name: "createEmoticonDialogTitle", - desc: - "Title of a dialog that pops up when choosing to create a new emoticon"); + String get createEmoticonDialogTitle => Intl.message( + "Create Emote", + name: "createEmoticonDialogTitle", + desc: + "Title of a dialog that pops up when choosing to create a new emoticon", + ); - String get editEmoticonDialogTitle => Intl.message("Edit Emote", - name: "editEmoticonDialogTitle", - desc: - "Title of a dialog that pops up when choosing to edit an existing emoticon"); + String get editEmoticonDialogTitle => Intl.message( + "Edit Emote", + name: "editEmoticonDialogTitle", + desc: "Title of a dialog that pops up when choosing to edit an existing emoticon", + ); @override Widget build(BuildContext context) { @@ -225,81 +251,86 @@ class EmoticonPackEditor extends StatelessWidget { children: [ Column( children: pack.emotes - .map((e) => Padding( - padding: const EdgeInsets.fromLTRB(0, 2, 0, 2), - child: ClipRRect( - borderRadius: BorderRadius.circular(8), - child: Material( - child: InkWell( - onTap: !editable - ? null - : () => AdaptiveDialog.show(context, - title: editEmoticonDialogTitle, - builder: (context) => EmoticonCreator( - pack: pack, - initialEmoticon: e, - onCreate: - (name, usage, newImageData) async { - await pack.updateEmoticon( - previous: e, - shortcode: name, - usage: usage, - data: newImageData, - ); - return true; - }, - onDelete: () async { - await pack.deleteEmoticon(e); - }, - ), - dismissible: true), - child: Padding( - padding: const EdgeInsets.all(4), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - SizedBox( - width: 40, - height: 40, - child: Image(image: e.image!)), - const SizedBox( - width: 10, - ), - tiamat.Text.label(e.shortcode!) - ], + .map( + (e) => Padding( + padding: const EdgeInsets.fromLTRB(0, 2, 0, 2), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Material( + child: InkWell( + onTap: !editable + ? null + : () => AdaptiveDialog.show( + context, + title: editEmoticonDialogTitle, + builder: (context) => EmoticonCreator( + pack: pack, + initialEmoticon: e, + onCreate: (name, usage, newImageData) async { + await pack.updateEmoticon( + previous: e, + shortcode: name, + usage: usage, + data: newImageData, + ); + return true; + }, + onDelete: () async { + await pack.deleteEmoticon(e); + }, ), - Row( - children: [ - if (e.isEmoji) - Icon( - color: Theme.of(context) - .colorScheme - .secondaryContainer, - size: 20, - Icons.emoji_emotions), - if (e.isSticker) - Icon( - color: Theme.of(context) - .colorScheme - .secondaryContainer, - Icons.sticky_note_2_rounded), - if (e.usage == EmoticonUsage.inherit) - Icon( - color: Theme.of(context) - .colorScheme - .secondaryContainer, - Icons.arrow_downward) - ], - ) - ], - ), + dismissible: true, + ), + child: Padding( + padding: const EdgeInsets.all(4), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + SizedBox( + width: 40, + height: 40, + child: Image(image: e.image!), + ), + const SizedBox(width: 10), + tiamat.Text.label(e.shortcode!), + ], + ), + Row( + children: [ + if (e.isEmoji) + Icon( + color: Theme.of(context) + .colorScheme + .secondaryContainer, + size: 20, + Icons.emoji_emotions, + ), + if (e.isSticker) + Icon( + color: Theme.of(context) + .colorScheme + .secondaryContainer, + Icons.sticky_note_2_rounded, + ), + if (e.usage == EmoticonUsage.inherit) + Icon( + color: Theme.of(context) + .colorScheme + .secondaryContainer, + Icons.arrow_downward, + ), + ], + ), + ], ), ), ), ), - )) + ), + ), + ) .toList(), ), if (editable) @@ -309,39 +340,43 @@ class EmoticonPackEditor extends StatelessWidget { padding: const EdgeInsets.fromLTRB(8, 8, 0, 8), child: tiamat.CircleButton( icon: Icons.add, - onPressed: () => AdaptiveDialog.show(context, - title: createEmoticonDialogTitle, - builder: (context) => EmoticonCreator( - pack: pack, - creatingNew: true, - onCreate: (name, usage, newImageData) async { - await pack.addEmoticon( - slug: name, - shortcode: name, - data: newImageData!, - usage: usage); - - return true; - }, - ), - dismissible: true), + onPressed: () => AdaptiveDialog.show( + context, + title: createEmoticonDialogTitle, + builder: (context) => EmoticonCreator( + pack: pack, + creatingNew: true, + onCreate: (name, usage, newImageData) async { + await pack.addEmoticon( + slug: name, + shortcode: name, + data: newImageData!, + usage: usage, + ); + + return true; + }, + ), + dismissible: true, + ), ), ), - ) + ), ], ); } } class EmoticonCreator extends StatefulWidget { - const EmoticonCreator( - {this.initialEmoticon, - this.pack, - this.createPack = false, - this.onCreate, - this.onDelete, - this.creatingNew = false, - super.key}); + const EmoticonCreator({ + this.initialEmoticon, + this.pack, + this.createPack = false, + this.onCreate, + this.onDelete, + this.creatingNew = false, + super.key, + }); final Emoticon? initialEmoticon; final EmoticonPack? pack; @@ -349,7 +384,11 @@ class EmoticonCreator extends StatefulWidget { final bool creatingNew; final Future Function( - String name, EmoticonUsage usage, Uint8List? newImageData)? onCreate; + String name, + EmoticonUsage usage, + Uint8List? newImageData, + )? + onCreate; final Future Function()? onDelete; @@ -365,18 +404,24 @@ class _EmoticonCreatorState extends State { TextEditingController controller = TextEditingController(); bool loading = false; - String get promptEmoticonPackName => Intl.message("Pack name", - name: "promptEmoticonPackName", - desc: "Prompt for the input of the name of an emoticon pack"); - - String get promptEmoteName => Intl.message("Emote name", - name: "promptEmoteName", - desc: "Prompt for the input of the name of an emoji"); - - String get promptConfirmSaveEmoticon => Intl.message("Save!", - name: "promptConfirmSaveEmoticon", - desc: - "Prompt to confirm the creation of an Emoticon Pack, Emoji, or Sticker"); + String get promptEmoticonPackName => Intl.message( + "Pack name", + name: "promptEmoticonPackName", + desc: "Prompt for the input of the name of an emoticon pack", + ); + + String get promptEmoteName => Intl.message( + "Emote name", + name: "promptEmoteName", + desc: "Prompt for the input of the name of an emoji", + ); + + String get promptConfirmSaveEmoticon => Intl.message( + "Save!", + name: "promptConfirmSaveEmoticon", + desc: + "Prompt to confirm the creation of an Emoticon Pack, Emoji, or Sticker", + ); @override void initState() { @@ -439,9 +484,7 @@ class _EmoticonCreatorState extends State { }, ), ), - const SizedBox( - width: 4, - ), + const SizedBox(width: 4), Expanded( child: ConstrainedBox( constraints: const BoxConstraints(minWidth: 300), @@ -453,12 +496,10 @@ class _EmoticonCreatorState extends State { controller: controller, ), ), - ) + ), ], ), - const SizedBox( - height: 4, - ), + const SizedBox(height: 4), SizedBox( height: 40, width: 40, @@ -483,25 +524,21 @@ class _EmoticonCreatorState extends State { EmoticonUsage.sticker => Icons.sticky_note_2, EmoticonUsage.emoji => Icons.emoji_emotions, EmoticonUsage.inherit => Icons.arrow_downward, - EmoticonUsage.all => Icons.star + EmoticonUsage.all => Icons.star, }), - const SizedBox( - width: 8, - ), + const SizedBox(width: 8), tiamat.Text.label(switch (item) { EmoticonUsage.sticker => "Sticker", EmoticonUsage.emoji => "Emoji", EmoticonUsage.inherit => "Follow Pack Settings", EmoticonUsage.all => "Emoji & Sticker", - }) + }), ], ); }, ), ), - const SizedBox( - height: 4, - ), + const SizedBox(height: 4), SizedBox( height: 48, child: tiamat.Button( @@ -512,23 +549,25 @@ class _EmoticonCreatorState extends State { loading = true; }); - await widget.onCreate - ?.call(controller.text, usage, imageData); + await widget.onCreate?.call( + controller.text, + usage, + imageData, + ); if (context.mounted) Navigator.of(context).pop(); } }, ), ), - const SizedBox( - height: 4, - ), + const SizedBox(height: 4), if (!widget.creatingNew) tiamat.Button.danger( text: CommonStrings.promptDelete, onTap: () async { - final confirm = - await AdaptiveDialog.confirmation(context); + final confirm = await AdaptiveDialog.confirmation( + context, + ); if (confirm == true) { setState(() { @@ -540,13 +579,13 @@ class _EmoticonCreatorState extends State { if (context.mounted) Navigator.of(context).pop(); } }, - ) + ), ], ), ), ), ), - if (loading) const Center(child: CircularProgressIndicator()) + if (loading) const Center(child: CircularProgressIndicator()), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/room/general/room_general_chat_privacy.dart b/commet/lib/ui/pages/settings/categories/room/general/room_general_chat_privacy.dart index a38e1d4fc..4127bff24 100644 --- a/commet/lib/ui/pages/settings/categories/room/general/room_general_chat_privacy.dart +++ b/commet/lib/ui/pages/settings/categories/room/general/room_general_chat_privacy.dart @@ -26,27 +26,31 @@ class _RoomGeneralChatPrivacySettings bool? typingIndicatorEnabledForRoom; String labelDefaultReadReceiptsOption(pref) => Intl.message( - "Use global preference ($pref)", - desc: - "Label to use the global preference, showing the current global preference value", - name: "labelDefaultReadReceiptsOption", - args: [pref]); + "Use global preference ($pref)", + desc: "Label to use the global preference, showing the current global preference value", + name: "labelDefaultReadReceiptsOption", + args: [pref], + ); String labelDefaultTypingIndicatorsOption(pref) => Intl.message( - "Use global preference ($pref)", - desc: - "Label to use the global preference, showing the current global preference value", - name: "labelDefaultTypingIndicatorsOption", - args: [pref]); + "Use global preference ($pref)", + desc: "Label to use the global preference, showing the current global preference value", + name: "labelDefaultTypingIndicatorsOption", + args: [pref], + ); - String get labelReadReceiptsTitle => Intl.message("Read receipts", - desc: - "Label for the toggle for enabling and disabling public read receipts", - name: "labelReadReceiptsTitle"); + String get labelReadReceiptsTitle => Intl.message( + "Read receipts", + desc: + "Label for the toggle for enabling and disabling public read receipts", + name: "labelReadReceiptsTitle", + ); - String get labelTypingIndicatorTitle => Intl.message("Typing indicators", - desc: "Label for the toggle for enabling and disabling typing indicators", - name: "labelTypingIndicatorTitle"); + String get labelTypingIndicatorTitle => Intl.message( + "Typing indicators", + desc: "Label for the toggle for enabling and disabling typing indicators", + name: "labelTypingIndicatorTitle", + ); @override void initState() { @@ -63,13 +67,13 @@ class _RoomGeneralChatPrivacySettings @override Widget build(BuildContext context) { - return Column(children: [ - publicReadReceiptsSettings(), - const SizedBox( - height: 10, - ), - publicTypingIndicatorSettings(), - ]); + return Column( + children: [ + publicReadReceiptsSettings(), + const SizedBox(height: 10), + publicTypingIndicatorSettings(), + ], + ); } Widget publicReadReceiptsSettings() { @@ -77,38 +81,41 @@ class _RoomGeneralChatPrivacySettings .getComponent()! .usePublicReadReceipts; return tiamat.Panel( - mode: tiamat.TileType.surfaceContainerLow, - header: labelReadReceiptsTitle, - child: material.Material( - color: material.Colors.transparent, - child: Column( - children: [ - tiamat.RadioButton( - groupValue: publicReadReceiptsForRoom, - value: null, - icon: material.Icons.remove_outlined, - text: labelDefaultReadReceiptsOption(usePublicReadReceipts + mode: tiamat.TileType.surfaceContainerLow, + header: labelReadReceiptsTitle, + child: material.Material( + color: material.Colors.transparent, + child: Column( + children: [ + tiamat.RadioButton( + groupValue: publicReadReceiptsForRoom, + value: null, + icon: material.Icons.remove_outlined, + text: labelDefaultReadReceiptsOption( + usePublicReadReceipts ? CommonStrings.labelPublic - : CommonStrings.labelPrivate), - onChanged: onReadReceiptPrefChanged, - ), - tiamat.RadioButton( - groupValue: publicReadReceiptsForRoom, - value: false, - icon: material.Icons.hide_source, - text: CommonStrings.labelPrivate, - onChanged: onReadReceiptPrefChanged, + : CommonStrings.labelPrivate, ), - tiamat.RadioButton( - groupValue: publicReadReceiptsForRoom, - value: true, - icon: material.Icons.public, - text: CommonStrings.labelPublic, - onChanged: onReadReceiptPrefChanged, - ), - ], - ), - )); + onChanged: onReadReceiptPrefChanged, + ), + tiamat.RadioButton( + groupValue: publicReadReceiptsForRoom, + value: false, + icon: material.Icons.hide_source, + text: CommonStrings.labelPrivate, + onChanged: onReadReceiptPrefChanged, + ), + tiamat.RadioButton( + groupValue: publicReadReceiptsForRoom, + value: true, + icon: material.Icons.public, + text: CommonStrings.labelPublic, + onChanged: onReadReceiptPrefChanged, + ), + ], + ), + ), + ); } Widget publicTypingIndicatorSettings() { @@ -116,38 +123,41 @@ class _RoomGeneralChatPrivacySettings .getComponent()! .typingIndicatorEnabled; return tiamat.Panel( - mode: tiamat.TileType.surfaceContainerLow, - header: labelTypingIndicatorTitle, - child: material.Material( - color: material.Colors.transparent, - child: Column( - children: [ - tiamat.RadioButton( - groupValue: typingIndicatorEnabledForRoom, - value: null, - icon: material.Icons.remove_outlined, - text: labelDefaultTypingIndicatorsOption(typingIndicatorEnabled + mode: tiamat.TileType.surfaceContainerLow, + header: labelTypingIndicatorTitle, + child: material.Material( + color: material.Colors.transparent, + child: Column( + children: [ + tiamat.RadioButton( + groupValue: typingIndicatorEnabledForRoom, + value: null, + icon: material.Icons.remove_outlined, + text: labelDefaultTypingIndicatorsOption( + typingIndicatorEnabled ? CommonStrings.labelEnabled - : CommonStrings.labelDisabled), - onChanged: onTypingIndicatorPrefChanged, + : CommonStrings.labelDisabled, ), - tiamat.RadioButton( - groupValue: typingIndicatorEnabledForRoom, - value: false, - icon: material.Icons.close, - text: CommonStrings.labelDisabled, - onChanged: onTypingIndicatorPrefChanged, - ), - tiamat.RadioButton( - groupValue: typingIndicatorEnabledForRoom, - value: true, - icon: material.Icons.check, - text: CommonStrings.labelEnabled, - onChanged: onTypingIndicatorPrefChanged, - ), - ], - ), - )); + onChanged: onTypingIndicatorPrefChanged, + ), + tiamat.RadioButton( + groupValue: typingIndicatorEnabledForRoom, + value: false, + icon: material.Icons.close, + text: CommonStrings.labelDisabled, + onChanged: onTypingIndicatorPrefChanged, + ), + tiamat.RadioButton( + groupValue: typingIndicatorEnabledForRoom, + value: true, + icon: material.Icons.check, + text: CommonStrings.labelEnabled, + onChanged: onTypingIndicatorPrefChanged, + ), + ], + ), + ), + ); } Future onReadReceiptPrefChanged(bool? value) async { diff --git a/commet/lib/ui/pages/settings/categories/room/general/room_general_settings_page.dart b/commet/lib/ui/pages/settings/categories/room/general/room_general_settings_page.dart index 9f0dadc12..312abc16b 100644 --- a/commet/lib/ui/pages/settings/categories/room/general/room_general_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/room/general/room_general_settings_page.dart @@ -30,16 +30,12 @@ class _RoomGeneralSettingsPageState extends State { pushRule: pushRule, onPushRuleChanged: setPushRule, ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), RoomGeneralChatPrivacySettings(widget.room), if (widget.room is MatrixRoom) ...[ - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), MatrixRoomAddressSettings((widget.room as MatrixRoom).matrixRoom), - ] + ], ], ); } diff --git a/commet/lib/ui/pages/settings/categories/room/general/room_general_settings_view.dart b/commet/lib/ui/pages/settings/categories/room/general/room_general_settings_view.dart index d8d21c8ac..cc4bc04ee 100644 --- a/commet/lib/ui/pages/settings/categories/room/general/room_general_settings_view.dart +++ b/commet/lib/ui/pages/settings/categories/room/general/room_general_settings_view.dart @@ -5,67 +5,76 @@ import 'package:tiamat/tiamat.dart' as tiamat; import 'package:flutter/material.dart' as material; class RoomGeneralSettingsView extends StatelessWidget { - const RoomGeneralSettingsView( - {super.key, required this.pushRule, this.onPushRuleChanged}); + const RoomGeneralSettingsView({ + super.key, + required this.pushRule, + this.onPushRuleChanged, + }); final PushRule pushRule; final void Function(PushRule? rule)? onPushRuleChanged; - String get labelPushRuleNotifyAll => Intl.message("All Messages", - desc: "Label for the push rule which notifies for all received messages", - name: "labelPushRuleNotifyAll"); + String get labelPushRuleNotifyAll => Intl.message( + "All Messages", + desc: "Label for the push rule which notifies for all received messages", + name: "labelPushRuleNotifyAll", + ); String get labelPushRuleMentionsAndKeywords => Intl.message( - "Mentions & Keywords", - desc: - "Label for the push rule which notifies only for keywords and mentions", - name: "labelPushRuleMentionsAndKeywords"); + "Mentions & Keywords", + desc: + "Label for the push rule which notifies only for keywords and mentions", + name: "labelPushRuleMentionsAndKeywords", + ); - String get labelPushRuleNone => Intl.message("Mute", - desc: "Label for the push rule which sends no notifications", - name: "labelPushRuleNone"); + String get labelPushRuleNone => Intl.message( + "Mute", + desc: "Label for the push rule which sends no notifications", + name: "labelPushRuleNone", + ); - String get labelRoomSettingsNotifications => Intl.message("Notifications", - desc: "Label for the notifications section in room settings", - name: "labelRoomSettingsNotifications"); + String get labelRoomSettingsNotifications => Intl.message( + "Notifications", + desc: "Label for the notifications section in room settings", + name: "labelRoomSettingsNotifications", + ); @override Widget build(BuildContext context) { - return Column( - children: [notificationSettings()], - ); + return Column(children: [notificationSettings()]); } Widget notificationSettings() { return tiamat.Panel( - mode: tiamat.TileType.surfaceContainerLow, - header: labelRoomSettingsNotifications, - child: material.Material( - color: material.Colors.transparent, - child: Column( - children: [ - tiamat.RadioButton( - groupValue: pushRule, - value: PushRule.notify, - icon: material.Icons.notifications_active_outlined, - text: labelPushRuleNotifyAll, - onChanged: onPushRuleChanged, - ), - tiamat.RadioButton( - groupValue: pushRule, - value: PushRule.mentionsOnly, - icon: material.Icons.notification_important_outlined, - text: labelPushRuleMentionsAndKeywords, - onChanged: onPushRuleChanged, - ), - tiamat.RadioButton( - groupValue: pushRule, - value: PushRule.dontNotify, - icon: material.Icons.notifications_off_outlined, - text: labelPushRuleNone, - onChanged: onPushRuleChanged, - ) - ], - ), - )); + mode: tiamat.TileType.surfaceContainerLow, + header: labelRoomSettingsNotifications, + child: material.Material( + color: material.Colors.transparent, + child: Column( + children: [ + tiamat.RadioButton( + groupValue: pushRule, + value: PushRule.notify, + icon: material.Icons.notifications_active_outlined, + text: labelPushRuleNotifyAll, + onChanged: onPushRuleChanged, + ), + tiamat.RadioButton( + groupValue: pushRule, + value: PushRule.mentionsOnly, + icon: material.Icons.notification_important_outlined, + text: labelPushRuleMentionsAndKeywords, + onChanged: onPushRuleChanged, + ), + tiamat.RadioButton( + groupValue: pushRule, + value: PushRule.dontNotify, + icon: material.Icons.notifications_off_outlined, + text: labelPushRuleNone, + onChanged: onPushRuleChanged, + ), + ], + ), + ), + ); } } diff --git a/commet/lib/ui/pages/settings/categories/room/permissions/matrix/matrix_room_permissions_page.dart b/commet/lib/ui/pages/settings/categories/room/permissions/matrix/matrix_room_permissions_page.dart index 8520a03c0..f375d945b 100644 --- a/commet/lib/ui/pages/settings/categories/room/permissions/matrix/matrix_room_permissions_page.dart +++ b/commet/lib/ui/pages/settings/categories/room/permissions/matrix/matrix_room_permissions_page.dart @@ -38,8 +38,11 @@ class MatrixRoomRoleEntry { } class MatrixRoomPermissionsPage extends StatefulWidget { - const MatrixRoomPermissionsPage(this.room, - {super.key, this.showCalendarPermissions = false}); + const MatrixRoomPermissionsPage( + this.room, { + super.key, + this.showCalendarPermissions = false, + }); final matrix.Room room; final bool showCalendarPermissions; @@ -54,34 +57,34 @@ class _MatrixRoomPermissionsPageState extends State { bool loading = false; String get labelMatrixPermissionsRoleOwner => Intl.message( - "Owner", - name: "labelMatrixPermissionsRoleOwner", - desc: "Label for the room owner role", - ); + "Owner", + name: "labelMatrixPermissionsRoleOwner", + desc: "Label for the room owner role", + ); String get labelMatrixPermissionsRoleAdmin => Intl.message( - "Admin", - name: "labelMatrixPermissionsRoleAdmin", - desc: "Label for the room administrator role", - ); + "Admin", + name: "labelMatrixPermissionsRoleAdmin", + desc: "Label for the room administrator role", + ); String get labelMatrixPermissionsRoleModerator => Intl.message( - "Moderator", - name: "labelMatrixPermissionsRoleModerator", - desc: "Label for the room moderator role", - ); + "Moderator", + name: "labelMatrixPermissionsRoleModerator", + desc: "Label for the room moderator role", + ); String get labelMatrixPermissionsRoleMember => Intl.message( - "Room Member", - name: "labelMatrixPermissionsRoleMember", - desc: "Label for the room member role", - ); + "Room Member", + name: "labelMatrixPermissionsRoleMember", + desc: "Label for the room member role", + ); String get labelMatrixPermissionsSpaceManageChildrenTitle => Intl.message( - "Manage Children", - name: "labelMatrixPermissionsSpaceManageChildrenTitle", - desc: "Title for permission to manage children", - ); + "Manage Children", + name: "labelMatrixPermissionsSpaceManageChildrenTitle", + desc: "Title for permission to manage children", + ); String get labelMatrixPermissionsSpaceManageChildrenDescription => Intl.message( @@ -91,10 +94,10 @@ class _MatrixRoomPermissionsPageState extends State { ); String get labelMatrixPermissionsRoomDeleteMessagesTitle => Intl.message( - "Delete Messages", - name: "labelMatrixPermissionsRoomDeleteMessagesTitle", - desc: "Title for permission to delete messages", - ); + "Delete Messages", + name: "labelMatrixPermissionsRoomDeleteMessagesTitle", + desc: "Title for permission to delete messages", + ); String get labelMatrixPermissionsRoomDeleteMessagesDescription => Intl.message( @@ -104,34 +107,34 @@ class _MatrixRoomPermissionsPageState extends State { ); String get labelMatrixPermissionsRoomSendMessagesTitle => Intl.message( - "Send Messages", - name: "labelMatrixPermissionsRoomSendMessagesTitle", - desc: "Title for the permission to send messages", - ); + "Send Messages", + name: "labelMatrixPermissionsRoomSendMessagesTitle", + desc: "Title for the permission to send messages", + ); String get labelMatrixPermissionsRoomSendMessagesDescription => Intl.message( - "Allows a user to send messages in this room", - name: "labelMatrixPermissionsRoomSendMessagesDescription", - desc: "Describes the permission to send messages", - ); + "Allows a user to send messages in this room", + name: "labelMatrixPermissionsRoomSendMessagesDescription", + desc: "Describes the permission to send messages", + ); String get labelMatrixPermissionsRoomAddReactionsTitle => Intl.message( - "Add Reactions", - name: "labelMatrixPermissionsRoomAddReactionsTitle", - desc: "Title for the permission to add an emoji reaction to a message", - ); + "Add Reactions", + name: "labelMatrixPermissionsRoomAddReactionsTitle", + desc: "Title for the permission to add an emoji reaction to a message", + ); String get labelMatrixPermissionsRoomAddReactionsDescription => Intl.message( - "Add reactions to messages", - name: "labelMatrixPermissionsRoomAddReactionsDescription", - desc: "describes the permission to add an emoji reaction to a message", - ); + "Add reactions to messages", + name: "labelMatrixPermissionsRoomAddReactionsDescription", + desc: "describes the permission to add an emoji reaction to a message", + ); String get labelMatrixPermissionsRoomHistoryVisibilityTitle => Intl.message( - "History Visibility", - name: "labelMatrixPermissionsRoomHistoryVisibilityTitle", - desc: "Title for the permission to add change room history settings", - ); + "History Visibility", + name: "labelMatrixPermissionsRoomHistoryVisibilityTitle", + desc: "Title for the permission to add change room history settings", + ); String get labelMatrixPermissionsRoomHistoryVisibilityDescription => Intl.message( @@ -141,59 +144,58 @@ class _MatrixRoomPermissionsPageState extends State { ); String get labelMatrixPermissionsRoomAvatarTitle => Intl.message( - "Set Room Avatar", - name: "labelMatrixPermissionsRoomAvatarTitle", - desc: "Title for the permission to add change the rooms avatar image", - ); + "Set Room Avatar", + name: "labelMatrixPermissionsRoomAvatarTitle", + desc: "Title for the permission to add change the rooms avatar image", + ); String get labelMatrixPermissionsRoomAvatarDescription => Intl.message( - "Change the room's avatar image", - name: "labelMatrixPermissionsRoomAvatarDescription", - desc: "Title for the permission to add change the rooms avatar image", - ); + "Change the room's avatar image", + name: "labelMatrixPermissionsRoomAvatarDescription", + desc: "Title for the permission to add change the rooms avatar image", + ); String get labelMatrixPermissionsMentionRoomTitle => Intl.message( - "Use @room mentions", - name: "labelMatrixPermissionsMentionRoomTitle", - desc: "Title for the permission to use '@room' mentions in a message", - ); + "Use @room mentions", + name: "labelMatrixPermissionsMentionRoomTitle", + desc: "Title for the permission to use '@room' mentions in a message", + ); String get labelMatrixPermissionsMentionRoomDescription => Intl.message( - "Allow use of '@room' to notify all members of the room", - name: "labelMatrixPermissionsMentionRoomDescription", - desc: - "Description for the permission to use '@room' mentions in a message", - ); + "Allow use of '@room' to notify all members of the room", + name: "labelMatrixPermissionsMentionRoomDescription", + desc: "Description for the permission to use '@room' mentions in a message", + ); String get labelMatrixPermissionsChangeRoomNameTitle => Intl.message( - "Change room name", - name: "labelMatrixPermissionsChangeRoomNameTitle", - desc: "Title for the permission to add change the rooms name", - ); + "Change room name", + name: "labelMatrixPermissionsChangeRoomNameTitle", + desc: "Title for the permission to add change the rooms name", + ); String get labelMatrixPermissionsChangeRoomNameDescription => Intl.message( - "Allows the user to change the name of this room", - name: "labelMatrixPermissionsChangeRoomNameDescription", - desc: "Description for the permission to add change the rooms name", - ); + "Allows the user to change the name of this room", + name: "labelMatrixPermissionsChangeRoomNameDescription", + desc: "Description for the permission to add change the rooms name", + ); String get labelMatrixPermissionsChangeRoomTopicTitle => Intl.message( - "Change room topic", - name: "labelMatrixPermissionsChangeRoomTopicTitle", - desc: "Title for the permission to add change the rooms topic", - ); + "Change room topic", + name: "labelMatrixPermissionsChangeRoomTopicTitle", + desc: "Title for the permission to add change the rooms topic", + ); String get labelMatrixPermissionsChangeRoomTopicDescription => Intl.message( - "Allows the user to change the topic of this room", - name: "labelMatrixPermissionsChangeRoomTopicDescription", - desc: "Description for the permission to add change the rooms topic", - ); + "Allows the user to change the topic of this room", + name: "labelMatrixPermissionsChangeRoomTopicDescription", + desc: "Description for the permission to add change the rooms topic", + ); String get labelMatrixPermissionsChangeRoomPermissionsTitle => Intl.message( - "Change permissions", - name: "labelMatrixPermissionsChangeRoomPermissionsTitle", - desc: "Title for the permission to change permissions of the room", - ); + "Change permissions", + name: "labelMatrixPermissionsChangeRoomPermissionsTitle", + desc: "Title for the permission to change permissions of the room", + ); String get labelMatrixPermissionsChangeRoomPermissionsDescription => Intl.message( @@ -204,56 +206,52 @@ class _MatrixRoomPermissionsPageState extends State { ); String get labelMatrixPermissionsKickUserTitle => Intl.message( - "Kick users", - name: "labelMatrixPermissionsKickUserTitle", - desc: "Title for the permission to kick other users out of the room", - ); + "Kick users", + name: "labelMatrixPermissionsKickUserTitle", + desc: "Title for the permission to kick other users out of the room", + ); String get labelMatrixPermissionsKickUserDescription => Intl.message( - "Kick other users out of the room", - name: "labelMatrixPermissionsKickUserDescription", - desc: - "Description for the permission to kick other users out of the room", - ); + "Kick other users out of the room", + name: "labelMatrixPermissionsKickUserDescription", + desc: "Description for the permission to kick other users out of the room", + ); String get labelMatrixPermissionsBanUserTitle => Intl.message( - "Ban users", - name: "labelMatrixPermissionsBanUserTitle", - desc: "Title for the permission to ban other users from the room", - ); + "Ban users", + name: "labelMatrixPermissionsBanUserTitle", + desc: "Title for the permission to ban other users from the room", + ); String get labelMatrixPermissionsBanUserDescription => Intl.message( - "Ban other users from the room", - name: "labelMatrixPermissionsBanUserDescription", - desc: "Description for the permission to ban other users from the room", - ); + "Ban other users from the room", + name: "labelMatrixPermissionsBanUserDescription", + desc: "Description for the permission to ban other users from the room", + ); String get labelMatrixPermissionsJoinCallTitle => Intl.message( - "Join Call", - name: "labelMatrixPermissionsJoinCallTitle", - desc: - "Title for the permission to allow users to join a call in a room", - ); + "Join Call", + name: "labelMatrixPermissionsJoinCallTitle", + desc: "Title for the permission to allow users to join a call in a room", + ); String get labelMatrixPermissionsJoinCallDescription => Intl.message( - "Allow users to join an ongoing call in this room", - name: "labelMatrixPermissionsJoinCallDescription", - desc: - "Description for the permission to allow users to join a call in a room", - ); + "Allow users to join an ongoing call in this room", + name: "labelMatrixPermissionsJoinCallDescription", + desc: "Description for the permission to allow users to join a call in a room", + ); String get labelMatrixPermissionsAddCalendarEventTitle => Intl.message( - "Edit Calendar Events", - name: "labelMatrixPermissionsAddCalendarEventTitle", - desc: "Title for the permission to allow users to edit the calendar", - ); + "Edit Calendar Events", + name: "labelMatrixPermissionsAddCalendarEventTitle", + desc: "Title for the permission to allow users to edit the calendar", + ); String get labelMatrixPermissionsAddCalendarEventDescription => Intl.message( - "Allow users to edit events in the calendar", - name: "labelMatrixPermissionsAddCalendarEventDescription", - desc: - "Description for the permission to allow users to create an event on the calendar", - ); + "Allow users to edit events in the calendar", + name: "labelMatrixPermissionsAddCalendarEventDescription", + desc: "Description for the permission to allow users to create an event on the calendar", + ); void initPermissions() { bool isCalendarRoom = widget.showCalendarPermissions; @@ -262,9 +260,10 @@ class _MatrixRoomPermissionsPageState extends State { roles = [ if (version != null && version >= 12) MatrixRoomRoleEntry( - name: labelMatrixPermissionsRoleOwner, - powerlevel: 150, - icon: Icons.local_police), + name: labelMatrixPermissionsRoleOwner, + powerlevel: 150, + icon: Icons.local_police, + ), MatrixRoomRoleEntry( name: labelMatrixPermissionsRoleAdmin, powerlevel: 100, @@ -424,16 +423,21 @@ class _MatrixRoomPermissionsPageState extends State { if (events != null) { for (var entry in events.entries) { if (permissions.any( - (i) => i.keyParent == "events" && i.key == entry.key)) continue; + (i) => i.keyParent == "events" && i.key == entry.key, + )) + continue; - permissions.add(MatrixRoomPermissionEntry( + permissions.add( + MatrixRoomPermissionEntry( key: entry.key, title: entry.key, keyParent: "events", description: "Allow the user to send events of type '${entry.key}'", icon: Icons.question_mark_rounded, - powerLevel: entry.value)); + powerLevel: entry.value, + ), + ); } } } diff --git a/commet/lib/ui/pages/settings/categories/room/permissions/matrix/matrix_room_permissions_view.dart b/commet/lib/ui/pages/settings/categories/room/permissions/matrix/matrix_room_permissions_view.dart index 4ea35c78a..3e1023812 100644 --- a/commet/lib/ui/pages/settings/categories/room/permissions/matrix/matrix_room_permissions_view.dart +++ b/commet/lib/ui/pages/settings/categories/room/permissions/matrix/matrix_room_permissions_view.dart @@ -9,13 +9,18 @@ import 'package:tiamat/atoms/tile.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class MatrixRoomPermissionsView extends StatefulWidget { - const MatrixRoomPermissionsView(this.permissions, this.powerLevels, - {super.key, this.setPermissions, this.canEdit = false}); + const MatrixRoomPermissionsView( + this.permissions, + this.powerLevels, { + super.key, + this.setPermissions, + this.canEdit = false, + }); final List permissions; final List powerLevels; final bool canEdit; final Future Function(List permissions)? - setPermissions; + setPermissions; @override State createState() => @@ -70,45 +75,44 @@ class _MatrixRoomPermissionsViewState extends State { return Scaffold( backgroundColor: Colors.transparent, body: ReorderableList( - itemBuilder: (context, index) { - var key = Key('$index'); - var enabled = - widget.canEdit && entries[index] is MatrixRoomPermissionEntry; - if (BuildConfig.MOBILE) { - return ReorderableDelayedDragStartListener( - key: key, - enabled: enabled, - index: index, - child: itemBuilder(context, index), - ); - } else { - return ReorderableDragStartListener( - key: key, - enabled: enabled, - index: index, - child: itemBuilder(context, index), - ); - } - }, - onReorderStart: (index) => HapticFeedback.mediumImpact(), - proxyDecorator: (child, index, animation) { - return AnimatedBuilder( - animation: animation, - builder: (BuildContext context, Widget? child) { - final double animValue = - Curves.easeOut.transform(animation.value); - final double scale = lerpDouble(1, 1.03, animValue)!; - return Transform.scale( - scale: scale, - child: child, - ); - }, - child: child, + itemBuilder: (context, index) { + var key = Key('$index'); + var enabled = + widget.canEdit && entries[index] is MatrixRoomPermissionEntry; + if (BuildConfig.MOBILE) { + return ReorderableDelayedDragStartListener( + key: key, + enabled: enabled, + index: index, + child: itemBuilder(context, index), ); - }, - shrinkWrap: true, - itemCount: entries.length, - onReorder: onReorder), + } else { + return ReorderableDragStartListener( + key: key, + enabled: enabled, + index: index, + child: itemBuilder(context, index), + ); + } + }, + onReorderStart: (index) => HapticFeedback.mediumImpact(), + proxyDecorator: (child, index, animation) { + return AnimatedBuilder( + animation: animation, + builder: (BuildContext context, Widget? child) { + final double animValue = Curves.easeOut.transform( + animation.value, + ); + final double scale = lerpDouble(1, 1.03, animValue)!; + return Transform.scale(scale: scale, child: child); + }, + child: child, + ); + }, + shrinkWrap: true, + itemCount: entries.length, + onReorder: onReorder, + ), floatingActionButton: isEdited ? FloatingActionButton( child: isLoading @@ -120,7 +124,8 @@ class _MatrixRoomPermissionsViewState extends State { ), ) : const Icon(Icons.check), - onPressed: () => applySettings()) + onPressed: () => applySettings(), + ) : null, ); } @@ -178,7 +183,7 @@ class _MatrixRoomPermissionsViewState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ tiamat.Text.labelEmphasised(item.title), - tiamat.Text.labelLow(item.description) + tiamat.Text.labelLow(item.description), ], ), ), @@ -204,7 +209,7 @@ class _MatrixRoomPermissionsViewState extends State { ), tiamat.Text.tiny(item.powerLevel.toString()), ], - ) + ), ], ), ), diff --git a/commet/lib/ui/pages/settings/categories/room/security/room_security_settings_page.dart b/commet/lib/ui/pages/settings/categories/room/security/room_security_settings_page.dart index 5a6215562..86203925a 100644 --- a/commet/lib/ui/pages/settings/categories/room/security/room_security_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/room/security/room_security_settings_page.dart @@ -29,15 +29,17 @@ class _RoomSecuritySettingsPageState extends State { late bool isE2EEEnabled; late RoomVisibility visibility; - String get promptEnableEncryptionRoomSettings => - Intl.message("Enable Encryption", - name: "promptEnableEncryptionRoomSettings", - desc: "Short prompt to enable encryption for a room"); - - String get encryptionCannotBeDisabledExplanationRoomSettings => - Intl.message("If enabled, encryption cannot be disabled later", - name: "encryptionCannotBeDisabledExplanationRoomSettings", - desc: "Explains that encryption cannot be disabled once enabled"); + String get promptEnableEncryptionRoomSettings => Intl.message( + "Enable Encryption", + name: "promptEnableEncryptionRoomSettings", + desc: "Short prompt to enable encryption for a room", + ); + + String get encryptionCannotBeDisabledExplanationRoomSettings => Intl.message( + "If enabled, encryption cannot be disabled later", + name: "encryptionCannotBeDisabledExplanationRoomSettings", + desc: "Explains that encryption cannot be disabled once enabled", + ); @override void initState() { @@ -67,14 +69,15 @@ class _RoomSecuritySettingsPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - tiamat.Text.labelEmphasised( - promptEnableEncryptionRoomSettings), - tiamat.Text.labelLow( - encryptionCannotBeDisabledExplanationRoomSettings) - ]), + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + tiamat.Text.labelEmphasised(promptEnableEncryptionRoomSettings), + tiamat.Text.labelLow( + encryptionCannotBeDisabledExplanationRoomSettings, + ), + ], + ), IgnorePointer( ignoring: isE2EEEnabled || !widget.room.permissions.canEnableE2EE, child: tiamat.Switch( @@ -87,7 +90,7 @@ class _RoomSecuritySettingsPageState extends State { }); }, ), - ) + ), ], ), ), @@ -116,8 +119,11 @@ class _RoomSecuritySettingsPageState extends State { } if (spaces.isEmpty) { - var parents = widget.room.client.spaces.where((i) => i.subspaces - .any((i) => i.identifier == widget.room.identifier)); + var parents = widget.room.client.spaces.where( + (i) => i.subspaces.any( + (i) => i.identifier == widget.room.identifier, + ), + ); for (var p in parents) { spaces.add(p.identifier); @@ -144,7 +150,9 @@ class _RoomSecuritySettingsPageState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: RoomFieldVisibility.buildRoomVisibility( - widget.room.client, item), + widget.room.client, + item, + ), ), ), ); @@ -162,7 +170,9 @@ class _RoomSecuritySettingsPageState extends State { } }, child: RoomFieldVisibility.buildRoomVisibility( - widget.room.client, visibility), + widget.room.client, + visibility, + ), ), ), ), diff --git a/commet/lib/ui/pages/settings/categories/room/settings_category_room.dart b/commet/lib/ui/pages/settings/categories/room/settings_category_room.dart index e35a2a1c0..d61ea33ee 100644 --- a/commet/lib/ui/pages/settings/categories/room/settings_category_room.dart +++ b/commet/lib/ui/pages/settings/categories/room/settings_category_room.dart @@ -21,52 +21,52 @@ class SettingsCategoryRoom implements SettingsCategory { Space? contextSpace; String get labelRoomSettingsGeneral => Intl.message( - "General", - name: "labelRoomSettingsGeneral", - desc: "Label for general room settings", - ); + "General", + name: "labelRoomSettingsGeneral", + desc: "Label for general room settings", + ); String get labelRoomSettingsAppearance => Intl.message( - "Appearance", - name: "labelRoomSettingsAppearance", - desc: "Label for room appearance settings", - ); + "Appearance", + name: "labelRoomSettingsAppearance", + desc: "Label for room appearance settings", + ); String get labelRoomSettingsSecurity => Intl.message( - "Security", - name: "labelRoomSettingsSecurity", - desc: "Label for room security settings", - ); + "Security", + name: "labelRoomSettingsSecurity", + desc: "Label for room security settings", + ); String get labelRoomSettingsEmoticons => Intl.message( - "Emoticons", - name: "labelRoomSettingsEmoticons", - desc: "Label for room Emoticon settings", - ); + "Emoticons", + name: "labelRoomSettingsEmoticons", + desc: "Label for room Emoticon settings", + ); String get labelRoomSettingsDeveloper => Intl.message( - "Developer", - name: "labelRoomSettingsDeveloper", - desc: "Label for room developer settings", - ); + "Developer", + name: "labelRoomSettingsDeveloper", + desc: "Label for room developer settings", + ); String get labelRoomSettingsCategory => Intl.message( - "Room Settings", - name: "labelRoomSettingsCategory", - desc: "Label for the overall settings category of a room", - ); + "Room Settings", + name: "labelRoomSettingsCategory", + desc: "Label for the overall settings category of a room", + ); String get labelRoomSettingsPermissions => Intl.message( - "Permissions", - name: "labelRoomSettingsPermissions", - desc: "Label for room permission settings", - ); + "Permissions", + name: "labelRoomSettingsPermissions", + desc: "Label for room permission settings", + ); String get labelRoomSettingsCalendar => Intl.message( - "Calendar", - name: "labelRoomSettingsCalendar", - desc: "Label for room calendar settings", - ); + "Calendar", + name: "labelRoomSettingsCalendar", + desc: "Label for room calendar settings", + ); @override String get title => labelRoomSettingsCategory; @@ -75,8 +75,8 @@ class SettingsCategoryRoom implements SettingsCategory { List get tabs => getTabs(); List getTabs() { - RoomEmoticonComponent? emoticons = - room.getComponent(); + RoomEmoticonComponent? emoticons = room + .getComponent(); CalendarRoom? calendar = room.getComponent(); diff --git a/commet/lib/ui/pages/settings/categories/space/settings_category_space.dart b/commet/lib/ui/pages/settings/categories/space/settings_category_space.dart index 8015f34c8..e50776b0e 100644 --- a/commet/lib/ui/pages/settings/categories/space/settings_category_space.dart +++ b/commet/lib/ui/pages/settings/categories/space/settings_category_space.dart @@ -21,41 +21,53 @@ class SettingsCategorySpace implements SettingsCategory { SettingsCategorySpace(this.space); Space space; - String get labelSpaceSettingsGeneral => Intl.message("General", - name: "labelSpaceSettingsGeneral", - desc: "Label for general space settings"); + String get labelSpaceSettingsGeneral => Intl.message( + "General", + name: "labelSpaceSettingsGeneral", + desc: "Label for general space settings", + ); - String get labelSpaceAppearanceSettings => Intl.message("Appearance", - name: "labelSpaceAppearanceSettings", - desc: "Label for space appearance settings"); + String get labelSpaceAppearanceSettings => Intl.message( + "Appearance", + name: "labelSpaceAppearanceSettings", + desc: "Label for space appearance settings", + ); - String get labelSpaceEmoticonSettings => Intl.message("Emoticons", - name: "labelSpaceEmoticonSettings", - desc: "Label for space emoticon settings"); + String get labelSpaceEmoticonSettings => Intl.message( + "Emoticons", + name: "labelSpaceEmoticonSettings", + desc: "Label for space emoticon settings", + ); - String get labelSpacePermissionSettings => Intl.message("Permissions", - name: "labelSpacePermissionSettings", - desc: "Label for space permission settings"); + String get labelSpacePermissionSettings => Intl.message( + "Permissions", + name: "labelSpacePermissionSettings", + desc: "Label for space permission settings", + ); - String get labelSpaceDeveloperSettings => Intl.message("Developer", - name: "labelSpaceDeveloperSettings", - desc: "Label for space developer settings"); + String get labelSpaceDeveloperSettings => Intl.message( + "Developer", + name: "labelSpaceDeveloperSettings", + desc: "Label for space developer settings", + ); - String get labelSettingsCategorySpace => Intl.message("Space Settings", - name: "labelSettingsCategorySpace", - desc: "Label for the overall space settings category"); + String get labelSettingsCategorySpace => Intl.message( + "Space Settings", + name: "labelSettingsCategorySpace", + desc: "Label for the overall space settings category", + ); String get labelSpaceSettingsSecurity => Intl.message( - "Security", - name: "labelSpaceSettingsSecurity", - desc: "Label for space security settings", - ); + "Security", + name: "labelSpaceSettingsSecurity", + desc: "Label for space security settings", + ); String get labelSpaceSettingsMembers => Intl.message( - "Members", - name: "labelSpaceSettingsMembers", - desc: "Label for space member settings", - ); + "Members", + name: "labelSpaceSettingsMembers", + desc: "Label for space member settings", + ); @override String get title => labelSettingsCategorySpace; @@ -64,25 +76,23 @@ class SettingsCategorySpace implements SettingsCategory { List get tabs => getTabs(); List getTabs() { - SpaceEmoticonComponent? emoticons = - space.getComponent(); + SpaceEmoticonComponent? emoticons = space + .getComponent(); return List.from([ SettingsTab( - label: labelSpaceSettingsGeneral, - icon: Icons.settings, - pageBuilder: (context) { - return SpaceGeneralSettingsPage( - space: space, - ); - }), + label: labelSpaceSettingsGeneral, + icon: Icons.settings, + pageBuilder: (context) { + return SpaceGeneralSettingsPage(space: space); + }, + ), SettingsTab( - label: labelSpaceAppearanceSettings, - icon: Icons.style, - pageBuilder: (context) { - return SpaceAppearanceSettingsPage( - space: space, - ); - }), + label: labelSpaceAppearanceSettings, + icon: Icons.style, + pageBuilder: (context) { + return SpaceAppearanceSettingsPage(space: space); + }, + ), if (space case MatrixSpace s) SettingsTab( label: labelSpaceSettingsSecurity, @@ -90,45 +100,56 @@ class SettingsCategorySpace implements SettingsCategory { makeScrollable: false, pageBuilder: (context) { return RoomSecuritySettingsPage( - showEncryptionToggle: false, - room: MatrixRoom(space.client as MatrixClient, s.matrixRoom, - s.matrixRoom.client)); + showEncryptionToggle: false, + room: MatrixRoom( + space.client as MatrixClient, + s.matrixRoom, + s.matrixRoom.client, + ), + ); }, ), if (emoticons != null && (space.permissions.canEditRoomEmoticons || emoticons.ownedPacks.isNotEmpty)) SettingsTab( - label: labelSpaceEmoticonSettings, - icon: Icons.emoji_emotions, - pageBuilder: (context) { - return SpaceEmojiPackSettings(space); - }), + label: labelSpaceEmoticonSettings, + icon: Icons.emoji_emotions, + pageBuilder: (context) { + return SpaceEmojiPackSettings(space); + }, + ), if (space is MatrixSpace) SettingsTab( - label: labelSpacePermissionSettings, - icon: Icons.admin_panel_settings, - makeScrollable: false, - pageBuilder: (context) { - return MatrixRoomPermissionsPage( - (space as MatrixSpace).matrixRoom); - }), + label: labelSpacePermissionSettings, + icon: Icons.admin_panel_settings, + makeScrollable: false, + pageBuilder: (context) { + return MatrixRoomPermissionsPage((space as MatrixSpace).matrixRoom); + }, + ), if (preferences.developerMode.value) SettingsTab( - label: labelSpaceDeveloperSettings, - icon: Icons.code, - makeScrollable: true, - pageBuilder: (context) { - return SpaceDeveloperSettingsView(space); - }), + label: labelSpaceDeveloperSettings, + icon: Icons.code, + makeScrollable: true, + pageBuilder: (context) { + return SpaceDeveloperSettingsView(space); + }, + ), if (space case MatrixSpace s) SettingsTab( label: labelSpaceSettingsMembers, icon: Icons.people, makeScrollable: false, pageBuilder: (context) { - return RoomMemberList(MatrixRoom(space.client as MatrixClient, - s.matrixRoom, s.matrixRoom.client)); + return RoomMemberList( + MatrixRoom( + space.client as MatrixClient, + s.matrixRoom, + s.matrixRoom.client, + ), + ); }, ), ]); diff --git a/commet/lib/ui/pages/settings/categories/space/space_appearance_settings_page.dart b/commet/lib/ui/pages/settings/categories/space/space_appearance_settings_page.dart index 588e33a8a..4b9adc990 100644 --- a/commet/lib/ui/pages/settings/categories/space/space_appearance_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/space/space_appearance_settings_page.dart @@ -42,7 +42,7 @@ class _SpaceAppearanceSettingsPageState Widget build(BuildContext context) { bool canEditBanner = widget.space.getComponent()?.canEditBanner == - true; + true; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -60,19 +60,18 @@ class _SpaceAppearanceSettingsPageState canEditTopic: widget.space.permissions.canEditTopic, canEditAvatar: widget.space.permissions.canEditAvatar, ), - SizedBox( - height: 12, - ), + SizedBox(height: 12), if (canEditBanner) tiamat.Text.labelLow("Set Banner:"), if (canEditBanner) ClipRRect( borderRadius: BorderRadiusGeometry.circular(12), child: DecoratedBox( decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerLow, - image: image != null - ? DecorationImage(image: image!, fit: BoxFit.cover) - : null), + color: Theme.of(context).colorScheme.surfaceContainerLow, + image: image != null + ? DecorationImage(image: image!, fit: BoxFit.cover) + : null, + ), child: Material( color: Colors.transparent, child: InkWell( @@ -98,8 +97,10 @@ class _SpaceAppearanceSettingsPageState return; } - var result = await PickerUtils.pickImageAndCrop(context, - aspectRatio: 16 / 9); + var result = await PickerUtils.pickImageAndCrop( + context, + aspectRatio: 16 / 9, + ); if (result != null) { setState(() { @@ -109,9 +110,7 @@ class _SpaceAppearanceSettingsPageState await widget.space .getComponent() - ?.setBanner( - result, - ); + ?.setBanner(result); setState(() { uploading = false; @@ -125,15 +124,17 @@ class _SpaceAppearanceSettingsPageState child: uploading ? Center( child: SizedBox( - width: 30, - height: 30, - child: CircularProgressIndicator())) + width: 30, + height: 30, + child: CircularProgressIndicator(), + ), + ) : null, ), ), ), ), - ) + ), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/space/space_developer_settings_view.dart b/commet/lib/ui/pages/settings/categories/space/space_developer_settings_view.dart index 4a7a572ce..49733fa0b 100644 --- a/commet/lib/ui/pages/settings/categories/space/space_developer_settings_view.dart +++ b/commet/lib/ui/pages/settings/categories/space/space_developer_settings_view.dart @@ -10,27 +10,26 @@ class SpaceDeveloperSettingsView extends StatelessWidget { @override Widget build(BuildContext context) { return Column( - children: [jsonDump(context)].map((e) { - return Padding( - padding: const EdgeInsets.fromLTRB(0, 3, 0, 3), - child: ClipRRect(borderRadius: BorderRadius.circular(10), child: e), - ); - }).toList()); + children: [jsonDump(context)].map((e) { + return Padding( + padding: const EdgeInsets.fromLTRB(0, 3, 0, 3), + child: ClipRRect(borderRadius: BorderRadius.circular(10), child: e), + ); + }).toList(), + ); } Widget jsonDump(BuildContext context) { return ExpansionTile( title: const tiamat.Text.labelEmphasised("Room State"), backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, children: [ SelectionArea( - child: Codeblock( - language: "json", - text: space.developerInfo, - ), - ) + child: Codeblock(language: "json", text: space.developerInfo), + ), ], ); } diff --git a/commet/lib/ui/pages/settings/categories/space/space_general_settings_page.dart b/commet/lib/ui/pages/settings/categories/space/space_general_settings_page.dart index 24587d543..d7a9a1cf7 100644 --- a/commet/lib/ui/pages/settings/categories/space/space_general_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/space/space_general_settings_page.dart @@ -31,11 +31,9 @@ class _SpaceGeneralSettingsPageState extends State { pushRule: pushRule, onPushRuleChanged: setPushRule, ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), if (widget.space is MatrixSpace) - MatrixRoomAddressSettings((widget.space as MatrixSpace).matrixRoom) + MatrixRoomAddressSettings((widget.space as MatrixSpace).matrixRoom), ], ); } diff --git a/commet/lib/ui/pages/settings/desktop_settings_page.dart b/commet/lib/ui/pages/settings/desktop_settings_page.dart index 9e5d65889..f7db40c19 100644 --- a/commet/lib/ui/pages/settings/desktop_settings_page.dart +++ b/commet/lib/ui/pages/settings/desktop_settings_page.dart @@ -13,12 +13,13 @@ import 'package:tiamat/tiamat.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class DesktopSettingsPage extends StatefulWidget { - const DesktopSettingsPage( - {required this.settings, - this.buttons, - this.onDonateButtonTapped, - this.showDonateButton = false, - super.key}); + const DesktopSettingsPage({ + required this.settings, + this.buttons, + this.onDonateButtonTapped, + this.showDonateButton = false, + super.key, + }); final List settings; final List? buttons; final bool showDonateButton; @@ -32,8 +33,9 @@ class DesktopSettingsPageState extends State { int selectedCategoryIndex = 0; int selectedTabIndex = 0; - static ValueKey backButtonKey = - const ValueKey("DESKTOP_SETTINGS_PAGE_BACK_BUTTON"); + static ValueKey backButtonKey = const ValueKey( + "DESKTOP_SETTINGS_PAGE_BACK_BUTTON", + ); @override void initState() { @@ -52,12 +54,13 @@ class DesktopSettingsPageState extends State { children: [ tabSelector(context), Expanded( - child: categories[selectedCategoryIndex] + child: + categories[selectedCategoryIndex] .tabs[selectedTabIndex] .makeScrollable ? SingleChildScrollView(child: buildContent()) : buildContent(), - ) + ), ], ), ), @@ -72,13 +75,16 @@ class DesktopSettingsPageState extends State { caulkClipBottomLeft: true, key: ValueKey(selectedTabIndex), child: ScaledSafeArea( - child: selectedCategoryIndex < categories.length && - selectedTabIndex < - categories[selectedCategoryIndex].tabs.length - ? settingsTab(categories[selectedCategoryIndex] - .tabs[selectedTabIndex] - .pageBuilder) - : Container()), + child: + selectedCategoryIndex < categories.length && + selectedTabIndex < categories[selectedCategoryIndex].tabs.length + ? settingsTab( + categories[selectedCategoryIndex] + .tabs[selectedTabIndex] + .pageBuilder, + ) + : Container(), + ), ); } @@ -103,52 +109,59 @@ class DesktopSettingsPageState extends State { Padding( padding: const EdgeInsets.all(8), child: Align( - alignment: Alignment.centerLeft, - child: CircleButton( - key: backButtonKey, - radius: 25, - icon: m.Icons.arrow_back, - onPressed: () => Navigator.of(context).pop(), - )), + alignment: Alignment.centerLeft, + child: CircleButton( + key: backButtonKey, + radius: 25, + icon: m.Icons.arrow_back, + onPressed: () => Navigator.of(context).pop(), + ), + ), ), Flexible( child: Padding( padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), - child: ListView(children: [ - ListView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: categories.length, - itemBuilder: (context, categoryIndex) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (categoryIndex != 0) - const tiamat.Seperator(), - if (categories[categoryIndex].title != null) - tiamat.Text.labelLow( - categories[categoryIndex].title!), - tabListBuilder(categoryIndex) - ], - ); - }, - ), - if (widget.buttons != null) const Seperator(), - if (widget.buttons != null) + child: ListView( + children: [ ListView.builder( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, - itemCount: widget.buttons!.length, - itemBuilder: (context, index) { - return button( + itemCount: categories.length, + itemBuilder: (context, categoryIndex) { + return Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (categoryIndex != 0) + const tiamat.Seperator(), + if (categories[categoryIndex].title != + null) + tiamat.Text.labelLow( + categories[categoryIndex].title!, + ), + tabListBuilder(categoryIndex), + ], + ); + }, + ), + if (widget.buttons != null) const Seperator(), + if (widget.buttons != null) + ListView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: widget.buttons!.length, + itemBuilder: (context, index) { + return button( label: widget.buttons![index].label, icon: widget.buttons![index].icon, onTap: widget.buttons![index].onPress, - color: widget.buttons![index].color); - }, - ), - ]), + color: widget.buttons![index].color, + ); + }, + ), + ], + ), ), ), ], @@ -156,8 +169,10 @@ class DesktopSettingsPageState extends State { ), ), if (widget.showDonateButton) - buildDonateButton(context, - onTap: () => widget.onDonateButtonTapped?.call(context)) + buildDonateButton( + context, + onTap: () => widget.onDonateButtonTapped?.call(context), + ), ], ), ), @@ -165,14 +180,17 @@ class DesktopSettingsPageState extends State { ); } - static String get promptDonate => Intl.message("Donate", - name: "promptDonate", desc: "Prompt the user to donate to the project"); + static String get promptDonate => Intl.message( + "Donate", + name: "promptDonate", + desc: "Prompt the user to donate to the project", + ); static String get promptDonationsRefreshAwards => Intl.message( - "Refresh Awards", - name: "promptDonationsRefreshAwards", - desc: - "Prompt the user to refresh any awards they may have received for donating to the project"); + "Refresh Awards", + name: "promptDonationsRefreshAwards", + desc: "Prompt the user to refresh any awards they may have received for donating to the project", + ); static Widget buildDonateButton(BuildContext context, {Function()? onTap}) { return Padding( @@ -180,30 +198,31 @@ class DesktopSettingsPageState extends State { child: AdaptiveContextMenu( items: [ ContextMenuItem( - text: promptDonationsRefreshAwards, - icon: m.Icons.refresh, - onPressed: () async { - var client = await AdaptiveDialog.pickClient(context); + text: promptDonationsRefreshAwards, + icon: m.Icons.refresh, + onPressed: () async { + var client = await AdaptiveDialog.pickClient(context); - if (client != null) { - var identifier = await client - .getComponent() - ?.getClientSecret(); - if (identifier != null) { - AdaptiveDialog.show( - context, - builder: (context) { - return DonationRewardsConfirmation( - client: client, - identifier: identifier, - didOpenDonationWindow: false, - since: null, - ); - }, - ); - } + if (client != null) { + var identifier = await client + .getComponent() + ?.getClientSecret(); + if (identifier != null) { + AdaptiveDialog.show( + context, + builder: (context) { + return DonationRewardsConfirmation( + client: client, + identifier: identifier, + didOpenDonationWindow: false, + since: null, + ); + }, + ); } - }), + } + }, + ), ], child: m.Material( clipBehavior: Clip.antiAlias, @@ -214,22 +233,23 @@ class DesktopSettingsPageState extends State { child: SizedBox( width: double.infinity, child: Padding( - padding: const EdgeInsets.fromLTRB(16, 4, 16, 4), - child: Row( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: m.Icon( - m.Icons.favorite, - color: m.ColorScheme.of(context).onSurfaceVariant, - ), - ), - tiamat.Text( - promptDonate, - color: m.ColorScheme.of(context).onSurface, + padding: const EdgeInsets.fromLTRB(16, 4, 16, 4), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: m.Icon( + m.Icons.favorite, + color: m.ColorScheme.of(context).onSurfaceVariant, ), - ], - )), + ), + tiamat.Text( + promptDonate, + color: m.ColorScheme.of(context).onSurface, + ), + ], + ), + ), ), ), ), @@ -242,40 +262,44 @@ class DesktopSettingsPageState extends State { shrinkWrap: true, itemBuilder: (context, tabIndex) { return button( - label: categories[categoryIndex].tabs[tabIndex].label, - icon: categories[categoryIndex].tabs[tabIndex].icon, - highlighted: categoryIndex == selectedCategoryIndex && - tabIndex == selectedTabIndex, - onTap: () { - setState(() { - selectedCategoryIndex = categoryIndex; - selectedTabIndex = tabIndex; - }); + label: categories[categoryIndex].tabs[tabIndex].label, + icon: categories[categoryIndex].tabs[tabIndex].icon, + highlighted: + categoryIndex == selectedCategoryIndex && + tabIndex == selectedTabIndex, + onTap: () { + setState(() { + selectedCategoryIndex = categoryIndex; + selectedTabIndex = tabIndex; }); + }, + ); }, itemCount: categories[categoryIndex].tabs.length, ); } - Widget button( - {required String label, - IconData? icon, - bool highlighted = false, - Color? color, - Function()? onTap}) { + Widget button({ + required String label, + IconData? icon, + bool highlighted = false, + Color? color, + Function()? onTap, + }) { return Padding( padding: const EdgeInsets.fromLTRB(0, 2, 0, 2), child: SizedBox( - height: 40, - width: 200, - child: TextButton( - label, - icon: icon, - highlighted: highlighted, - onTap: onTap, - textColor: color, - iconColor: color, - )), + height: 40, + width: 200, + child: TextButton( + label, + icon: icon, + highlighted: highlighted, + onTap: onTap, + textColor: color, + iconColor: color, + ), + ), ); } diff --git a/commet/lib/ui/pages/settings/donation_rewards_confirmation.dart b/commet/lib/ui/pages/settings/donation_rewards_confirmation.dart index faa747f58..85b0447f7 100644 --- a/commet/lib/ui/pages/settings/donation_rewards_confirmation.dart +++ b/commet/lib/ui/pages/settings/donation_rewards_confirmation.dart @@ -15,12 +15,13 @@ import 'package:starfield/renderer/particle_system_renderer.dart'; import 'package:tiamat/tiamat.dart' as tiamat; class DonationRewardsConfirmation extends StatefulWidget { - const DonationRewardsConfirmation( - {required this.client, - required this.identifier, - required this.since, - required this.didOpenDonationWindow, - super.key}); + const DonationRewardsConfirmation({ + required this.client, + required this.identifier, + required this.since, + required this.didOpenDonationWindow, + super.key, + }); final Client client; final SecretClientIdentifier identifier; final DateTime? since; @@ -32,7 +33,8 @@ class DonationRewardsConfirmation extends StatefulWidget { } class _DonationRewardsConfirmationState - extends State with WidgetsBindingObserver { + extends State + with WidgetsBindingObserver { late DonationAwardsClient awards; List? receivedAwards; EcsParticleSystem? particles; @@ -41,8 +43,10 @@ class _DonationRewardsConfirmationState @override void initState() { - awards = - DonationAwardsClient(BuildConfig.donationRewardsApiHost, widget.client); + awards = DonationAwardsClient( + BuildConfig.donationRewardsApiHost, + widget.client, + ); WidgetsBinding.instance.addObserver(this); @@ -104,10 +108,7 @@ class _DonationRewardsConfirmationState } Future checkConfirmation() async { - var result = await awards.getAwards( - widget.identifier, - since: widget.since, - ); + var result = await awards.getAwards(widget.identifier, since: widget.since); if (result != null) { if (result.isNotEmpty) { doConfetti(); @@ -120,34 +121,35 @@ class _DonationRewardsConfirmationState } } - String get titleConfirmingDonation => Intl.message("Confirming Donation", - name: "titleConfirmingDonation", - desc: - "Title for the popup shown while waiting for the user to finish the donation flow, which checks for completion of the donation"); + String get titleConfirmingDonation => Intl.message( + "Confirming Donation", + name: "titleConfirmingDonation", + desc: "Title for the popup shown while waiting for the user to finish the donation flow, which checks for completion of the donation", + ); String get labelDonationInstructions => Intl.message( - "Follow the instructions in your browser. Please be patient, it may take a minute or two for your awards to appear once your donation has been received.", - name: "labelDonationInstructions", - desc: - "Explains to the user to follow the donation instructions shown in the opened web page. Also asks for patience if the confirmation is taking a while to complete after donating"); + "Follow the instructions in your browser. Please be patient, it may take a minute or two for your awards to appear once your donation has been received.", + name: "labelDonationInstructions", + desc: "Explains to the user to follow the donation instructions shown in the opened web page. Also asks for patience if the confirmation is taking a while to complete after donating", + ); String get labelDonationConfirmationSucceeded => Intl.message( - "Thank you for your generous donation!", - name: "labelDonationConfirmationSucceeded", - desc: - "Text that is shown when the donation flow was successful, and the donation has been confirmed"); + "Thank you for your generous donation!", + name: "labelDonationConfirmationSucceeded", + desc: "Text that is shown when the donation flow was successful, and the donation has been confirmed", + ); String get labelDonationConfirmationFailed => Intl.message( - "Could not find any donations :( Please consider donating to support development of Commet!", - name: "labelDonationConfirmationFailed", - desc: - "Text that is shown when the donation flow was failed, and the no donation was found"); + "Could not find any donations :( Please consider donating to support development of Commet!", + name: "labelDonationConfirmationFailed", + desc: "Text that is shown when the donation flow was failed, and the no donation was found", + ); String get labelConfirmCancelDonationConfirmation => Intl.message( - "Are you sure you want to dismiss without accepting any award?", - name: "labelConfirmCancelDonationConfirmation", - desc: - "Text that is shown when the user attempts to cancel the donation confirmation flow before the confirmation has finished"); + "Are you sure you want to dismiss without accepting any award?", + name: "labelConfirmCancelDonationConfirmation", + desc: "Text that is shown when the user attempts to cancel the donation confirmation flow before the confirmation has finished", + ); @override Widget build(BuildContext context) { @@ -160,38 +162,41 @@ class _DonationRewardsConfirmationState WidgetsBinding.instance.lifecycleState == AppLifecycleState.resumed) SizedBox( - width: 800, - height: 500, - child: ParticleSystemRenderer(system: particles!)), + width: 800, + height: 500, + child: ParticleSystemRenderer(system: particles!), + ), Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - titleConfirmingDonation, - style: TextTheme.of(context).headlineSmall, - ), - if (widget.didOpenDonationWindow) - tiamat.Text.labelLow(labelDonationInstructions), - ]), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + titleConfirmingDonation, + style: TextTheme.of(context).headlineSmall, + ), + if (widget.didOpenDonationWindow) + tiamat.Text.labelLow(labelDonationInstructions), + ], + ), Column( children: [ if (receivedAwards == null) SizedBox( height: 200, - child: Center( - child: CircularProgressIndicator(), - ), + child: Center(child: CircularProgressIndicator()), ), if (receivedAwards?.isNotEmpty == true) Padding( padding: const EdgeInsets.all(8.0), child: Column( - spacing: 10, - children: receivedAwards! - .map((i) => buildAward(i)) - .toList()), + spacing: 10, + children: receivedAwards! + .map((i) => buildAward(i)) + .toList(), + ), ), if (receivedAwards?.isEmpty == true) tiamat.Text.labelLow(labelDonationConfirmationFailed), @@ -199,8 +204,9 @@ class _DonationRewardsConfirmationState Padding( padding: const EdgeInsets.all(8.0), child: tiamat.Text.labelLow( - labelDonationConfirmationSucceeded), - ) + labelDonationConfirmationSucceeded, + ), + ), ], ), Column( @@ -211,38 +217,41 @@ class _DonationRewardsConfirmationState IgnorePointer( ignoring: acceptLoading, child: tiamat.Button( - text: CommonStrings.promptAccept, - isLoading: acceptLoading, - onTap: () async { - setState(() { - acceptLoading = true; - }); + text: CommonStrings.promptAccept, + isLoading: acceptLoading, + onTap: () async { + setState(() { + acceptLoading = true; + }); - preferences.clearRunningDonationCheckFlow(); + preferences.clearRunningDonationCheckFlow(); - await widget.client - .getComponent() - ?.acceptAwards(receivedAwards! - .map((i) => i.data) - .toList()); + await widget.client + .getComponent() + ?.acceptAwards( + receivedAwards!.map((i) => i.data).toList(), + ); - Navigator.of(context).pop(); - }), + Navigator.of(context).pop(); + }, + ), ), tiamat.Button.secondary( - text: CommonStrings.promptDismiss, - onTap: () async { - if (receivedAwards?.isEmpty == true || - await AdaptiveDialog.confirmation(context, - prompt: - labelConfirmCancelDonationConfirmation) == - true) { - preferences.clearRunningDonationCheckFlow(); - Navigator.of(context).pop(); - } - }) + text: CommonStrings.promptDismiss, + onTap: () async { + if (receivedAwards?.isEmpty == true || + await AdaptiveDialog.confirmation( + context, + prompt: labelConfirmCancelDonationConfirmation, + ) == + true) { + preferences.clearRunningDonationCheckFlow(); + Navigator.of(context).pop(); + } + }, + ), ], - ) + ), ], ), ], @@ -253,8 +262,9 @@ class _DonationRewardsConfirmationState Widget buildAward(DonationAward i) { return Container( decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainerLowest, - borderRadius: BorderRadius.circular(8)), + color: ColorScheme.of(context).surfaceContainerLowest, + borderRadius: BorderRadius.circular(8), + ), child: Padding( padding: const EdgeInsets.all(8.0), child: Row( @@ -262,7 +272,7 @@ class _DonationRewardsConfirmationState spacing: 12, children: [ SizedBox(height: 64, width: 64, child: Image(image: i.image)), - tiamat.Text.largeTitle(i.title) + tiamat.Text.largeTitle(i.title), ], ), ), diff --git a/commet/lib/ui/pages/settings/mobile_settings_page.dart b/commet/lib/ui/pages/settings/mobile_settings_page.dart index 88fde4416..5d1530b6c 100644 --- a/commet/lib/ui/pages/settings/mobile_settings_page.dart +++ b/commet/lib/ui/pages/settings/mobile_settings_page.dart @@ -10,12 +10,13 @@ import 'package:tiamat/tiamat.dart' as tiamat; import '../../navigation/navigation_utils.dart'; class MobileSettingsPage extends StatefulWidget { - const MobileSettingsPage( - {required this.settings, - this.buttons, - this.onDonateButtonTapped, - this.showDonateButton = false, - super.key}); + const MobileSettingsPage({ + required this.settings, + this.buttons, + this.onDonateButtonTapped, + this.showDonateButton = false, + super.key, + }); final List? buttons; final List settings; final bool showDonateButton; @@ -48,83 +49,93 @@ class _MobileSettingsPageState extends State { Padding( padding: const EdgeInsets.all(8.0), child: Align( - alignment: Alignment.centerLeft, - child: CircleButton( - radius: 25, - icon: m.Icons.arrow_back, - onPressed: () => Navigator.of(context).pop(), - )), + alignment: Alignment.centerLeft, + child: CircleButton( + radius: 25, + icon: m.Icons.arrow_back, + onPressed: () => Navigator.of(context).pop(), + ), + ), ), Flexible( - child: ListView(children: [ - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: tabs.length, - itemBuilder: (context, categoryIndex) { - return m.Padding( - padding: const EdgeInsets.all(8.0), - child: m.Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (categoryIndex != 0) const tiamat.Seperator(), - if (tabs[categoryIndex].title != null) - tiamat.Text.labelLow( - tabs[categoryIndex].title!, - ), - ListView.builder( - shrinkWrap: true, - itemCount: tabs[categoryIndex].tabs.length, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, tabIndex) { - return button( - label: tabs[categoryIndex] - .tabs[tabIndex] - .label, - icon: - tabs[categoryIndex].tabs[tabIndex].icon, - onTap: () { - setState(() { - NavigationUtils.navigateTo( - context, - SettingsSubPage( - makeScrollable: - tabs[categoryIndex] - .tabs[tabIndex] - .makeScrollable, - builder: tabs[categoryIndex] - .tabs[tabIndex] - .pageBuilder)); - }); - }, - ); - }, - ) - ], - ), - ); - }, - ), - if (widget.buttons != null) const Seperator(), - if (widget.buttons != null) + child: ListView( + children: [ ListView.builder( shrinkWrap: true, - itemCount: widget.buttons!.length, - itemBuilder: (context, index) { - var b = widget.buttons![index]; - return button( + physics: const NeverScrollableScrollPhysics(), + itemCount: tabs.length, + itemBuilder: (context, categoryIndex) { + return m.Padding( + padding: const EdgeInsets.all(8.0), + child: m.Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (categoryIndex != 0) + const tiamat.Seperator(), + if (tabs[categoryIndex].title != null) + tiamat.Text.labelLow( + tabs[categoryIndex].title!, + ), + ListView.builder( + shrinkWrap: true, + itemCount: tabs[categoryIndex].tabs.length, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, tabIndex) { + return button( + label: tabs[categoryIndex] + .tabs[tabIndex] + .label, + icon: tabs[categoryIndex] + .tabs[tabIndex] + .icon, + onTap: () { + setState(() { + NavigationUtils.navigateTo( + context, + SettingsSubPage( + makeScrollable: + tabs[categoryIndex] + .tabs[tabIndex] + .makeScrollable, + builder: tabs[categoryIndex] + .tabs[tabIndex] + .pageBuilder, + ), + ); + }); + }, + ); + }, + ), + ], + ), + ); + }, + ), + if (widget.buttons != null) const Seperator(), + if (widget.buttons != null) + ListView.builder( + shrinkWrap: true, + itemCount: widget.buttons!.length, + itemBuilder: (context, index) { + var b = widget.buttons![index]; + return button( label: b.label, icon: b.icon, color: b.color, - onTap: b.onPress); - }, - ) - ]), + onTap: b.onPress, + ); + }, + ), + ], + ), ), if (widget.showDonateButton) - DesktopSettingsPageState.buildDonateButton(context, - onTap: () => widget.onDonateButtonTapped?.call(context)) + DesktopSettingsPageState.buildDonateButton( + context, + onTap: () => widget.onDonateButtonTapped?.call(context), + ), ], ), ), @@ -133,28 +144,33 @@ class _MobileSettingsPageState extends State { ); } - Widget button( - {required String label, - IconData? icon, - bool highlighted = false, - Color? color, - Function()? onTap}) { + Widget button({ + required String label, + IconData? icon, + bool highlighted = false, + Color? color, + Function()? onTap, + }) { return SizedBox( - height: 40, - child: TextButton( - label, - icon: icon, - highlighted: highlighted, - onTap: onTap, - textColor: color, - iconColor: color, - )); + height: 40, + child: TextButton( + label, + icon: icon, + highlighted: highlighted, + onTap: onTap, + textColor: color, + iconColor: color, + ), + ); } } class SettingsSubPage extends StatelessWidget { - const SettingsSubPage( - {required this.builder, super.key, this.makeScrollable = true}); + const SettingsSubPage({ + required this.builder, + super.key, + this.makeScrollable = true, + }); final Widget Function(BuildContext) builder; final bool makeScrollable; @override @@ -168,12 +184,7 @@ class SettingsSubPage extends StatelessWidget { children: [ if (makeScrollable) ListView( - children: [ - const SizedBox( - height: 70, - ), - builder(context) - ], + children: [const SizedBox(height: 70), builder(context)], ), if (!makeScrollable) m.Padding( @@ -187,7 +198,7 @@ class SettingsSubPage extends StatelessWidget { icon: m.Icons.arrow_back, onPressed: () => Navigator.of(context).pop(), ), - ) + ), ], ), ), diff --git a/commet/lib/ui/pages/settings/room_settings_page.dart b/commet/lib/ui/pages/settings/room_settings_page.dart index 409a92674..2c6101e79 100644 --- a/commet/lib/ui/pages/settings/room_settings_page.dart +++ b/commet/lib/ui/pages/settings/room_settings_page.dart @@ -7,8 +7,12 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; class RoomSettingsPage extends StatefulWidget { - const RoomSettingsPage( - {super.key, this.contextSpace, required this.room, this.onLeaveRoom}); + const RoomSettingsPage({ + super.key, + this.contextSpace, + required this.room, + this.onLeaveRoom, + }); final Room room; final Space? contextSpace; final Function()? onLeaveRoom; @@ -18,39 +22,41 @@ class RoomSettingsPage extends StatefulWidget { } class _RoomSettingsPageState extends State { - String get promptLeaveRoom => Intl.message("Leave Room", - desc: "Text on a button to leave a room", name: "promptLeaveRoom"); + String get promptLeaveRoom => Intl.message( + "Leave Room", + desc: "Text on a button to leave a room", + name: "promptLeaveRoom", + ); - String promptLeaveRoomConfirmation(String roomName) => - Intl.message("Are you sure you want to leave $roomName?", - desc: "Text for the popup dialog confirming the intent to leave", - args: [roomName], - name: "promptLeaveRoomConfirmation"); + String promptLeaveRoomConfirmation(String roomName) => Intl.message( + "Are you sure you want to leave $roomName?", + desc: "Text for the popup dialog confirming the intent to leave", + args: [roomName], + name: "promptLeaveRoomConfirmation", + ); @override Widget build(BuildContext context) { return SettingsPage( - settings: [ - SettingsCategoryRoom( - widget.room, - widget.contextSpace, - ), - ], + settings: [SettingsCategoryRoom(widget.room, widget.contextSpace)], buttons: [ SettingsButton( - label: promptLeaveRoom, - icon: Icons.subdirectory_arrow_left_rounded, - color: Theme.of(context).colorScheme.error, - onPress: () => leaveRoom(context)), + label: promptLeaveRoom, + icon: Icons.subdirectory_arrow_left_rounded, + color: Theme.of(context).colorScheme.error, + onPress: () => leaveRoom(context), + ), ], ); } Future leaveRoom(BuildContext context) async { - if (await AdaptiveDialog.confirmation(context, - title: promptLeaveRoom, - prompt: promptLeaveRoomConfirmation(widget.room.displayName), - dangerous: true) == + if (await AdaptiveDialog.confirmation( + context, + title: promptLeaveRoom, + prompt: promptLeaveRoomConfirmation(widget.room.displayName), + dangerous: true, + ) == true) { if (context.mounted) Navigator.pop(context); widget.room.client.leaveRoom(widget.room); diff --git a/commet/lib/ui/pages/settings/settings_page.dart b/commet/lib/ui/pages/settings/settings_page.dart index 28bae6721..d2910275a 100644 --- a/commet/lib/ui/pages/settings/settings_page.dart +++ b/commet/lib/ui/pages/settings/settings_page.dart @@ -16,11 +16,12 @@ import 'package:intl/intl.dart'; import 'desktop_settings_page.dart'; class SettingsPage extends StatelessWidget { - const SettingsPage( - {required this.settings, - this.buttons, - this.showDonateButton = false, - super.key}); + const SettingsPage({ + required this.settings, + this.buttons, + this.showDonateButton = false, + super.key, + }); final List settings; final List? buttons; final bool showDonateButton; @@ -49,33 +50,33 @@ class SettingsPage extends StatelessWidget { } throw Exception( - "No SettingsPage has been defined for the current build config"); + "No SettingsPage has been defined for the current build config", + ); } - static String get labelNoAccount => Intl.message("No Account", - name: "labelNoAccount", - desc: - "When the user is prompted to select an account to use for some action, this option is shown when the action can be completed without picking any account"); + static String get labelNoAccount => Intl.message( + "No Account", + name: "labelNoAccount", + desc: "When the user is prompted to select an account to use for some action, this option is shown when the action can be completed without picking any account", + ); static String get promptPickDonationAccount => Intl.message( - "Pick an account to donate with", - name: "promptPickDonationAccount", - desc: "Prompt the user to select an account to link to their donation"); + "Pick an account to donate with", + name: "promptPickDonationAccount", + desc: "Prompt the user to select an account to link to their donation", + ); static String get labelDonateAnonymously => Intl.message( - "Donate without linking to an account", - name: "labelDonateAnonymously", - desc: - "Prompt the user to donate to the project, without linking to their user account"); + "Donate without linking to an account", + name: "labelDonateAnonymously", + desc: "Prompt the user to donate to the project, without linking to their user account", + ); static onDonateButtonTapped(BuildContext context) async { var client = await AdaptiveDialog.pickOne( title: promptPickDonationAccount, context, - items: [ - ...clientManager!.clients, - "anonymous", - ], + items: [...clientManager!.clients, "anonymous"], itemBuilder: (context, item, callback) { if (item is Client) { return UserPanelView( @@ -107,8 +108,10 @@ class SettingsPage extends StatelessWidget { secret = await comp?.getClientSecret(); if (secret == null) { - AdaptiveDialog.show(context, - builder: (_) => Text("Error: Unable to get client token")); + AdaptiveDialog.show( + context, + builder: (_) => Text("Error: Unable to get client token"), + ); } } @@ -123,26 +126,31 @@ class SettingsPage extends StatelessWidget { var time = DateTime.now(); var url = Uri.parse( - "$host/donate/#client_reference_id=${Uri.encodeComponent(secret?.encryptedHash ?? "null")}&matrix_id=${Uri.encodeComponent(userId!)}&secret=${Uri.encodeComponent(secret?.clientSecret ?? "null")}"); + "$host/donate/#client_reference_id=${Uri.encodeComponent(secret?.encryptedHash ?? "null")}&matrix_id=${Uri.encodeComponent(userId!)}&secret=${Uri.encodeComponent(secret?.clientSecret ?? "null")}", + ); if (client is Client) { preferences.setRunningDonationCheckFlow(client.identifier, time); } - LinkUtils.open(url, - context: context, - filterTrackingParameters: false, - bypassConfirmation: true); + LinkUtils.open( + url, + context: context, + filterTrackingParameters: false, + bypassConfirmation: true, + ); if (userId != "null" && secret != null) { - AdaptiveDialog.show(context, - builder: (context) => DonationRewardsConfirmation( - client: client, - identifier: secret!, - didOpenDonationWindow: true, - since: time, - ), - dismissible: false); + AdaptiveDialog.show( + context, + builder: (context) => DonationRewardsConfirmation( + client: client, + identifier: secret!, + didOpenDonationWindow: true, + since: time, + ), + dismissible: false, + ); } } } diff --git a/commet/lib/ui/pages/settings/settings_tab.dart b/commet/lib/ui/pages/settings/settings_tab.dart index ccc3fb056..a0a265a32 100644 --- a/commet/lib/ui/pages/settings/settings_tab.dart +++ b/commet/lib/ui/pages/settings/settings_tab.dart @@ -6,9 +6,10 @@ class SettingsTab { final IconData? icon; final bool makeScrollable; - SettingsTab( - {required this.label, - required this.pageBuilder, - this.icon, - this.makeScrollable = true}); + SettingsTab({ + required this.label, + required this.pageBuilder, + this.icon, + this.makeScrollable = true, + }); } diff --git a/commet/lib/ui/pages/settings/space_settings_page.dart b/commet/lib/ui/pages/settings/space_settings_page.dart index c109c065a..2b9ac7240 100644 --- a/commet/lib/ui/pages/settings/space_settings_page.dart +++ b/commet/lib/ui/pages/settings/space_settings_page.dart @@ -15,38 +15,41 @@ class SpaceSettingsPage extends StatefulWidget { } class _SpaceSettingsPageState extends State { - String get promptLeaveSpace => Intl.message("Leave Space", - desc: "Text on a button to leave a space", name: "promptLeaveSpace"); + String get promptLeaveSpace => Intl.message( + "Leave Space", + desc: "Text on a button to leave a space", + name: "promptLeaveSpace", + ); String promptLeaveSpaceConfirmation(String spaceName) => Intl.message( - "Are you sure you want to leave $spaceName?", - desc: "Text for the popup dialog confirming the intent to leave a space", - args: [spaceName], - name: "promptLeaveSpaceConfirmation"); + "Are you sure you want to leave $spaceName?", + desc: "Text for the popup dialog confirming the intent to leave a space", + args: [spaceName], + name: "promptLeaveSpaceConfirmation", + ); @override Widget build(BuildContext context) { return SettingsPage( - settings: [ - SettingsCategorySpace( - widget.space, - ), - ], + settings: [SettingsCategorySpace(widget.space)], buttons: [ SettingsButton( - label: promptLeaveSpace, - icon: Icons.subdirectory_arrow_left_rounded, - color: Theme.of(context).colorScheme.error, - onPress: () => leaveSpace(context)), + label: promptLeaveSpace, + icon: Icons.subdirectory_arrow_left_rounded, + color: Theme.of(context).colorScheme.error, + onPress: () => leaveSpace(context), + ), ], ); } Future leaveSpace(BuildContext context) async { - if (await AdaptiveDialog.confirmation(context, - title: promptLeaveSpace, - prompt: promptLeaveSpaceConfirmation(widget.space.displayName), - dangerous: true) == + if (await AdaptiveDialog.confirmation( + context, + title: promptLeaveSpace, + prompt: promptLeaveSpaceConfirmation(widget.space.displayName), + dangerous: true, + ) == true) { if (context.mounted) Navigator.pop(context); widget.space.client.leaveSpace(widget.space); diff --git a/commet/lib/ui/pages/setup/menus/check_for_updates.dart b/commet/lib/ui/pages/setup/menus/check_for_updates.dart index 816055dcf..fb709edf7 100644 --- a/commet/lib/ui/pages/setup/menus/check_for_updates.dart +++ b/commet/lib/ui/pages/setup/menus/check_for_updates.dart @@ -18,18 +18,20 @@ class UpdateCheckerSetup implements SetupMenu { children: [ tiamat.Text.largeTitle("Check for updates"), tiamat.Text.label( - "Would you like Commet to automatically check for new updates?"), + "Would you like Commet to automatically check for new updates?", + ), Padding( padding: const EdgeInsets.all(8.0), child: Container( - decoration: BoxDecoration( - color: ColorScheme.of(context).surfaceContainerLowest, - borderRadius: BorderRadius.circular(8), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: CheckForUpdatesSettingWidget(), - )), + decoration: BoxDecoration( + color: ColorScheme.of(context).surfaceContainerLowest, + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: CheckForUpdatesSettingWidget(), + ), + ), ), ], ); diff --git a/commet/lib/ui/pages/setup/menus/unified_push_setup.dart b/commet/lib/ui/pages/setup/menus/unified_push_setup.dart index be7c5eea3..e7adf63db 100644 --- a/commet/lib/ui/pages/setup/menus/unified_push_setup.dart +++ b/commet/lib/ui/pages/setup/menus/unified_push_setup.dart @@ -174,7 +174,7 @@ If you already have a Unified Push compatible distributor app installed, you can if (mounted) { UnifiedPush.tryUseCurrentOrDefaultDistributor().then((success) { - if(success) { + if (success) { UnifiedPush.register(); } else { Log.w("Failed to register unified push"); diff --git a/commet/lib/ui/pages/setup/setup_menu.dart b/commet/lib/ui/pages/setup/setup_menu.dart index 3d22a8de3..c0733e3bb 100644 --- a/commet/lib/ui/pages/setup/setup_menu.dart +++ b/commet/lib/ui/pages/setup/setup_menu.dart @@ -1,9 +1,6 @@ import 'package:flutter/material.dart'; -enum SetupMenuState { - canProgress, - cannotProgress, -} +enum SetupMenuState { canProgress, cannotProgress } abstract class SetupMenu { Widget builder(BuildContext context); diff --git a/commet/lib/ui/pages/setup/setup_page.dart b/commet/lib/ui/pages/setup/setup_page.dart index d6ae71f24..dd7882135 100644 --- a/commet/lib/ui/pages/setup/setup_page.dart +++ b/commet/lib/ui/pages/setup/setup_page.dart @@ -38,9 +38,9 @@ class _SetupPageState extends State { children: [ Flexible( child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: Tile.low( - child: Column( + borderRadius: BorderRadius.circular(10), + child: Tile.low( + child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -48,7 +48,8 @@ class _SetupPageState extends State { child: Padding( padding: const EdgeInsets.all(8), child: SingleChildScrollView( - child: currentMenu.builder(context)), + child: currentMenu.builder(context), + ), ), ), Column( @@ -64,22 +65,23 @@ class _SetupPageState extends State { ), ), TweenAnimationBuilder( - tween: Tween( - begin: 0, - end: currentMenuIndex / - widget.menus.length), - duration: const Duration(milliseconds: 200), - curve: Curves.easeOutCubic, - builder: (context, value, _) { - return LinearProgressIndicator( - value: value, - ); - }) + tween: Tween( + begin: 0, + end: currentMenuIndex / widget.menus.length, + ), + duration: const Duration(milliseconds: 200), + curve: Curves.easeOutCubic, + builder: (context, value, _) { + return LinearProgressIndicator(value: value); + }, + ), ], ), ], - ))), - ) + ), + ), + ), + ), ], ), ), diff --git a/commet/lib/utils/animation/ring_shaker.dart b/commet/lib/utils/animation/ring_shaker.dart index 6db9e851d..841877c73 100644 --- a/commet/lib/utils/animation/ring_shaker.dart +++ b/commet/lib/utils/animation/ring_shaker.dart @@ -34,10 +34,7 @@ class _RingShakerAnimationState extends State var amp = sin(controller.value * 50); amp = amp * pow(1 - controller.value, 2); amp *= 0.15; - return Transform.rotate( - angle: amp, - child: child, - ); + return Transform.rotate(angle: amp, child: child); }, child: widget.child, ); diff --git a/commet/lib/utils/animation/ripple.dart b/commet/lib/utils/animation/ripple.dart index 31ee8e13d..1c3caa4c8 100644 --- a/commet/lib/utils/animation/ripple.dart +++ b/commet/lib/utils/animation/ripple.dart @@ -1,5 +1,6 @@ // Based on https://github.com/jemisgoti/simple_ripple_animation import 'dart:async'; + import 'package:flutter/material.dart'; /// You can use whatever widget as a [child], when you don't need to provide any @@ -54,10 +55,7 @@ class RippleAnimationState extends State @override void initState() { - _controller = AnimationController( - duration: widget.duration, - vsync: this, - ); + _controller = AnimationController(duration: widget.duration, vsync: this); Timer? animationTimer; @@ -81,24 +79,27 @@ class RippleAnimationState extends State @override Widget build(BuildContext context) => CustomPaint( - painter: CirclePainter(_controller, - color: widget.color, - minRadius: widget.minRadius, - wavesCount: widget.ripplesCount + 2, - scale: widget.scale), - child: widget.child, - ); + painter: CirclePainter( + _controller, + color: widget.color, + minRadius: widget.minRadius, + wavesCount: widget.ripplesCount + 2, + scale: widget.scale, + ), + child: widget.child, + ); } /// Creating a Circular painter for clipping the rects and creating circle shape class CirclePainter extends CustomPainter { ///initialize the painter - CirclePainter(this.animation, - {required this.wavesCount, - required this.color, - this.minRadius, - this.scale = 1}) - : super(repaint: animation); + CirclePainter( + this.animation, { + required this.wavesCount, + required this.color, + this.minRadius, + this.scale = 1, + }) : super(repaint: animation); ///[Color] of the painter final Color color; diff --git a/commet/lib/utils/app_focus_util.dart b/commet/lib/utils/app_focus_util.dart index 4f533783f..6b0a66985 100644 --- a/commet/lib/utils/app_focus_util.dart +++ b/commet/lib/utils/app_focus_util.dart @@ -15,12 +15,14 @@ class AppFocus { static void init() { _state = WidgetsBinding.instance.lifecycleState; - WidgetsBinding.instance.addObserver(AppFocusObserver((state) { - Log.i("App lifecycle state changed: ${state}"); - - _state = state; - _focusStateChanged.add(null); - })); + WidgetsBinding.instance.addObserver( + AppFocusObserver((state) { + Log.i("App lifecycle state changed: ${state}"); + + _state = state; + _focusStateChanged.add(null); + }), + ); } } diff --git a/commet/lib/utils/autofill_utils.dart b/commet/lib/utils/autofill_utils.dart index 6c8e7c2d2..9830a8e97 100644 --- a/commet/lib/utils/autofill_utils.dart +++ b/commet/lib/utils/autofill_utils.dart @@ -8,8 +8,11 @@ import 'package:flutter/material.dart'; import 'package:fuzzy/fuzzy.dart'; class AutofillUtils { - static List search(String string, Client client, - {Room? room}) { + static List search( + String string, + Client client, { + Room? room, + }) { List? results; var firstChar = string.characters.first; @@ -38,21 +41,27 @@ class AutofillUtils { return []; } - var fuzzy = Fuzzy(results, - options: FuzzyOptions(keys: [ + var fuzzy = Fuzzy( + results, + options: FuzzyOptions( + keys: [ WeightedKey( - name: "alternate", - getter: (obj) { - return obj.alternateSearchTerm ?? ""; - }, - weight: 1), + name: "alternate", + getter: (obj) { + return obj.alternateSearchTerm ?? ""; + }, + weight: 1, + ), WeightedKey( - name: "result", - getter: (result) { - return result.result; - }, - weight: 1) - ])); + name: "result", + getter: (result) { + return result.result; + }, + weight: 1, + ), + ], + ), + ); return fuzzy.search(string, 20).map((e) { return e.item; @@ -81,14 +90,17 @@ class AutofillUtils { .map((i) => i.senderId) .toSet(); - results = recentUsers.map((i) { - var member = room.getMemberOrFallback(i); - return AutofillSearchResultAvatar( - member.displayName, - member.identifier, - member.avatar, - member.defaultColor) as AutofillSearchResult; - }).toList(growable: true); + results = recentUsers + .map((i) { + var member = room.getMemberOrFallback(i); + return AutofillSearchResultAvatar( + member.displayName, + member.identifier, + member.avatar, + member.defaultColor, + ) as AutofillSearchResult; + }) + .toList(growable: true); } } @@ -97,15 +109,27 @@ class AutofillUtils { .map((e) => room.getMemberOrFallback(e)) .toList(); - results.addAll(result - .map((e) => AutofillSearchResultAvatar( - e.displayName, e.identifier, e.avatar, e.defaultColor) - as AutofillSearchResult) - .toList(growable: true)); + results.addAll( + result + .map( + (e) => AutofillSearchResultAvatar( + e.displayName, + e.identifier, + e.avatar, + e.defaultColor, + ) as AutofillSearchResult, + ) + .toList(growable: true), + ); if (room.permissions.canMentionRoom) { - results.add(AutofillSearchResult("@room", "@room", - alternateSearchTerm: "@everyone")); + results.add( + AutofillSearchResult( + "@room", + "@room", + alternateSearchTerm: "@everyone", + ), + ); } return results; @@ -113,8 +137,9 @@ class AutofillUtils { static List searchRooms(String string, Room room) { var rooms = List.empty(growable: true); - var spaces = room.client.spaces - .where((element) => element.containsRoom(room.identifier)); + var spaces = room.client.spaces.where( + (element) => element.containsRoom(room.identifier), + ); for (var space in spaces) { for (var room in space.rooms) { if (!rooms.contains(room)) { @@ -122,26 +147,33 @@ class AutofillUtils { } } } - var fuzzy = Fuzzy(rooms, - options: FuzzyOptions(keys: [ + var fuzzy = Fuzzy( + rooms, + options: FuzzyOptions( + keys: [ WeightedKey( - name: "displayName", - getter: (result) { - return result.displayName; - }, - weight: 1) - ])); + name: "displayName", + getter: (result) { + return result.displayName; + }, + weight: 1, + ), + ], + ), + ); return fuzzy.search(string, 20).map((e) { return AutofillSearchResult(e.item.displayName, e.item.identifier); }).toList(); } - static List searchEmoticon(String string, - {int limit = 20, - required Client client, - Room? room, - double threshold = 0.2}) { + static List searchEmoticon( + String string, { + int limit = 20, + required Client client, + Room? room, + double threshold = 0.2, + }) { List? packs; if (room != null) { var emoticons = room.getComponent(); @@ -156,23 +188,34 @@ class AutofillUtils { var result = List.empty(growable: true); for (var pack in packs) { - var fuzzy = Fuzzy(pack.emoji, - options: FuzzyOptions(threshold: threshold, keys: [ + var fuzzy = Fuzzy( + pack.emoji, + options: FuzzyOptions( + threshold: threshold, + keys: [ WeightedKey( - name: "shortcode", - getter: (obj) { - return obj.shortcode ?? ""; - }, - weight: 1) - ])); + name: "shortcode", + getter: (obj) { + return obj.shortcode ?? ""; + }, + weight: 1, + ), + ], + ), + ); var searchResult = fuzzy.search(string, limit); - result.addAll(searchResult.map((e) { - return AutofillSearchResultEmoticon( - e.item.shortcode!, e.item.slug, e.item, - score: e.score); - })); + result.addAll( + searchResult.map((e) { + return AutofillSearchResultEmoticon( + e.item.shortcode!, + e.item.slug, + e.item, + score: e.score, + ); + }), + ); if (result.length >= limit) { break; @@ -197,12 +240,20 @@ class AutofillSearchResultAvatar extends AutofillSearchResult { Color fallbackColor; AutofillSearchResultAvatar( - super.result, super.slug, this.image, this.fallbackColor); + super.result, + super.slug, + this.image, + this.fallbackColor, + ); } class AutofillSearchResultEmoticon extends AutofillSearchResult { Emoticon emoticon; double score; - AutofillSearchResultEmoticon(super.result, super.slug, this.emoticon, - {this.score = 0}); + AutofillSearchResultEmoticon( + super.result, + super.slug, + this.emoticon, { + this.score = 0, + }); } diff --git a/commet/lib/utils/background_tasks/background_task_manager.dart b/commet/lib/utils/background_tasks/background_task_manager.dart index 5be02867d..a3d652a43 100644 --- a/commet/lib/utils/background_tasks/background_task_manager.dart +++ b/commet/lib/utils/background_tasks/background_task_manager.dart @@ -16,8 +16,9 @@ class BackgroundTaskManager { void addTask(BackgroundTask task) { tasks.add(task); - subscriptions[task] = - task.statusChanged.listen((_) => onStatusChanged(task)); + subscriptions[task] = task.statusChanged.listen( + (_) => onStatusChanged(task), + ); } void onStatusChanged(BackgroundTask task) { @@ -67,8 +68,12 @@ class AsyncTask implements BackgroundTask { @override BackgroundTaskStatus status = BackgroundTaskStatus.running; - AsyncTask(Future Function() func, this.label, - {this.action, this.isActionReady}) { + AsyncTask( + Future Function() func, + this.label, { + this.action, + this.isActionReady, + }) { doAsyncFunc(func); } diff --git a/commet/lib/utils/common_strings.dart b/commet/lib/utils/common_strings.dart index 81ef05c88..a4a1b86cf 100644 --- a/commet/lib/utils/common_strings.dart +++ b/commet/lib/utils/common_strings.dart @@ -1,123 +1,183 @@ import 'package:intl/intl.dart'; class CommonStrings { - static String get promptReply => Intl.message("Reply", - name: "promptReply", desc: "Generic prompt to reply to a message"); - - static String get promptAddReaction => Intl.message("Add Reaction", - name: "promptAddReaction", - desc: "Generic prompt to add reaction to a message"); - - static String get promptEdit => Intl.message("Edit", - name: "promptEdit", desc: "Generic prompt to edit something"); - - static String get promptOptions => Intl.message("Options", - name: "promptOptions", - desc: - "Generic prompt for options, generally would be used to open a settings menu, extra details or similar"); - - static String get promptSettings => Intl.message("Settings", - name: "promptSettings", - desc: - "Generic prompt for settings, usually will open a settings menu or similar"); - - static String get promptNext => Intl.message("Next", - name: "promptNext", - desc: - "Generic prompt for going to the next step of an activity or flow, usually on a button"); - - static String get promptHome => Intl.message("Home", - name: "promptHome", - desc: - "Generic prompt to go home, usually will go back to a main menu, or similar"); - - static String get promptAccept => Intl.message("Accept", - name: "promptAccept", - desc: - "Generic prompt to accept something, probably a request of some kind"); - - static String get promptDismiss => Intl.message("Dismiss", - name: "promptDismiss", - desc: "Generic prompt to dismiss something, probably a popup"); - - static String get promptDecline => Intl.message("Decline", - name: "promptDecline", - desc: - "Generic prompt to decline something, probably a request of some kind"); - - static String get promptReject => Intl.message("Reject", - name: "promptReject", - desc: - "Generic prompt to reject something, probably a request of some kind"); - - static String get promptApply => Intl.message("Apply", - name: "promptApply", - desc: "Generic prompt to apply something, probably a setting"); - - static String get promptDelete => Intl.message("Delete", - name: "promptDelete", desc: "Generic prompt to delete something"); - - static String get promptDownload => Intl.message("Download", - name: "promptDownload", desc: "Generic prompt to download something"); - - static String get promptJoin => Intl.message("Join", - name: "promptJoin", desc: "Generic prompt to join a room"); - - static String get promptSubmit => Intl.message("Submit", - name: "promptSubmit", desc: "Generic prompt to submit something"); - - static String get promptContinue => Intl.message("Continue", - name: "promptContinue", - desc: "Generic prompt to continue with some action"); - - static String get promptConfirm => Intl.message("Confirm", - name: "promptConfirm", desc: "Generic prompt to confirm some action"); - - static String get promptDone => Intl.message("Done", - name: "promptDone", desc: "Generic prompt to confirm that you are done"); - - static String get promptReset => Intl.message("Reset", - name: "promptReset", desc: "Generic prompt to reset something"); - - static String get promptEnable => Intl.message("Enable", - name: "promptEnable", desc: "Generic prompt to enable something"); - - static String get promptYes => Intl.message("Yes", - name: "promptYes", - desc: - "Generic prompt to say yes to a request, probably on a confirmation dialog 'are you sure you want to do x?' 'yes' "); - - static String get promptNo => Intl.message("No", - name: "promptNo", - desc: - "Generic prompt to say no to a request, probably on a confirmation dialog 'are you sure you want to do x?' 'no' "); - - static String get promptRestore => Intl.message("Restore", - name: "promptRestore", desc: "Generic prompt to restore something"); - - static String get promptPoliteNo => Intl.message("No, thanks", - name: "promptPoliteNo", - desc: "Generic message to decline something, using nice manners :)"); - - static String get promptBack => Intl.message("Back", - desc: "Prompt text to go backwards, probably for navigation", - name: "promptBack"); - - static String get promptSearch => Intl.message("Search", - desc: - "Prompt the user to search for something, usually shown as the hint in a text box", - name: "promptSearch"); + static String get promptReply => Intl.message( + "Reply", + name: "promptReply", + desc: "Generic prompt to reply to a message", + ); + + static String get promptAddReaction => Intl.message( + "Add Reaction", + name: "promptAddReaction", + desc: "Generic prompt to add reaction to a message", + ); + + static String get promptEdit => Intl.message( + "Edit", + name: "promptEdit", + desc: "Generic prompt to edit something", + ); + + static String get promptOptions => Intl.message( + "Options", + name: "promptOptions", + desc: "Generic prompt for options, generally would be used to open a settings menu, extra details or similar", + ); + + static String get promptSettings => Intl.message( + "Settings", + name: "promptSettings", + desc: "Generic prompt for settings, usually will open a settings menu or similar", + ); + + static String get promptNext => Intl.message( + "Next", + name: "promptNext", + desc: "Generic prompt for going to the next step of an activity or flow, usually on a button", + ); + + static String get promptHome => Intl.message( + "Home", + name: "promptHome", + desc: "Generic prompt to go home, usually will go back to a main menu, or similar", + ); + + static String get promptAccept => Intl.message( + "Accept", + name: "promptAccept", + desc: "Generic prompt to accept something, probably a request of some kind", + ); + + static String get promptDismiss => Intl.message( + "Dismiss", + name: "promptDismiss", + desc: "Generic prompt to dismiss something, probably a popup", + ); + + static String get promptDecline => Intl.message( + "Decline", + name: "promptDecline", + desc: + "Generic prompt to decline something, probably a request of some kind", + ); + + static String get promptReject => Intl.message( + "Reject", + name: "promptReject", + desc: "Generic prompt to reject something, probably a request of some kind", + ); + + static String get promptApply => Intl.message( + "Apply", + name: "promptApply", + desc: "Generic prompt to apply something, probably a setting", + ); + + static String get promptDelete => Intl.message( + "Delete", + name: "promptDelete", + desc: "Generic prompt to delete something", + ); + + static String get promptDownload => Intl.message( + "Download", + name: "promptDownload", + desc: "Generic prompt to download something", + ); + + static String get promptJoin => Intl.message( + "Join", + name: "promptJoin", + desc: "Generic prompt to join a room", + ); + + static String get promptSubmit => Intl.message( + "Submit", + name: "promptSubmit", + desc: "Generic prompt to submit something", + ); + + static String get promptContinue => Intl.message( + "Continue", + name: "promptContinue", + desc: "Generic prompt to continue with some action", + ); + + static String get promptConfirm => Intl.message( + "Confirm", + name: "promptConfirm", + desc: "Generic prompt to confirm some action", + ); + + static String get promptDone => Intl.message( + "Done", + name: "promptDone", + desc: "Generic prompt to confirm that you are done", + ); + + static String get promptReset => Intl.message( + "Reset", + name: "promptReset", + desc: "Generic prompt to reset something", + ); + + static String get promptEnable => Intl.message( + "Enable", + name: "promptEnable", + desc: "Generic prompt to enable something", + ); + + static String get promptYes => Intl.message( + "Yes", + name: "promptYes", + desc: "Generic prompt to say yes to a request, probably on a confirmation dialog 'are you sure you want to do x?' 'yes' ", + ); + + static String get promptNo => Intl.message( + "No", + name: "promptNo", + desc: "Generic prompt to say no to a request, probably on a confirmation dialog 'are you sure you want to do x?' 'no' ", + ); + + static String get promptRestore => Intl.message( + "Restore", + name: "promptRestore", + desc: "Generic prompt to restore something", + ); + + static String get promptPoliteNo => Intl.message( + "No, thanks", + name: "promptPoliteNo", + desc: "Generic message to decline something, using nice manners :)", + ); + + static String get promptBack => Intl.message( + "Back", + desc: "Prompt text to go backwards, probably for navigation", + name: "promptBack", + ); + + static String get promptSearch => Intl.message( + "Search", + desc: "Prompt the user to search for something, usually shown as the hint in a text box", + name: "promptSearch", + ); static String get promptCopy => Intl.message("Copy", desc: "Prompt to copy text", name: "promptCopy"); - static String get promptCancel => Intl.message("Cancel", - desc: "Generic prompt to cancel an action, usually shown on a button", - name: "promptCancel"); + static String get promptCancel => Intl.message( + "Cancel", + desc: "Generic prompt to cancel an action, usually shown on a button", + name: "promptCancel", + ); - static String get promptRemove => Intl.message("Remove", - desc: "Generic prompt to remove something, usually shown on a button", - name: "promptRemove"); + static String get promptRemove => Intl.message( + "Remove", + desc: "Generic prompt to remove something, usually shown on a button", + name: "promptRemove", + ); static String get labelPublic => Intl.message("Public", desc: "Label for public", name: "labelPublic"); @@ -128,15 +188,21 @@ class CommonStrings { static String get labelEnabled => Intl.message("Enabled", desc: "Label for enabled", name: "labelEnabled"); - static String get labelDisabled => Intl.message("Disabled", - desc: "Label for disabled", name: "labelDisabled"); - - static String get promptCopyComplete => Intl.message("Copied!", - desc: "Prompt text for after a copy has been completed", - name: "promptCopyComplete"); - - static String get labelOr => Intl.message("Or", - desc: - "Text that is placed between two or more options: [button1] or [button2]", - name: "labelOr"); + static String get labelDisabled => Intl.message( + "Disabled", + desc: "Label for disabled", + name: "labelDisabled", + ); + + static String get promptCopyComplete => Intl.message( + "Copied!", + desc: "Prompt text for after a copy has been completed", + name: "promptCopyComplete", + ); + + static String get labelOr => Intl.message( + "Or", + desc: "Text that is placed between two or more options: [button1] or [button2]", + name: "labelOr", + ); } diff --git a/commet/lib/utils/custom_safe_area.dart b/commet/lib/utils/custom_safe_area.dart index adc7c855b..7e3244f3d 100644 --- a/commet/lib/utils/custom_safe_area.dart +++ b/commet/lib/utils/custom_safe_area.dart @@ -28,15 +28,18 @@ class _CustomSafeAreaState extends State { var query = MediaQuery.of(context); return MediaQuery( - data: query.copyWith( - viewPadding: EdgeInsets.fromLTRB( - 0, - 0, - 0, - isTextFieldFocused - ? preferences.customOnscreenKeyboardViewOffset.value - : 0)), - child: widget.child); + data: query.copyWith( + viewPadding: EdgeInsets.fromLTRB( + 0, + 0, + 0, + isTextFieldFocused + ? preferences.customOnscreenKeyboardViewOffset.value + : 0, + ), + ), + child: widget.child, + ); } void onTextFieldFocused(bool event) { diff --git a/commet/lib/utils/custom_uri.dart b/commet/lib/utils/custom_uri.dart index f0b2f7cdd..b31db25a4 100644 --- a/commet/lib/utils/custom_uri.dart +++ b/commet/lib/utils/custom_uri.dart @@ -38,14 +38,15 @@ class CustomURI { if (uri.host == "open_room") { if ([ "room_id", - "client_id" + "client_id", ].any((element) => uri!.queryParameters.containsKey(element) == false)) { return null; } return OpenRoomURI( - roomId: uri.queryParameters["room_id"]!, - clientId: uri.queryParameters["client_id"]!); + roomId: uri.queryParameters["room_id"]!, + clientId: uri.queryParameters["client_id"]!, + ); } if (uri.host == "add_widget") { @@ -57,16 +58,18 @@ class CustomURI { if (url != null) { return AddWidgetURI( - widgetUrl: Uri.decodeComponent(url), - widgetAvatarMxc: - avatar != null ? Uri.decodeComponent(avatar) : null, - widgetName: - widgetName != null ? Uri.decodeComponent(widgetName) : null, - previewMxc: preview != null && preview.startsWith("mxc") == true - ? Uri.decodeComponent(preview) - : null, - widgetType: - widgetType != null ? Uri.decodeComponent(widgetType) : null); + widgetUrl: Uri.decodeComponent(url), + widgetAvatarMxc: avatar != null ? Uri.decodeComponent(avatar) : null, + widgetName: widgetName != null + ? Uri.decodeComponent(widgetName) + : null, + previewMxc: preview != null && preview.startsWith("mxc") == true + ? Uri.decodeComponent(preview) + : null, + widgetType: widgetType != null + ? Uri.decodeComponent(widgetType) + : null, + ); } } @@ -74,30 +77,32 @@ class CustomURI { if ([ "room_id", "client_id", - "call_id" + "call_id", ].any((element) => uri!.queryParameters.containsKey(element) == false)) { return null; } return AcceptCallUri( - roomId: uri.queryParameters["room_id"]!, - callId: uri.queryParameters["call_id"]!, - clientId: uri.queryParameters["client_id"]!); + roomId: uri.queryParameters["room_id"]!, + callId: uri.queryParameters["call_id"]!, + clientId: uri.queryParameters["client_id"]!, + ); } if (uri.host == "decline_call") { if ([ "room_id", "client_id", - "call_id" + "call_id", ].any((element) => uri!.queryParameters.containsKey(element) == false)) { return null; } return DeclineCallUri( - roomId: uri.queryParameters["room_id"]!, - callId: uri.queryParameters["call_id"]!, - clientId: uri.queryParameters["client_id"]!); + roomId: uri.queryParameters["room_id"]!, + callId: uri.queryParameters["call_id"]!, + clientId: uri.queryParameters["client_id"]!, + ); } return null; @@ -113,9 +118,10 @@ class OpenRoomURI implements CustomURI { @override String toString() { return Uri( - scheme: BuildConfig.appSchema, - host: "open_room", - queryParameters: {"room_id": roomId, "client_id": clientId}).toString(); + scheme: BuildConfig.appSchema, + host: "open_room", + queryParameters: {"room_id": roomId, "client_id": clientId}, + ).toString(); } } @@ -126,23 +132,25 @@ class AddWidgetURI implements CustomURI { final String? widgetName; final String? previewMxc; - AddWidgetURI( - {required this.widgetUrl, - this.previewMxc, - this.widgetName, - this.widgetType, - this.widgetAvatarMxc}); + AddWidgetURI({ + required this.widgetUrl, + this.previewMxc, + this.widgetName, + this.widgetType, + this.widgetAvatarMxc, + }); @override String toString() { return Uri( - scheme: BuildConfig.appSchema, - host: "add_widget", - queryParameters: { - "url": widgetUrl, - if (widgetType != null) "type": widgetType, - if (widgetAvatarMxc != null) "avatar": widgetAvatarMxc!, - }).toString(); + scheme: BuildConfig.appSchema, + host: "add_widget", + queryParameters: { + "url": widgetUrl, + if (widgetType != null) "type": widgetType, + if (widgetAvatarMxc != null) "avatar": widgetAvatarMxc!, + }, + ).toString(); } } @@ -151,19 +159,23 @@ class AcceptCallUri implements CustomURI { final String clientId; final String callId; - AcceptCallUri( - {required this.roomId, required this.clientId, required this.callId}); + AcceptCallUri({ + required this.roomId, + required this.clientId, + required this.callId, + }); @override String toString() { return Uri( - scheme: BuildConfig.appSchema, - host: "accept_call", - queryParameters: { - "room_id": roomId, - "client_id": clientId, - "call_id": callId - }).toString(); + scheme: BuildConfig.appSchema, + host: "accept_call", + queryParameters: { + "room_id": roomId, + "client_id": clientId, + "call_id": callId, + }, + ).toString(); } } @@ -172,19 +184,23 @@ class DeclineCallUri implements CustomURI { final String clientId; final String callId; - DeclineCallUri( - {required this.roomId, required this.clientId, required this.callId}); + DeclineCallUri({ + required this.roomId, + required this.clientId, + required this.callId, + }); @override String toString() { return Uri( - scheme: BuildConfig.appSchema, - host: "decline_call", - queryParameters: { - "room_id": roomId, - "client_id": clientId, - "call_id": callId - }).toString(); + scheme: BuildConfig.appSchema, + host: "decline_call", + queryParameters: { + "room_id": roomId, + "client_id": clientId, + "call_id": callId, + }, + ).toString(); } } @@ -194,8 +210,9 @@ class SsoLoginUri implements CustomURI { @override String toString() { return Uri( - scheme: BuildConfig.appSchema, - host: "login", - queryParameters: {}).toString(); + scheme: BuildConfig.appSchema, + host: "login", + queryParameters: {}, + ).toString(); } } diff --git a/commet/lib/utils/database/multiple_database_server.dart b/commet/lib/utils/database/multiple_database_server.dart index 2ef4cd3b9..5b0e7f07e 100644 --- a/commet/lib/utils/database/multiple_database_server.dart +++ b/commet/lib/utils/database/multiple_database_server.dart @@ -60,7 +60,7 @@ class DatabaseIsolate { static Future start() async { Log.i("Starting database server: $isolateName"); - + connectToServer = IsolateNameServer.lookupPortByName(isolateName); if (connectToServer == null) { Isolate.spawn( diff --git a/commet/lib/utils/download_utils.dart b/commet/lib/utils/download_utils.dart index a995b5185..cd0a4ec97 100644 --- a/commet/lib/utils/download_utils.dart +++ b/commet/lib/utils/download_utils.dart @@ -81,7 +81,8 @@ class DownloadFileTask implements BackgroundTaskWithOptionalProgress { Future _doDownload() async { sub = file.onProgressChanged?.listen((downloadProgress) { - final amount = downloadProgress.downloaded.toDouble() / + final amount = + downloadProgress.downloaded.toDouble() / downloadProgress.total.toDouble(); progress = amount; @@ -92,9 +93,10 @@ class DownloadFileTask implements BackgroundTaskWithOptionalProgress { final bytes = await file.getFileData(); if (bytes != null) { destinationPath = await FilePicker.platform.saveFile( - fileName: filename, - initialDirectory: preferences.lastDownloadLocation.value, - bytes: bytes); + fileName: filename, + initialDirectory: preferences.lastDownloadLocation.value, + bytes: bytes, + ); return destinationPath != null; } else { @@ -103,8 +105,9 @@ class DownloadFileTask implements BackgroundTaskWithOptionalProgress { } destinationPath = await FilePicker.platform.saveFile( - fileName: filename, - initialDirectory: preferences.lastDownloadLocation.value); + fileName: filename, + initialDirectory: preferences.lastDownloadLocation.value, + ); if (destinationPath != null) { await file.save(destinationPath!); diff --git a/commet/lib/utils/emoji/unicode_emoji.dart b/commet/lib/utils/emoji/unicode_emoji.dart index 148c415ed..6c29edca0 100644 --- a/commet/lib/utils/emoji/unicode_emoji.dart +++ b/commet/lib/utils/emoji/unicode_emoji.dart @@ -14,50 +14,59 @@ class UnicodeEmojis { static Future> load() async { packs = List.from([ UnicodeEmoticonPack( - dataPacks: [UnicodeEmojiGroups.GROUP_0], - getLocalisedName: () => "Smileys", - identifier: "chat.commet.commetapp.internal_emoticons.group_0", - icon: Icons.emoji_emotions), + dataPacks: [UnicodeEmojiGroups.GROUP_0], + getLocalisedName: () => "Smileys", + identifier: "chat.commet.commetapp.internal_emoticons.group_0", + icon: Icons.emoji_emotions, + ), UnicodeEmoticonPack( - dataPacks: [UnicodeEmojiGroups.GROUP_1], - getLocalisedName: () => "People", - identifier: "chat.commet.commetapp.internal_emoticons.group_1", - icon: Icons.emoji_people), + dataPacks: [UnicodeEmojiGroups.GROUP_1], + getLocalisedName: () => "People", + identifier: "chat.commet.commetapp.internal_emoticons.group_1", + icon: Icons.emoji_people, + ), UnicodeEmoticonPack( - dataPacks: [UnicodeEmojiGroups.GROUP_3], - getLocalisedName: () => "Animals & Nature", - identifier: "chat.commet.commetapp.internal_emoticons.group_3", - icon: Icons.emoji_nature_rounded), + dataPacks: [UnicodeEmojiGroups.GROUP_3], + getLocalisedName: () => "Animals & Nature", + identifier: "chat.commet.commetapp.internal_emoticons.group_3", + icon: Icons.emoji_nature_rounded, + ), UnicodeEmoticonPack( - dataPacks: [UnicodeEmojiGroups.GROUP_4], - getLocalisedName: () => "Food & Drink", - identifier: "chat.commet.commetapp.internal_emoticons.group_4", - icon: Icons.emoji_food_beverage), + dataPacks: [UnicodeEmojiGroups.GROUP_4], + getLocalisedName: () => "Food & Drink", + identifier: "chat.commet.commetapp.internal_emoticons.group_4", + icon: Icons.emoji_food_beverage, + ), UnicodeEmoticonPack( - dataPacks: [UnicodeEmojiGroups.GROUP_5], - getLocalisedName: () => "Travel & Places", - identifier: "chat.commet.commetapp.internal_emoticons.group_5", - icon: Icons.emoji_transportation), + dataPacks: [UnicodeEmojiGroups.GROUP_5], + getLocalisedName: () => "Travel & Places", + identifier: "chat.commet.commetapp.internal_emoticons.group_5", + icon: Icons.emoji_transportation, + ), UnicodeEmoticonPack( - dataPacks: [UnicodeEmojiGroups.GROUP_6], - getLocalisedName: () => "Activities", - identifier: "chat.commet.commetapp.internal_emoticons.group_6", - icon: Icons.emoji_events), + dataPacks: [UnicodeEmojiGroups.GROUP_6], + getLocalisedName: () => "Activities", + identifier: "chat.commet.commetapp.internal_emoticons.group_6", + icon: Icons.emoji_events, + ), UnicodeEmoticonPack( - dataPacks: [UnicodeEmojiGroups.GROUP_7], - getLocalisedName: () => "Objects", - identifier: "chat.commet.commetapp.internal_emoticons.group_7", - icon: Icons.emoji_objects), + dataPacks: [UnicodeEmojiGroups.GROUP_7], + getLocalisedName: () => "Objects", + identifier: "chat.commet.commetapp.internal_emoticons.group_7", + icon: Icons.emoji_objects, + ), UnicodeEmoticonPack( - dataPacks: [UnicodeEmojiGroups.GROUP_8], - getLocalisedName: () => "Symbols", - identifier: "chat.commet.commetapp.internal_emoticons.group_8", - icon: Icons.emoji_symbols), + dataPacks: [UnicodeEmojiGroups.GROUP_8], + getLocalisedName: () => "Symbols", + identifier: "chat.commet.commetapp.internal_emoticons.group_8", + icon: Icons.emoji_symbols, + ), UnicodeEmoticonPack( - dataPacks: [UnicodeEmojiGroups.GROUP_9], - getLocalisedName: () => "Flags", - identifier: "chat.commet.commetapp.internal_emoticons.group_9", - icon: Icons.emoji_flags), + dataPacks: [UnicodeEmojiGroups.GROUP_9], + getLocalisedName: () => "Flags", + identifier: "chat.commet.commetapp.internal_emoticons.group_9", + icon: Icons.emoji_flags, + ), ]); for (var pack in packs!) { @@ -71,8 +80,9 @@ class UnicodeEmojis { static Future loadShortcodeData() async { if (shortcodeData == null) { - var data = - await rootBundle.loadString('assets/emoji_data/shortcodes/en.json'); + var data = await rootBundle.loadString( + 'assets/emoji_data/shortcodes/en.json', + ); shortcodeData = jsonDecode(data) as Map; } @@ -132,21 +142,25 @@ class UnicodeEmoticonPack implements EmoticonPack { final String Function() getLocalisedName; - UnicodeEmoticonPack( - {required this.getLocalisedName, - required this.dataPacks, - required this.identifier, - this.icon, - this.image}); + UnicodeEmoticonPack({ + required this.getLocalisedName, + required this.dataPacks, + required this.identifier, + this.icon, + this.image, + }); Future load() async { _emoji = List.empty(growable: true); for (var pack in dataPacks) { var emoji = List.generate( - pack.length, - (index) => UnicodeEmoticon(pack[index].unicode, - shortcode: pack[index].shortcode)); + pack.length, + (index) => UnicodeEmoticon( + pack[index].unicode, + shortcode: pack[index].shortcode, + ), + ); _emoji!.addAll(emoji); } @@ -192,29 +206,34 @@ class UnicodeEmoticonPack implements EmoticonPack { EmoticonUsage get usage => EmoticonUsage.emoji; @override - Future addEmoticon( - {required String slug, - String? shortcode, - required Uint8List data, - String? mimeType, - EmoticonUsage? usage}) { + Future addEmoticon({ + required String slug, + String? shortcode, + required Uint8List data, + String? mimeType, + EmoticonUsage? usage, + }) { throw UnimplementedError(); } @override - Future updateEmoticon( - {String? slug, - String? shortcode, - Uint8List? data, - String? mimeType, - EmoticonUsage? usage, - required Emoticon previous}) { + Future updateEmoticon({ + String? slug, + String? shortcode, + Uint8List? data, + String? mimeType, + EmoticonUsage? usage, + required Emoticon previous, + }) { throw UnimplementedError(); } @override - Future updatePack( - {EmoticonUsage? usage, String? name, Uint8List? imageData}) { + Future updatePack({ + EmoticonUsage? usage, + String? name, + Uint8List? imageData, + }) { throw UnimplementedError(); } @@ -250,14 +269,11 @@ class UnicodeEmoticon extends Emoticon { static final _u200D = String.fromCharCode(0x200D); - static final _uFE0Fg = RegExp( - r'\uFE0F', - unicode: true, - ); + static final _uFE0Fg = RegExp(r'\uFE0F', unicode: true); static String emojiToUnicode(String rawText) => toCodePoint( - !rawText.contains(_u200D) ? rawText.replaceAll(_uFE0Fg, '') : rawText, - ); + !rawText.contains(_u200D) ? rawText.replaceAll(_uFE0Fg, '') : rawText, + ); static String toCodePoint(String input, {String sep = '-'}) { var r = [], c = 0, p = 0, i = 0; @@ -265,7 +281,8 @@ class UnicodeEmoticon extends Emoticon { c = input.codeUnitAt(i++); if (p != 0) { r.add( - (0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toRadixString(16)); + (0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toRadixString(16), + ); p = 0; } else if (0xD800 <= c && c <= 0xDBFF) { p = c; diff --git a/commet/lib/utils/error_utils.dart b/commet/lib/utils/error_utils.dart index e8d291f77..8b49aec95 100644 --- a/commet/lib/utils/error_utils.dart +++ b/commet/lib/utils/error_utils.dart @@ -3,8 +3,12 @@ import 'package:commet/ui/navigation/adaptive_dialog.dart'; import 'package:flutter/widgets.dart'; class ErrorUtils { - static Future tryRun(BuildContext context, Future function(), - {Future Function()? onError, String title = "Error"}) async { + static Future tryRun( + BuildContext context, + Future function(), { + Future Function()? onError, + String title = "Error", + }) async { try { await function(); } catch (e, s) { diff --git a/commet/lib/utils/event_bus.dart b/commet/lib/utils/event_bus.dart index 4d0fc95d1..9a8409e7b 100644 --- a/commet/lib/utils/event_bus.dart +++ b/commet/lib/utils/event_bus.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:commet/client/client.dart'; import 'package:commet/client/components/message_effects/message_effect_particles.dart'; import 'package:commet/ui/molecules/overlapping_panels.dart'; @@ -12,10 +13,13 @@ class RoomOpenArgs { bool bypassSpecialRoomTypes; bool openInSpace; - RoomOpenArgs(this.roomId, this.clientId, - {this.bypassSpecialRoomTypes = false, - this.threadId, - this.openInSpace = true}); + RoomOpenArgs( + this.roomId, + this.clientId, { + this.bypassSpecialRoomTypes = false, + this.threadId, + this.openInSpace = true, + }); } class EventBus { @@ -23,15 +27,22 @@ class EventBus { static StreamController openRoom = StreamController.broadcast(); - static void doOpenRoom(String roomId, - {String? clientId, - bool bypassSpecialRoomType = false, - String? threadId, - bool openInSpace = true}) { - openRoom.add(RoomOpenArgs(roomId, clientId, + static void doOpenRoom( + String roomId, { + String? clientId, + bool bypassSpecialRoomType = false, + String? threadId, + bool openInSpace = true, + }) { + openRoom.add( + RoomOpenArgs( + roomId, + clientId, threadId: threadId, bypassSpecialRoomTypes: bypassSpecialRoomType, - openInSpace: openInSpace)); + openInSpace: openInSpace, + ), + ); } /// First string is user id, Second string is client id, third string is context room diff --git a/commet/lib/utils/exponential_backoff.dart b/commet/lib/utils/exponential_backoff.dart index 1220db41d..1366ce95d 100644 --- a/commet/lib/utils/exponential_backoff.dart +++ b/commet/lib/utils/exponential_backoff.dart @@ -1,8 +1,10 @@ import 'package:commet/debug/log.dart'; -Future exponentialBackoff(Future Function() callback, - {Duration maxDelay = const Duration(seconds: 30), - int maxRetries = 20}) async { +Future exponentialBackoff( + Future Function() callback, { + Duration maxDelay = const Duration(seconds: 30), + int maxRetries = 20, +}) async { var delay = Duration(milliseconds: 500); Log.d("Starting exponential backoff"); diff --git a/commet/lib/utils/image/lod_image.dart b/commet/lib/utils/image/lod_image.dart index b67af0cf8..fbd6df251 100644 --- a/commet/lib/utils/image/lod_image.dart +++ b/commet/lib/utils/image/lod_image.dart @@ -10,21 +10,18 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_blurhash/flutter_blurhash.dart'; -enum LODImageType { - blurhash, - thumbnail, - fullres, -} +enum LODImageType { blurhash, thumbnail, fullres } class LODImageProvider extends ImageProvider { - LODImageProvider( - {this.blurhash, - this.loadThumbnail, - this.loadFullRes, - this.thumbnailHeight, - required this.id, - this.fullResHeight, - this.autoLoadFullRes = true}); + LODImageProvider({ + this.blurhash, + this.loadThumbnail, + this.loadFullRes, + this.thumbnailHeight, + required this.id, + this.fullResHeight, + this.autoLoadFullRes = true, + }); String id; String? blurhash; String? get mimeType => completer?.mimeType; @@ -53,8 +50,12 @@ class LODImageProvider extends ImageProvider { } @override - void resolveStreamForKey(ImageConfiguration configuration, ImageStream stream, - String key, ImageErrorListener handleError) { + void resolveStreamForKey( + ImageConfiguration configuration, + ImageStream stream, + String key, + ImageErrorListener handleError, + ) { super.resolveStreamForKey(configuration, stream, key, handleError); completer = stream.completer as LODImageCompleter; @@ -63,18 +64,19 @@ class LODImageProvider extends ImageProvider { @override ImageStreamCompleter loadImage(String key, ImageDecoderCallback decode) { completer = LODImageCompleter( - blurhash: blurhash, - loadThumbnail: loadThumbnail, - loadFullRes: loadFullRes, - callback: decode, - onLODChanged: () { - _lodChangedController.add(null); - }, - hasCachedFullres: hasCachedFullres, - hasCachedThumbnail: hasCachedThumbnail, - thumbnailHeight: thumbnailHeight, - fullResHeight: fullResHeight, - autoLoadFullres: autoLoadFullRes); + blurhash: blurhash, + loadThumbnail: loadThumbnail, + loadFullRes: loadFullRes, + callback: decode, + onLODChanged: () { + _lodChangedController.add(null); + }, + hasCachedFullres: hasCachedFullres, + hasCachedThumbnail: hasCachedThumbnail, + thumbnailHeight: thumbnailHeight, + fullResHeight: fullResHeight, + autoLoadFullres: autoLoadFullRes, + ); return completer!; } @@ -122,17 +124,18 @@ class LODImageCompleter extends ImageStreamCompleter { Future? thumbnailLoading = null; StreamSubscription? appFocusStateSub; - LODImageCompleter( - {this.blurhash, - required this.callback, - this.loadThumbnail, - this.loadFullRes, - this.hasCachedFullres, - this.hasCachedThumbnail, - this.thumbnailHeight, - this.onLODChanged, - this.fullResHeight, - this.autoLoadFullres = true}) { + LODImageCompleter({ + this.blurhash, + required this.callback, + this.loadThumbnail, + this.loadFullRes, + this.hasCachedFullres, + this.hasCachedThumbnail, + this.thumbnailHeight, + this.onLODChanged, + this.fullResHeight, + this.autoLoadFullres = true, + }) { loadImages(); } @@ -158,8 +161,11 @@ class LODImageCompleter extends ImageStreamCompleter { } Future _loadBlurhash() async { - var image = - await blurHashDecodeImage(blurHash: blurhash!, width: 10, height: 10); + var image = await blurHashDecodeImage( + blurHash: blurhash!, + width: 10, + height: 10, + ); if (currentlyLoadedImage == null) { currentlyLoadedImage = LODImageType.blurhash; @@ -248,11 +254,13 @@ class LODImageCompleter extends ImageStreamCompleter { _nextFrame = await _codec!.getNextFrame(); - _emitFrame(ImageInfo( - image: _nextFrame!.image.clone(), - scale: _scale, - debugLabel: debugLabel, - )); + _emitFrame( + ImageInfo( + image: _nextFrame!.image.clone(), + scale: _scale, + debugLabel: debugLabel, + ), + ); if (_codec!.frameCount == 1) { _nextFrame!.image.dispose(); @@ -279,11 +287,13 @@ class LODImageCompleter extends ImageStreamCompleter { } assert(_nextFrame != null); if (_isFirstFrame() || _hasFrameDurationPassed(timestamp)) { - _emitFrame(ImageInfo( - image: _nextFrame!.image.clone(), - scale: _scale, - debugLabel: debugLabel, - )); + _emitFrame( + ImageInfo( + image: _nextFrame!.image.clone(), + scale: _scale, + debugLabel: debugLabel, + ), + ); _shownTimestamp = timestamp; _frameDuration = _nextFrame!.duration; _nextFrame!.image.dispose(); diff --git a/commet/lib/utils/image_utils.dart b/commet/lib/utils/image_utils.dart index 6bf6e3fd7..90df7ba32 100644 --- a/commet/lib/utils/image_utils.dart +++ b/commet/lib/utils/image_utils.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flutter/widgets.dart'; + import 'dart:ui' as ui; class ImageUtils { diff --git a/commet/lib/utils/links/executor/link_executor_open_uri.dart b/commet/lib/utils/links/executor/link_executor_open_uri.dart index 8c3959fdf..9af11c645 100644 --- a/commet/lib/utils/links/executor/link_executor_open_uri.dart +++ b/commet/lib/utils/links/executor/link_executor_open_uri.dart @@ -21,17 +21,21 @@ class LinkExecutorOpenUri extends LinkExecutor { // Uri Encode all components, to protect against weird url escapes: `https://example.com; rm -rf ~` var processed = Uri( - scheme: uri.scheme, - host: uri.host, - port: uri.port, - queryParameters: uri.queryParameters.isEmpty - ? null - : Map.fromEntries(uri.queryParameters.entries.map( - (i) => MapEntry(procComponent(i.key), procComponent(i.value)))), - pathSegments: uri.pathSegments.isEmpty - ? null - : uri.pathSegments.map((i) => procComponent(i)).toList(), - fragment: uri.fragment.isEmpty ? null : procComponent(uri.fragment)); + scheme: uri.scheme, + host: uri.host, + port: uri.port, + queryParameters: uri.queryParameters.isEmpty + ? null + : Map.fromEntries( + uri.queryParameters.entries.map( + (i) => MapEntry(procComponent(i.key), procComponent(i.value)), + ), + ), + pathSegments: uri.pathSegments.isEmpty + ? null + : uri.pathSegments.map((i) => procComponent(i)).toList(), + fragment: uri.fragment.isEmpty ? null : procComponent(uri.fragment), + ); result = result.replaceAll("\${uri}", processed.toString()); diff --git a/commet/lib/utils/links/link_utils.dart b/commet/lib/utils/links/link_utils.dart index 6ae182769..9befe1143 100644 --- a/commet/lib/utils/links/link_utils.dart +++ b/commet/lib/utils/links/link_utils.dart @@ -10,37 +10,45 @@ import 'package:flutter/widgets.dart'; import 'package:url_launcher/url_launcher.dart'; class LinkUtils { - static Future open(Uri uri, - {String? clientId, - String? contextRoomId, - BuildContext? context, - bool bypassConfirmation = false, - bool filterTrackingParameters = true}) async { + static Future open( + Uri uri, { + String? clientId, + String? contextRoomId, + BuildContext? context, + bool bypassConfirmation = false, + bool filterTrackingParameters = true, + }) async { if (context != null) { ErrorUtils.tryRun(context, () async { - await _open(uri, - clientId: clientId, - context: context, - contextRoomId: contextRoomId, - bypassConfirmation: bypassConfirmation, - filterTrackingParameters: filterTrackingParameters); - }); - } else { - await _open(uri, + await _open( + uri, clientId: clientId, context: context, contextRoomId: contextRoomId, bypassConfirmation: bypassConfirmation, - filterTrackingParameters: filterTrackingParameters); + filterTrackingParameters: filterTrackingParameters, + ); + }); + } else { + await _open( + uri, + clientId: clientId, + context: context, + contextRoomId: contextRoomId, + bypassConfirmation: bypassConfirmation, + filterTrackingParameters: filterTrackingParameters, + ); } } - static Future _open(Uri uri, - {String? clientId, - String? contextRoomId, - BuildContext? context, - bool bypassConfirmation = false, - bool filterTrackingParameters = true}) async { + static Future _open( + Uri uri, { + String? clientId, + String? contextRoomId, + BuildContext? context, + bool bypassConfirmation = false, + bool filterTrackingParameters = true, + }) async { if (uri.host == "matrix.to") { var result = MatrixClient.parseMatrixLink(uri); @@ -49,8 +57,11 @@ class LinkUtils { case MatrixLinkType.room: return EventBus.doOpenRoom(result.$3, clientId: clientId); case MatrixLinkType.user: - return EventBus.openUserProfile - .add((result.$2, clientId, contextRoomId)); + return EventBus.openUserProfile.add(( + result.$2, + clientId, + contextRoomId, + )); case MatrixLinkType.roomAlias: return EventBus.doOpenRoom(result.$3, clientId: clientId); } @@ -69,9 +80,11 @@ class LinkUtils { if (handler != null) { for (var executor in handler.executors) { if (await executor.canHandleLink(uri)) { - var confirm = await AdaptiveDialog.confirmation(context, - prompt: executor.getDescription(uri), - title: "Open in ${handler.appName}?"); + var confirm = await AdaptiveDialog.confirmation( + context, + prompt: executor.getDescription(uri), + title: "Open in ${handler.appName}?", + ); if (confirm == true) { executor.execute(openUrl); @@ -94,12 +107,14 @@ class LinkUtils { if (cleanedUrl.toString() != uri.toString()) { if (context != null) { if (!bypassConfirmation) { - var confirm = await AdaptiveDialog.confirmation(context, - title: "Open Link", - confirmationText: "Open", - cancelText: "Open Original Link", - prompt: - "This link contained trackers, which have been removed. Open `$cleanedUrl` in your browser?"); + var confirm = await AdaptiveDialog.confirmation( + context, + title: "Open Link", + confirmationText: "Open", + cancelText: "Open Original Link", + prompt: + "This link contained trackers, which have been removed. Open `$cleanedUrl` in your browser?", + ); if (confirm == null) return; @@ -113,11 +128,13 @@ class LinkUtils { } else { if (!bypassConfirmation) { if (context != null) { - if (await AdaptiveDialog.confirmation(context, - title: "Open Link", - confirmationText: "Open", - cancelText: "Cancel", - prompt: "Open `$uri` in your web browser?") != + if (await AdaptiveDialog.confirmation( + context, + title: "Open Link", + confirmationText: "Open", + cancelText: "Cancel", + prompt: "Open `$uri` in your web browser?", + ) != true) { return; } diff --git a/commet/lib/utils/links/smart_link_handler.dart b/commet/lib/utils/links/smart_link_handler.dart index b408a8cf2..0048a9a8e 100644 --- a/commet/lib/utils/links/smart_link_handler.dart +++ b/commet/lib/utils/links/smart_link_handler.dart @@ -25,14 +25,12 @@ class SmartLinkHandler { String appName; List executors; - SmartLinkHandler({ - required this.appName, - required this.executors, - }); + SmartLinkHandler({required this.appName, required this.executors}); static SmartLinkHandler? fromJson(Map data) { - Map? appNameLocalizations = - data.tryGetMap("appDisplayName"); + Map? appNameLocalizations = data.tryGetMap( + "appDisplayName", + ); String? appName = appNameLocalizations?.tryGet("en"); if (appName == null) return null; diff --git a/commet/lib/utils/links/tracking_parameters_cleaner.dart b/commet/lib/utils/links/tracking_parameters_cleaner.dart index 9e781771e..eb1ecd04a 100644 --- a/commet/lib/utils/links/tracking_parameters_cleaner.dart +++ b/commet/lib/utils/links/tracking_parameters_cleaner.dart @@ -14,7 +14,9 @@ class UrlTrackingParametersCleaner { for (var key in providers.entries) { parameterRules[key.key] = UrlParameterRule.fromJson( - key.value as Map, key.key)!; + key.value as Map, + key.key, + )!; } } @@ -132,8 +134,9 @@ class UrlParameterRule { host: result.host, port: result.port, path: result.path, - queryParameters: - result.queryParameters.isEmpty ? null : result.queryParameters, + queryParameters: result.queryParameters.isEmpty + ? null + : result.queryParameters, fragment: result.fragment.isEmpty ? null : result.fragment, ); } diff --git a/commet/lib/utils/list_extension.dart b/commet/lib/utils/list_extension.dart index 9545ce966..38952c532 100644 --- a/commet/lib/utils/list_extension.dart +++ b/commet/lib/utils/list_extension.dart @@ -1,9 +1,7 @@ extension ListExtension on List { T? tryFirstWhere(bool Function(T element) test) { try { - return firstWhere( - test, - ); + return firstWhere(test); } catch (exception) { return null; } diff --git a/commet/lib/utils/mime.dart b/commet/lib/utils/mime.dart index f74bd9731..cec188785 100644 --- a/commet/lib/utils/mime.dart +++ b/commet/lib/utils/mime.dart @@ -11,7 +11,7 @@ class Mime { "image/png", "image/gif", "image/bmp", - "image/webp" + "image/webp", }; static const imageTypes = { @@ -22,10 +22,7 @@ class Mime { "image/bmp", }; - static const gifTypes = { - "image/gif", - "image/webp", - }; + static const gifTypes = {"image/gif", "image/webp"}; static const playableAudioTypes = { "audio/x-wav", @@ -43,7 +40,7 @@ class Mime { "video/mp4", "video/mpeg", "video/webm", - "video/quicktime" + "video/quicktime", }; static const videoStreamTypes = {"application/vnd.apple.mpegurl"}; @@ -52,7 +49,7 @@ class Mime { "application/x-7z-compressed", "application/x-bzip", "application/x-bzip2", - "application/gzip" + "application/gzip", }; static const extensionToMime = { @@ -61,7 +58,7 @@ class Mime { "png": "image/png", "gif": "image/gif", "webp": "image/webp", - "bmp": "image/bmp" + "bmp": "image/bmp", }; static String? fromExtenstion(String extension) { diff --git a/commet/lib/utils/notification_utils.dart b/commet/lib/utils/notification_utils.dart index c4716dc86..1bac0703f 100644 --- a/commet/lib/utils/notification_utils.dart +++ b/commet/lib/utils/notification_utils.dart @@ -5,8 +5,9 @@ class NotificationUtils { var highlightedNotificationCount = 0; var notificationCount = 0; - var topLevelSpaces = - clientManager!.spaces.where((e) => e.isTopLevel).toList(); + var topLevelSpaces = clientManager!.spaces + .where((e) => e.isTopLevel) + .toList(); for (var i in topLevelSpaces) { highlightedNotificationCount += i.displayHighlightedNotificationCount; diff --git a/commet/lib/utils/notifying_list.dart b/commet/lib/utils/notifying_list.dart index 1d2cd6ac9..a3bb44986 100644 --- a/commet/lib/utils/notifying_list.dart +++ b/commet/lib/utils/notifying_list.dart @@ -92,8 +92,11 @@ class NotifyingList implements INotifyingList { return NotifyingList._internal(internalList, sync); } - factory NotifyingList.from(Iterable elements, - {bool growable = false, bool sync = true}) { + factory NotifyingList.from( + Iterable elements, { + bool growable = false, + bool sync = true, + }) { List internalList = List.from(elements, growable: growable); return NotifyingList._internal(internalList, sync); } diff --git a/commet/lib/utils/notifying_list_combiner.dart b/commet/lib/utils/notifying_list_combiner.dart index fd68ff634..e896b2c3f 100644 --- a/commet/lib/utils/notifying_list_combiner.dart +++ b/commet/lib/utils/notifying_list_combiner.dart @@ -10,8 +10,9 @@ class NotifyingListCombiner implements INotifyingList { List subs = List.empty(growable: true); NotifyingListCombiner(List> baseLists) { - this._internalList = - NotifyingList.from([for (var i in baseLists) ...i], growable: true); + this._internalList = NotifyingList.from([ + for (var i in baseLists) ...i, + ], growable: true); for (var item in baseLists) { subs.addAll([ diff --git a/commet/lib/utils/notifying_list_filter.dart b/commet/lib/utils/notifying_list_filter.dart index f05f77415..53206af6d 100644 --- a/commet/lib/utils/notifying_list_filter.dart +++ b/commet/lib/utils/notifying_list_filter.dart @@ -12,15 +12,19 @@ class NotifyingListFilter implements INotifyingList { late List subs; - NotifyingListFilter(INotifyingList base, - {required bool Function(T item) where, - List? onFilterParamsChanged}) { + NotifyingListFilter( + INotifyingList base, { + required bool Function(T item) where, + List? onFilterParamsChanged, + }) { this._baseList = base; this.whereFunction = where; - this._internalList = - NotifyingList.from(base.where(whereFunction), growable: true); + this._internalList = NotifyingList.from( + base.where(whereFunction), + growable: true, + ); subs = [ _baseList.onRemove.listen(_onBaseItemRemoved), diff --git a/commet/lib/utils/notifying_list_mapped.dart b/commet/lib/utils/notifying_list_mapped.dart index d690a69e1..960de8b46 100644 --- a/commet/lib/utils/notifying_list_mapped.dart +++ b/commet/lib/utils/notifying_list_mapped.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:math'; + import 'package:commet/utils/notifying_list.dart'; class NotifyingListMapped implements INotifyingList { @@ -11,9 +12,10 @@ class NotifyingListMapped implements INotifyingList { late List subs; - NotifyingListMapped( - {required NotifyingList baseList, - required List Function(R value) map}) { + NotifyingListMapped({ + required NotifyingList baseList, + required List Function(R value) map, + }) { this.mapFunction = map; this._baseList = baseList; @@ -369,13 +371,17 @@ class NotifyingListMapped implements INotifyingList { final mapped = mapFunction(event); if (mapped case INotifyingList n) { - subs.add(n.onAdd.listen((d) { - _internalList.add(d); - })); - - subs.add(n.onRemove.listen((d) { - _internalList.remove(d); - })); + subs.add( + n.onAdd.listen((d) { + _internalList.add(d); + }), + ); + + subs.add( + n.onRemove.listen((d) { + _internalList.remove(d); + }), + ); } _internalList.addAll(mapped); diff --git a/commet/lib/utils/overlay.dart b/commet/lib/utils/overlay.dart index e244e2354..545a4c354 100644 --- a/commet/lib/utils/overlay.dart +++ b/commet/lib/utils/overlay.dart @@ -24,27 +24,27 @@ class VoipOverlay { var exe = Platform.resolvedExecutable; - var process = await Process.start(exe, [ - '--overlay', - ]); + var process = await Process.start(exe, ['--overlay']); var runner = MatrixUserWidgetSubprocessRunner( - process: process, - room: room as MatrixRoom, - context: context, - widgetId: widgetId, - hidden: true, - privileged: true, - info: MatrixUserWidgetInfo( - id: widgetId, - name: "Overlay", - stateKey: "", - url: "", - type: widgetId, - icon: ImageOrIcon(icon: Icons.screen_share), - roomId: room.identifier, - event: StrippedStateEvent(type: "", content: {}, senderId: "")), - client: room.client as MatrixClient); + process: process, + room: room as MatrixRoom, + context: context, + widgetId: widgetId, + hidden: true, + privileged: true, + info: MatrixUserWidgetInfo( + id: widgetId, + name: "Overlay", + stateKey: "", + url: "", + type: widgetId, + icon: ImageOrIcon(icon: Icons.screen_share), + roomId: room.identifier, + event: StrippedStateEvent(type: "", content: {}, senderId: ""), + ), + client: room.client as MatrixClient, + ); (component as MatrixWidgetComponent).registerRunner(runner); diff --git a/commet/lib/utils/picker_utils.dart b/commet/lib/utils/picker_utils.dart index 4042b5cab..e694db80e 100644 --- a/commet/lib/utils/picker_utils.dart +++ b/commet/lib/utils/picker_utils.dart @@ -35,8 +35,10 @@ class PickerUtils { return null; } - static Future pickImageAndCrop(BuildContext context, - {double? aspectRatio}) async { + static Future pickImageAndCrop( + BuildContext context, { + double? aspectRatio, + }) async { var image = await pickImage(); if (image == null) return null; @@ -52,21 +54,28 @@ class PickerUtils { var uiImage = await ImageUtils.imageProviderToImage(imageProvider); var ratio = uiImage.width.toDouble() / uiImage.height.toDouble(); - var result = await tiamat.PopupDialog.show(context, - content: ImageCropView( - bytes, - controller, - ratio, - onImageSubmitted: (data) => Navigator.of(context).pop(data), - )); + var result = await tiamat.PopupDialog.show( + context, + content: ImageCropView( + bytes, + controller, + ratio, + onImageSubmitted: (data) => Navigator.of(context).pop(data), + ), + ); return result; } } class ImageCropView extends StatelessWidget { - const ImageCropView(this.imageBytes, this.controller, this.imageAspectRatio, - {this.onImageSubmitted, super.key}); + const ImageCropView( + this.imageBytes, + this.controller, + this.imageAspectRatio, { + this.onImageSubmitted, + super.key, + }); final CropController controller; final Uint8List imageBytes; @@ -77,9 +86,11 @@ class ImageCropView extends StatelessWidget { final double width = 1000; - String get useWithoutCroppingPrompt => Intl.message("Use Without Cropping", - name: "useWithoutCroppingPrompt", - desc: "Button text for using an image without cropping it"); + String get useWithoutCroppingPrompt => Intl.message( + "Use Without Cropping", + name: "useWithoutCroppingPrompt", + desc: "Button text for using an image without cropping it", + ); @override Widget build(BuildContext context) { @@ -118,18 +129,17 @@ class ImageCropView extends StatelessWidget { child: SizedBox( width: 1000, child: AspectRatio( - aspectRatio: imageAspectRatio, - child: Container( - child: CropImage( - image: Image.memory(imageBytes), - controller: controller, - ), - )), + aspectRatio: imageAspectRatio, + child: Container( + child: CropImage( + image: Image.memory(imageBytes), + controller: controller, + ), + ), + ), ), ), - SizedBox( - height: 20, - ), + SizedBox(height: 20), Column( mainAxisSize: MainAxisSize.min, children: [ @@ -139,36 +149,39 @@ class ImageCropView extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ SizedBox( - height: 50, - width: 50, - child: tiamat.IconButton( - icon: Icons.rotate_90_degrees_ccw, - onPressed: () => controller.rotateLeft(), - size: 30, - )), + height: 50, + width: 50, + child: tiamat.IconButton( + icon: Icons.rotate_90_degrees_ccw, + onPressed: () => controller.rotateLeft(), + size: 30, + ), + ), SizedBox( - height: 50, - width: 50, - child: tiamat.IconButton( - icon: Icons.rotate_90_degrees_cw, - size: 30, - onPressed: () => controller.rotateRight(), - )) + height: 50, + width: 50, + child: tiamat.IconButton( + icon: Icons.rotate_90_degrees_cw, + size: 30, + onPressed: () => controller.rotateRight(), + ), + ), ], ), ), if (MediaQuery.of(context).desktop) Row( - spacing: 8, - mainAxisSize: MainAxisSize.max, - children: buttons), + spacing: 8, + mainAxisSize: MainAxisSize.max, + children: buttons, + ), if (MediaQuery.of(context).mobile) Column( spacing: 8, mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: buttons, - ) + ), ], ), ], diff --git a/commet/lib/utils/rng.dart b/commet/lib/utils/rng.dart index f23207188..6e6434bfe 100644 --- a/commet/lib/utils/rng.dart +++ b/commet/lib/utils/rng.dart @@ -3,14 +3,17 @@ import 'dart:math'; class RandomUtils { static const _chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890'; - static final _words = - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." - .split(' '); + static final _words = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + .split(' '); static String getRandomString(int length) { Random rnd = Random(); - return String.fromCharCodes(Iterable.generate( - length, (_) => _chars.codeUnitAt(rnd.nextInt(_chars.length)))); + return String.fromCharCodes( + Iterable.generate( + length, + (_) => _chars.codeUnitAt(rnd.nextInt(_chars.length)), + ), + ); } static String getRandomSentence(int length, {int? seed}) { diff --git a/commet/lib/utils/scaled_app.dart b/commet/lib/utils/scaled_app.dart index cf9fd490f..a500bc4c3 100644 --- a/commet/lib/utils/scaled_app.dart +++ b/commet/lib/utils/scaled_app.dart @@ -2,6 +2,7 @@ import 'dart:async' show scheduleMicrotask, Timer; import 'dart:collection' show Queue; import 'dart:ui' show PointerDataPacket; + import 'package:flutter/rendering.dart' show RenderView, ViewConfiguration; import 'package:flutter/gestures.dart' show FlutterView, PointerEventConverter; import 'package:flutter/widgets.dart'; @@ -33,7 +34,7 @@ class ScaledWidgetsFlutterBinding extends WidgetsFlutterBinding { ScaleFactorCallback? _scaleFactor; ScaledWidgetsFlutterBinding._({ScaleFactorCallback? scaleFactor}) - : _scaleFactor = scaleFactor; + : _scaleFactor = scaleFactor; ScaleFactorCallback get scaleFactor => _scaleFactor ?? (_) => 1.0; @@ -112,23 +113,25 @@ class ScaledWidgetsFlutterBinding extends WidgetsFlutterBinding { // We convert pointer data to logical pixels so that e.g. the touch slop can be // defined in a device-independent manner. try { - _pendingPointerEvents.addAll(PointerEventConverter.expand( - packet.data, - (viewId) { + _pendingPointerEvents.addAll( + PointerEventConverter.expand(packet.data, (viewId) { return devicePixelRatioScaled; - }, - )); + }), + ); if (!locked) { _flushPointerEventQueue(); } } catch (error, stack) { - FlutterError.reportError(FlutterErrorDetails( - exception: error, - stack: stack, - library: 'gestures library', - context: - ErrorDescription('while handling a scaled pointer data packet'), - )); + FlutterError.reportError( + FlutterErrorDetails( + exception: error, + stack: stack, + library: 'gestures library', + context: ErrorDescription( + 'while handling a scaled pointer data packet', + ), + ), + ); } } diff --git a/commet/lib/utils/shortcuts_manager.dart b/commet/lib/utils/shortcuts_manager.dart index 89345e960..850fd7aa5 100644 --- a/commet/lib/utils/shortcuts_manager.dart +++ b/commet/lib/utils/shortcuts_manager.dart @@ -12,16 +12,13 @@ import 'package:commet/utils/event_bus.dart'; import 'package:commet/utils/image/lod_image.dart'; import 'package:commet/utils/image_utils.dart'; import 'package:flutter/material.dart'; + import 'dart:ui' as ui; import 'package:flutter_shortcuts_new/flutter_shortcuts_new.dart'; import 'package:image/image.dart' as img; -enum ShortcutIconFormat { - jpeg, - png, - rawRgba, -} +enum ShortcutIconFormat { jpeg, png, rawRgba } class ShortcutsManager { FlutterShortcuts? shortcuts; @@ -33,8 +30,9 @@ class ShortcutsManager { loading = shortcuts!.initialize(debug: true); EventBus.onSelectedRoomChanged.stream.listen(onRoomOpenedInUI); - shortcuts! - .listenAction((action) => Log.i("Received shortcut action: $action")); + shortcuts!.listenAction( + (action) => Log.i("Received shortcut action: $action"), + ); } } @@ -42,12 +40,13 @@ class ShortcutsManager { if (loading != null) await loading; var cachedAvatar = await getCachedAvatarImage( - identifier: room.identifier, - placeholderColor: room.defaultColor, - placeholderText: room.displayName, - format: ShortcutIconFormat.jpeg, - doCircleMask: false, - imageProvider: await room.getShortcutImage()); + identifier: room.identifier, + placeholderColor: room.defaultColor, + placeholderText: room.displayName, + format: ShortcutIconFormat.jpeg, + doCircleMask: false, + imageProvider: await room.getShortcutImage(), + ); String? icon; if (cachedAvatar != null) { @@ -57,14 +56,16 @@ class ShortcutsManager { } var item = ShortcutItem( - id: room.identifier, - action: OpenRoomURI( - roomId: room.identifier, clientId: room.client.identifier) - .toString(), - shortLabel: room.displayName, - icon: icon, - shortcutIconAsset: ShortcutIconAsset.memoryAsset, - conversationShortcut: true); + id: room.identifier, + action: OpenRoomURI( + roomId: room.identifier, + clientId: room.client.identifier, + ).toString(), + shortLabel: room.displayName, + icon: icon, + shortcutIconAsset: ShortcutIconAsset.memoryAsset, + conversationShortcut: true, + ); await shortcuts?.pushShortcutItem(shortcut: item); } @@ -81,15 +82,16 @@ class ShortcutsManager { await createShortcutForRoom(event); } - static Future getCachedAvatarImage( - {required Color placeholderColor, - required String placeholderText, - required String identifier, - required ShortcutIconFormat format, - String? imageId, - ImageProvider? imageProvider, - bool shouldZoomOut = true, - bool doCircleMask = true}) async { + static Future getCachedAvatarImage({ + required Color placeholderColor, + required String placeholderText, + required String identifier, + required ShortcutIconFormat format, + String? imageId, + ImageProvider? imageProvider, + bool shouldZoomOut = true, + bool doCircleMask = true, + }) async { String avatarId = "shortcutAvatar_$identifier"; if (imageProvider == null) { @@ -125,18 +127,20 @@ class ShortcutsManager { if (isHeadless) { Log.i( - "Failed to find cached image, we are headless so continuing with no image"); + "Failed to find cached image, we are headless so continuing with no image", + ); return null; } Log.i("Cache miss, generating image"); var image = await createAvatarImage( - placeholderColor: placeholderColor, - placeholderText: placeholderText, - imageProvider: imageProvider, - doCircleMask: doCircleMask, - shouldZoomOut: shouldZoomOut); + placeholderColor: placeholderColor, + placeholderText: placeholderText, + imageProvider: imageProvider, + doCircleMask: doCircleMask, + shouldZoomOut: shouldZoomOut, + ); late Uint8List data; @@ -144,17 +148,17 @@ class ShortcutsManager { case ShortcutIconFormat.jpeg: var bytes = await image.toByteData(format: ImageByteFormat.rawRgba); var finalImage = img.Image.fromBytes( - width: image.width, - height: image.height, - bytes: bytes!.buffer, - format: img.Format.uint8, - numChannels: 4, - order: img.ChannelOrder.rgba); + width: image.width, + height: image.height, + bytes: bytes!.buffer, + format: img.Format.uint8, + numChannels: 4, + order: img.ChannelOrder.rgba, + ); data = img.encodeJpg(finalImage); break; case ShortcutIconFormat.png: - data = (await image.toByteData(format: ImageByteFormat.png))! - .buffer + data = (await image.toByteData(format: ImageByteFormat.png))!.buffer .asUint8List(); break; case ShortcutIconFormat.rawRgba: @@ -167,12 +171,13 @@ class ShortcutsManager { return cachedAvatar; } - static Future createAvatarImage( - {required Color placeholderColor, - required String placeholderText, - ImageProvider? imageProvider, - bool shouldZoomOut = true, - bool doCircleMask = true}) async { + static Future createAvatarImage({ + required Color placeholderColor, + required String placeholderText, + ImageProvider? imageProvider, + bool shouldZoomOut = true, + bool doCircleMask = true, + }) async { PictureRecorder recorder = PictureRecorder(); Canvas c = Canvas(recorder); @@ -183,7 +188,9 @@ class ShortcutsManager { double scale = 0.7; c.scale(scale); c.translate( - (size.width * 1 / scale) * 0.5, (size.height * 1 / scale) * 0.5); + (size.width * 1 / scale) * 0.5, + (size.height * 1 / scale) * 0.5, + ); c.translate(-size.width / 2, -size.height / 2); } @@ -199,21 +206,21 @@ class ShortcutsManager { var smallestDimension = min(image.width, image.height).toDouble(); c.drawImageRect( - image, - Rect.fromCenter( - center: Offset( - image.width.toDouble() / 2, image.height.toDouble() / 2), - width: smallestDimension, - height: smallestDimension), - Rect.fromCenter( - center: center, width: size.width, height: size.height), - Paint()..filterQuality = FilterQuality.medium); + image, + Rect.fromCenter( + center: Offset( + image.width.toDouble() / 2, + image.height.toDouble() / 2, + ), + width: smallestDimension, + height: smallestDimension, + ), + Rect.fromCenter(center: center, width: size.width, height: size.height), + Paint()..filterQuality = FilterQuality.medium, + ); } else { c.drawColor(placeholderColor, BlendMode.dstATop); - const textStyle = TextStyle( - color: Colors.white, - fontSize: 50, - ); + const textStyle = TextStyle(color: Colors.white, fontSize: 50); final textSpan = TextSpan( text: placeholderText.characters.first.toUpperCase(), style: textStyle, @@ -222,10 +229,7 @@ class ShortcutsManager { text: textSpan, textDirection: TextDirection.ltr, ); - textPainter.layout( - minWidth: 0, - maxWidth: size.width, - ); + textPainter.layout(minWidth: 0, maxWidth: size.width); final xCenter = (size.width - textPainter.width) / 2; final yCenter = (size.height - textPainter.height) / 2; final offset = Offset(xCenter, yCenter); @@ -244,14 +248,16 @@ class ShortcutsManager { ..blendMode = BlendMode.dstOut; c.drawArc( - Rect.fromCenter( - center: center, - width: size.height + width, - height: size.height + width), - 0, - 360, - false, - paint); + Rect.fromCenter( + center: center, + width: size.height + width, + height: size.height + width, + ), + 0, + 360, + false, + paint, + ); } var pic = recorder.endRecording(); @@ -261,7 +267,9 @@ class ShortcutsManager { } static Future combineRoomAndUserImages( - ui.Image roomImage, ui.Image userImage) async { + ui.Image roomImage, + ui.Image userImage, + ) async { var recorder = ui.PictureRecorder(); Canvas c = Canvas(recorder); @@ -272,7 +280,11 @@ class ShortcutsManager { var roomSize = circleSize * 0.8; var targetRect = Rect.fromLTWH( - size.width - roomSize, size.height - roomSize, roomSize, roomSize); + size.width - roomSize, + size.height - roomSize, + roomSize, + roomSize, + ); var path = Path(); path.addArc(targetRect, 0, 90); c.drawShadow(path.shift(Offset(-5, -5)), Color(0xff000000), 6, true); @@ -281,11 +293,16 @@ class ShortcutsManager { var userRect = Rect.fromLTWH(0, 0, userSize, userSize); c.drawImageRect( - roomImage, - Rect.fromLTWH( - 0, 0, roomImage.width.toDouble(), roomImage.height.toDouble()), - targetRect, - Paint()); + roomImage, + Rect.fromLTWH( + 0, + 0, + roomImage.width.toDouble(), + roomImage.height.toDouble(), + ), + targetRect, + Paint(), + ); var userPath = Path(); userPath.addArc(userRect, 0, 360); @@ -294,11 +311,16 @@ class ShortcutsManager { c.drawShadow(userPath.shift(Offset(5, 5)), Color(0xff000000), 5, true); c.drawImageRect( - userImage, - Rect.fromLTWH( - 0, 0, userImage.width.toDouble(), userImage.height.toDouble()), - userRect, - Paint()); + userImage, + Rect.fromLTWH( + 0, + 0, + userImage.width.toDouble(), + userImage.height.toDouble(), + ), + userRect, + Paint(), + ); var pic = recorder.endRecording(); var img = await pic.toImage(size.width.round(), size.height.round()); diff --git a/commet/lib/utils/stream_utils.dart b/commet/lib/utils/stream_utils.dart index 81acede1d..232e4ce74 100644 --- a/commet/lib/utils/stream_utils.dart +++ b/commet/lib/utils/stream_utils.dart @@ -4,11 +4,9 @@ extension StreamUtils on Stream { Future nextItemAsFuture() { Completer completer = Completer(); - listen( - (event) { - completer.complete(event); - }, - ); + listen((event) { + completer.complete(event); + }); return completer.future; } diff --git a/commet/lib/utils/system_processes_utils.dart b/commet/lib/utils/system_processes_utils.dart index 615a9958a..8d4ad534b 100644 --- a/commet/lib/utils/system_processes_utils.dart +++ b/commet/lib/utils/system_processes_utils.dart @@ -11,8 +11,13 @@ class SystemProcessesUtils { } if (BuildConfig.IS_FLATPAK) { - var result = await Process.run( - "flatpak-spawn", ["--host", "ps", "-e", "-o", "pid,command"]); + var result = await Process.run("flatpak-spawn", [ + "--host", + "ps", + "-e", + "-o", + "pid,command", + ]); return parseLinuxPS(result.stdout); } @@ -37,8 +42,11 @@ class SystemProcessesUtils { } Log.i("Spawning subprocess: ${name} ${args}"); - var result = - await Process.start("flatpak-spawn", ["--host", name, ...args]); + var result = await Process.start("flatpak-spawn", [ + "--host", + name, + ...args, + ]); return result; } @@ -49,12 +57,17 @@ class SystemProcessesUtils { } static Future runSubprocess( - String name, List args) async { + String name, + List args, + ) async { Log.i("Spawning subprocess: ${name} ${args}"); if (BuildConfig.IS_FLATPAK) { - var result = - await Process.run("flatpak-spawn", ["--host", name, ...args]); + var result = await Process.run("flatpak-spawn", [ + "--host", + name, + ...args, + ]); return result; } @@ -96,6 +109,9 @@ class ProcessInfo { final String command; final List args; - ProcessInfo( - {required this.processId, required this.command, this.args = const []}); + ProcessInfo({ + required this.processId, + required this.command, + this.args = const [], + }); } diff --git a/commet/lib/utils/system_wide_shortcuts/system_wide_shortcuts.dart b/commet/lib/utils/system_wide_shortcuts/system_wide_shortcuts.dart index 19c18abb3..809d761b9 100644 --- a/commet/lib/utils/system_wide_shortcuts/system_wide_shortcuts.dart +++ b/commet/lib/utils/system_wide_shortcuts/system_wide_shortcuts.dart @@ -32,29 +32,37 @@ class SystemWideShortcuts { return false; } - static String get shortcutNameMute => Intl.message("Mute", - name: "shortcutNameMute", - desc: "name for the system wide shortcut to activate microphone mute"); - - static String get shortcutNameUnmute => Intl.message("Unmute", - name: "shortcutNameUnmute", - desc: "name for the system wide shortcut to disable microphone mute"); - - static String get shortcutNameToggleMute => Intl.message("Toggle Mute", - name: "shortcutNameToggleMute", - desc: - "name for the system wide shortcut to toggle the microphone mute status"); + static String get shortcutNameMute => Intl.message( + "Mute", + name: "shortcutNameMute", + desc: "name for the system wide shortcut to activate microphone mute", + ); + + static String get shortcutNameUnmute => Intl.message( + "Unmute", + name: "shortcutNameUnmute", + desc: "name for the system wide shortcut to disable microphone mute", + ); + + static String get shortcutNameToggleMute => Intl.message( + "Toggle Mute", + name: "shortcutNameToggleMute", + desc: "name for the system wide shortcut to toggle the microphone mute status", + ); static Map shortcuts = { "mute": AppShortcut( - getDisplayName: () => shortcutNameMute, - callback: () => clientManager?.callManager.mute()), + getDisplayName: () => shortcutNameMute, + callback: () => clientManager?.callManager.mute(), + ), "unmute": AppShortcut( - getDisplayName: () => shortcutNameUnmute, - callback: () => clientManager?.callManager.unmute()), + getDisplayName: () => shortcutNameUnmute, + callback: () => clientManager?.callManager.unmute(), + ), "toggle_mute": AppShortcut( - getDisplayName: () => shortcutNameToggleMute, - callback: () => clientManager?.callManager.toggleMute()), + getDisplayName: () => shortcutNameToggleMute, + callback: () => clientManager?.callManager.toggleMute(), + ), }; static Future storeHotkeys() async { @@ -71,10 +79,7 @@ class AppShortcut { HotKey? hotkey; - AppShortcut({ - required this.getDisplayName, - required this.callback, - }); + AppShortcut({required this.getDisplayName, required this.callback}); Future setHotkey(HotKey newHotkey) async { if (hotkey != null) { diff --git a/commet/lib/utils/text_scale_changer.dart b/commet/lib/utils/text_scale_changer.dart index 78b36121f..725c12ad0 100644 --- a/commet/lib/utils/text_scale_changer.dart +++ b/commet/lib/utils/text_scale_changer.dart @@ -24,8 +24,9 @@ class _TextScaleChangerState extends State { } return MediaQuery( - data: MediaQuery.of(context).copyWith( - textScaler: TextScaler.linear(preferences.textScale.value)), - child: widget.child); + data: MediaQuery.of(context) + .copyWith(textScaler: TextScaler.linear(preferences.textScale.value)), + child: widget.child, + ); } } diff --git a/commet/lib/utils/text_utils.dart b/commet/lib/utils/text_utils.dart index aad0547de..a15dcaa3b 100644 --- a/commet/lib/utils/text_utils.dart +++ b/commet/lib/utils/text_utils.dart @@ -4,7 +4,9 @@ import 'package:commet/client/matrix/matrix_client.dart'; import 'package:commet/main.dart'; import 'package:commet/ui/atoms/rich_text/spans/link.dart'; import 'package:flutter/material.dart'; + import 'emoji/emoji_matcher.dart'; + import 'package:intl/intl.dart' as intl; import 'package:flutter/material.dart' as material; @@ -47,21 +49,25 @@ class TextUtils { return _urlRegex.hasMatch(text); } - static List linkifyString(String text, - {TextStyle? style, - required BuildContext context, - required String clientId}) { + static List linkifyString( + String text, { + TextStyle? style, + required BuildContext context, + required String clientId, + }) { var matches = _urlRegex.allMatches(text); return formatMatches( matches, text, style: style, builder: (matchedText, theme) { - return LinkSpan.create(matchedText, - clientId: clientId, - context: context, - destination: Uri.parse(matchedText), - style: style); + return LinkSpan.create( + matchedText, + clientId: clientId, + context: context, + destination: Uri.parse(matchedText), + style: style, + ); }, ); } @@ -83,10 +89,11 @@ class TextUtils { } static List formatMatches( - Iterable matches, String text, - {required InlineSpan Function(String matchedText, TextStyle? theme) - builder, - TextStyle? style}) { + Iterable matches, + String text, { + required InlineSpan Function(String matchedText, TextStyle? theme) builder, + TextStyle? style, + }) { if (matches.isEmpty) return [TextSpan(text: text, style: style)]; List span = List.empty(growable: true); @@ -139,7 +146,8 @@ class TextUtils { if (forceSpecialCharacter) { if (!password.characters.any( - (char) => ("!@#\$%^&*()_+`{}|:\"<>?/.,';][=-\\").contains(char))) { + (char) => ("!@#\$%^&*()_+`{}|:\"<>?/.,';][=-\\").contains(char), + )) { return NewPasswordResult.noSymbols; } } @@ -227,11 +235,14 @@ class TextUtils { static String toHexString(Uint8List bytes) { return bytes.fold( - '', (str, byte) => str + byte.toRadixString(16).padLeft(2, '0')); + '', + (str, byte) => str + byte.toRadixString(16).padLeft(2, '0'), + ); } static Uint8List parseHexString(String hexString) => Uint8List.fromList( - (RegExp(r'.{1,2}').allMatches(hexString).toList()).map((byte) { - return int.parse(byte.group(0)!, radix: 16); - }).toList()); + (RegExp(r'.{1,2}').allMatches(hexString).toList()).map((byte) { + return int.parse(byte.group(0)!, radix: 16); + }).toList(), + ); } diff --git a/commet/lib/utils/update_checker.dart b/commet/lib/utils/update_checker.dart index 819f09956..9a16268b1 100644 --- a/commet/lib/utils/update_checker.dart +++ b/commet/lib/utils/update_checker.dart @@ -18,16 +18,18 @@ import 'package:http/http.dart' as http; class UpdateChecker { static bool foundUpdate = false; - static String get labelUpdateAvailable => Intl.message("Update Available", - name: "labelUpdateAvailable", - desc: "Label for the the info popup when an update is available"); + static String get labelUpdateAvailable => Intl.message( + "Update Available", + name: "labelUpdateAvailable", + desc: "Label for the the info popup when an update is available", + ); static String descriptionUpdateAvailable(String version) => Intl.message( - "There is a newer version of Commet available: ${version}", - name: "descriptionUpdateAvailable", - args: [version], - desc: - "describes the update, showing the version code for the available update"); + "There is a newer version of Commet available: ${version}", + name: "descriptionUpdateAvailable", + args: [version], + desc: "describes the update, showing the version code for the available update", + ); static Future checkForUpdates() async { if (foundUpdate) return; @@ -43,7 +45,8 @@ class UpdateChecker { const key = "chat.commet.published_version"; var url = Uri.parse( - "https://data.commet.chat/_matrix/federation/v1/query/profile?user_id=@updates:data.commet.chat"); + "https://data.commet.chat/_matrix/federation/v1/query/profile?user_id=@updates:data.commet.chat", + ); var response = await http.get(url); @@ -65,13 +68,18 @@ class UpdateChecker { Log.i("Supports auto update: $canAutoUpdate"); if (time.isAfter(BuildConfig.BUILD_DATE)) { var tag = fields[key]; - clientManager!.alertManager.addAlert(Alert(AlertType.info, + clientManager!.alertManager.addAlert( + Alert( + AlertType.info, messageGetter: () => descriptionUpdateAvailable(tag), titleGetter: () => labelUpdateAvailable, - action: (context) => doUpdateAction(context, canAutoUpdate))); + action: (context) => doUpdateAction(context, canAutoUpdate), + ), + ); } else { Log.i( - "Found an update, but it's build date is not after the current build, current: ${BuildConfig.BUILD_DATE.toString()} remote: ${time.toString()}"); + "Found an update, but it's build date is not after the current build, current: ${BuildConfig.BUILD_DATE.toString()} remote: ${time.toString()}", + ); } return; @@ -103,8 +111,10 @@ class UpdateChecker { } if (PlatformUtils.isLinux) { - LinkUtils.open(Uri.parse("https://commet.chat/install/linux/"), - context: context); + LinkUtils.open( + Uri.parse("https://commet.chat/install/linux/"), + context: context, + ); } } @@ -113,14 +123,19 @@ class UpdateChecker { var installPath = path.dirname(exe); - var installerPath = - path.join(installPath, "installer", "commet-installer.exe"); + var installerPath = path.join( + installPath, + "installer", + "commet-installer.exe", + ); Log.i("Installed at: $installerPath"); if (await File(installerPath).exists() && canAutoUpdate) { - var confirmation = await AdaptiveDialog.confirmation(context, - prompt: "Would you like to run the update installer?"); + var confirmation = await AdaptiveDialog.confirmation( + context, + prompt: "Would you like to run the update installer?", + ); if (confirmation == true) { await ErrorUtils.tryRun(context, () async { @@ -130,13 +145,7 @@ class UpdateChecker { await client.close(); } - Process.run( - installerPath, - [ - "--command", - "update", - ], - runInShell: true); + Process.run(installerPath, ["--command", "update"], runInShell: true); // TODO: not this await Future.delayed(Duration(seconds: 1)); @@ -148,7 +157,9 @@ class UpdateChecker { if (confirmation == null) return; } - LinkUtils.open(Uri.parse("https://commet.chat/install/windows/"), - context: context); + LinkUtils.open( + Uri.parse("https://commet.chat/install/windows/"), + context: context, + ); } } diff --git a/commet/scripts/apply_google_services.patch b/commet/scripts/apply_google_services.patch index 32861ad74..80f1029cc 100644 --- a/commet/scripts/apply_google_services.patch +++ b/commet/scripts/apply_google_services.patch @@ -1,5 +1,5 @@ diff --git a/commet/android/app/build.gradle b/commet/android/app/build.gradle -index 7869e8c..a757560 100644 +index f05c3a9e..fc1c65bf 100644 --- a/commet/android/app/build.gradle +++ b/commet/android/app/build.gradle @@ -1,7 +1,7 @@ @@ -12,7 +12,7 @@ index 7869e8c..a757560 100644 id "kotlin-android" id "dev.flutter.flutter-gradle-plugin" diff --git a/commet/android/settings.gradle b/commet/android/settings.gradle -index 308e212..4945661 100644 +index f139440b..08f505b4 100644 --- a/commet/android/settings.gradle +++ b/commet/android/settings.gradle @@ -20,7 +20,7 @@ plugins { @@ -25,10 +25,10 @@ index 308e212..4945661 100644 id "org.jetbrains.kotlin.android" version "2.2.20" apply false } diff --git a/commet/lib/client/components/push_notification/android/firebase_push_notifier.dart b/commet/lib/client/components/push_notification/android/firebase_push_notifier.dart -index 9704b92..d0e99c9 100644 +index 0c39f98f..a53c381c 100644 --- a/commet/lib/client/components/push_notification/android/firebase_push_notifier.dart +++ b/commet/lib/client/components/push_notification/android/firebase_push_notifier.dart -@@ -14,12 +14,12 @@ import 'package:commet/main.dart'; +@@ -15,12 +15,12 @@ import 'package:commet/main.dart'; import 'package:commet/service/background_service_notifications/background_service_task_notification2.dart'; // Manage these to enable / disable firebase @@ -48,20 +48,20 @@ index 9704b92..d0e99c9 100644 Future onForegroundMessage(dynamic message) async { diff --git a/commet/lib/config/build_config.dart b/commet/lib/config/build_config.dart -index ea2fdad..e4eaa30 100644 +index a55c80b7..4290d95d 100644 --- a/commet/lib/config/build_config.dart +++ b/commet/lib/config/build_config.dart -@@ -20,7 +20,7 @@ class BuildConfig { - String.fromEnvironment('BUILD_DETAIL', defaultValue: "default"); +@@ -31,7 +31,7 @@ class BuildConfig { - static const bool ENABLE_GOOGLE_SERVICES = -- bool.fromEnvironment("ENABLE_GOOGLE_SERVICES", defaultValue: false); -+ bool.fromEnvironment("ENABLE_GOOGLE_SERVICES", defaultValue: true); + static const bool ENABLE_GOOGLE_SERVICES = bool.fromEnvironment( + "ENABLE_GOOGLE_SERVICES", +- defaultValue: false, ++ defaultValue: true, + ); static const bool DEBUG = _buildMode == _Constants._debug; - diff --git a/commet/lib/firebase_options.dart b/commet/lib/firebase_options.dart -index 235bb5c..e0eeee9 100644 +index 235bb5cd..e0eeee91 100644 --- a/commet/lib/firebase_options.dart +++ b/commet/lib/firebase_options.dart @@ -1,6 +1,5 @@ @@ -78,10 +78,10 @@ index 235bb5c..e0eeee9 100644 - -*/ diff --git a/commet/pubspec.yaml b/commet/pubspec.yaml -index 3c5334e..9cae74c 100644 +index e16377db..298f41e7 100644 --- a/commet/pubspec.yaml +++ b/commet/pubspec.yaml -@@ -99,8 +99,8 @@ dependencies: +@@ -101,8 +101,8 @@ dependencies: ## ---- Putting some extra lines in here to help git with the diff ## ---- Probably good to keep this stuff at the bottom of the list ## Begin Google Services Dependencies diff --git a/commet/scripts/build_release.dart b/commet/scripts/build_release.dart index 91dfcf96e..8dd8d8890 100644 --- a/commet/scripts/build_release.dart +++ b/commet/scripts/build_release.dart @@ -62,33 +62,29 @@ Future main(List args) async { print("Detail:\t\t'$buildDetail'"); } - var process = Process.runSync( - "flutter", - [ - "build", - flutterPlatform, - "--build-name=$buildVersion", - "--release", - "--dart-define", - "BUILD_MODE=release", - "--dart-define", - "PLATFORM=$platform", - "--dart-define", - "GIT_HASH=$hash", - "--dart-define", - "VERSION_TAG=$version", - "--dart-define", - "ENABLE_GOOGLE_SERVICES=$enableGoogleServices", - "--dart-define", - "BUILD_DATE=${DateTime.now().millisecondsSinceEpoch}", - if (buildDetail != null) "--dart-define", - if (buildDetail != null) "BUILD_DETAIL=$buildDetail", - if (platform == "web") "--dart-define", - if (platform == "web") "FLUTTER_WEB_CANVASKIT_URL=canvaskit/", - if (platform == "web") "--source-maps", - ], - runInShell: true, - ); + var process = Process.runSync("flutter", [ + "build", + flutterPlatform, + "--build-name=$buildVersion", + "--release", + "--dart-define", + "BUILD_MODE=release", + "--dart-define", + "PLATFORM=$platform", + "--dart-define", + "GIT_HASH=$hash", + "--dart-define", + "VERSION_TAG=$version", + "--dart-define", + "ENABLE_GOOGLE_SERVICES=$enableGoogleServices", + "--dart-define", + "BUILD_DATE=${DateTime.now().millisecondsSinceEpoch}", + if (buildDetail != null) "--dart-define", + if (buildDetail != null) "BUILD_DETAIL=$buildDetail", + if (platform == "web") "--dart-define", + if (platform == "web") "FLUTTER_WEB_CANVASKIT_URL=canvaskit/", + if (platform == "web") "--source-maps", + ], runInShell: true); print(process.stdout); print(process.stderr); diff --git a/commet/scripts/codegen.dart b/commet/scripts/codegen.dart index bc906fb2d..5c762e66c 100644 --- a/commet/scripts/codegen.dart +++ b/commet/scripts/codegen.dart @@ -3,14 +3,7 @@ import 'dart:io'; Future getDependencies() async { - var process = Process.runSync( - "flutter", - [ - "pub", - "get", - ], - runInShell: true, - ); + var process = Process.runSync("flutter", ["pub", "get"], runInShell: true); print(process.stdout); print(process.stderr); @@ -18,15 +11,11 @@ Future getDependencies() async { } Future intlUtilsGenerate() async { - var process = await Process.run( - "flutter", - [ - "pub", - "run", - "intl_utils:generate", - ], - runInShell: true, - ); + var process = await Process.run("flutter", [ + "pub", + "run", + "intl_utils:generate", + ], runInShell: true); print(process.stdout); print(process.stderr); @@ -87,20 +76,16 @@ Future> generateFileLists() async { } Future generateFromArb(List files) async { - var process = await Process.run( - "flutter", - [ - "pub", - "run", - "intl_translation:generate_from_arb", - "--sources-list-file", - files[0].absolute.path, - "--translations-list-file", - files[1].absolute.path, - "--output-dir=lib/generated/l10n" - ], - runInShell: true, - ); + var process = await Process.run("flutter", [ + "pub", + "run", + "intl_translation:generate_from_arb", + "--sources-list-file", + files[0].absolute.path, + "--translations-list-file", + files[1].absolute.path, + "--output-dir=lib/generated/l10n", + ], runInShell: true); print(process.stdout); print(process.stderr); @@ -108,17 +93,13 @@ Future generateFromArb(List files) async { } Future buildRunner() async { - var process = await Process.run( - "flutter", - [ - "pub", - "run", - "build_runner", - "build", - "--delete-conflicting-outputs", - ], - runInShell: true, - ); + var process = await Process.run("flutter", [ + "pub", + "run", + "build_runner", + "build", + "--delete-conflicting-outputs", + ], runInShell: true); print(process.stdout); print(process.stderr); diff --git a/commet/scripts/extract_strings.dart b/commet/scripts/extract_strings.dart index 92c1e77c3..8744262bc 100644 --- a/commet/scripts/extract_strings.dart +++ b/commet/scripts/extract_strings.dart @@ -5,19 +5,15 @@ import 'dart:io'; import './codegen.dart' as codegen; void extractStrings(List files) async { - var process = await Process.run( - "flutter", - [ - "pub", - "run", - "intl_translation:extract_to_arb", - "--sources-list-file", - files[0].absolute.path, - "--output-dir=./assets/l10n/", - "--output-file=intl_en.arb" - ], - runInShell: true, - ); + var process = await Process.run("flutter", [ + "pub", + "run", + "intl_translation:extract_to_arb", + "--sources-list-file", + files[0].absolute.path, + "--output-dir=./assets/l10n/", + "--output-file=intl_en.arb", + ], runInShell: true); print(process.stdout); print(process.stderr); diff --git a/commet/test_driver/benchmark_driver.dart b/commet/test_driver/benchmark_driver.dart index d28b231fe..7531a941e 100644 --- a/commet/test_driver/benchmark_driver.dart +++ b/commet/test_driver/benchmark_driver.dart @@ -1,6 +1,7 @@ // ignore_for_file: depend_on_referenced_packages import 'package:flutter_driver/flutter_driver.dart'; + import 'dart:convert' show JsonEncoder; import 'package:file/file.dart'; @@ -14,69 +15,70 @@ Future main() { var result = List>.empty(growable: true); for (var key in data.keys) { - final File file = - fs.file(path.join(testOutputsDirectory, 'data.json')); + final File file = fs.file( + path.join(testOutputsDirectory, 'data.json'), + ); const JsonEncoder prettyEncoder = JsonEncoder.withIndent(' '); await file.writeAsString(prettyEncoder.convert(data[key])); - final timeline = Timeline.fromJson( - data[key] as Map, - ); + final timeline = Timeline.fromJson(data[key] as Map); final summary = TimelineSummary.summarize(timeline); if (data[key]["extra_values"] != null) { result.addAll( - List>.from(data[key]["extra_values"])); + List>.from(data[key]["extra_values"]), + ); } result.addAll([ { "name": "$key - Average Build Time", "value": summary.computeAverageFrameBuildTimeMillis(), - "unit": "ms" + "unit": "ms", }, { "name": "$key - Average Raster Time", "value": summary.computeAverageFrameRasterizerTimeMillis(), - "unit": "ms" + "unit": "ms", }, { "name": "$key - Worst Build Time", "value": summary.computeWorstFrameBuildTimeMillis(), - "unit": "ms" + "unit": "ms", }, { "name": "$key - Worst Raster Time", "value": summary.computeWorstFrameRasterizerTimeMillis(), - "unit": "ms" + "unit": "ms", }, { "name": "$key - 99th Percentile Build Time", "value": summary.computePercentileFrameBuildTimeMillis(99), - "unit": "ms" + "unit": "ms", }, { "name": "$key - 90th Percentile Build Time", "value": summary.computePercentileFrameBuildTimeMillis(99), - "unit": "ms" + "unit": "ms", }, { "name": "$key - 99th Percentile Raster Time", "value": summary.computePercentileFrameRasterizerTimeMillis(99), - "unit": "ms" + "unit": "ms", }, { "name": "$key - 90th Percentile Raster Time", "value": summary.computePercentileFrameRasterizerTimeMillis(90), - "unit": "ms" + "unit": "ms", }, ]); } final File file = fs.file( - path.join(testOutputsDirectory, 'customSmallerIsBetter.json')); + path.join(testOutputsDirectory, 'customSmallerIsBetter.json'), + ); const JsonEncoder prettyEncoder = JsonEncoder.withIndent(' '); await file.writeAsString(prettyEncoder.convert(result)); diff --git a/commet/unit_test/matrix_widget_capability_parsing_test.dart b/commet/unit_test/matrix_widget_capability_parsing_test.dart index 368df0f14..8ca3fff5b 100644 --- a/commet/unit_test/matrix_widget_capability_parsing_test.dart +++ b/commet/unit_test/matrix_widget_capability_parsing_test.dart @@ -3,50 +3,35 @@ import 'package:flutter_test/flutter_test.dart'; void main() async { test("org.matrix.msc4039.download_file", () async { - var parsed = - MatrixWidgetCapabilityString.parse("org.matrix.msc4039.download_file"); - - expect( - parsed.capability, + var parsed = MatrixWidgetCapabilityString.parse( "org.matrix.msc4039.download_file", ); + + expect(parsed.capability, "org.matrix.msc4039.download_file"); expect(parsed.eventType, null); expect(parsed.eventKey, null); }); - test("org.matrix.msc2762.send.event:io.element.call.encryption_keys", - () async { - var parsed = MatrixWidgetCapabilityString.parse( - "org.matrix.msc2762.send.event:io.element.call.encryption_keys"); + test( + "org.matrix.msc2762.send.event:io.element.call.encryption_keys", + () async { + var parsed = MatrixWidgetCapabilityString.parse( + "org.matrix.msc2762.send.event:io.element.call.encryption_keys", + ); - expect( - parsed.capability, - "org.matrix.msc2762.send.event", - ); - expect( - parsed.eventType, - "io.element.call.encryption_keys", - ); - expect(parsed.eventKey, null); - }); + expect(parsed.capability, "org.matrix.msc2762.send.event"); + expect(parsed.eventType, "io.element.call.encryption_keys"); + expect(parsed.eventKey, null); + }, + ); - test( - "org.matrix.msc2762.send.state_event:org.matrix.msc3401.call.member#@user:example.com", - () async { + test("org.matrix.msc2762.send.state_event:org.matrix.msc3401.call.member#@user:example.com", () async { var parsed = MatrixWidgetCapabilityString.parse( - "org.matrix.msc2762.send.state_event:org.matrix.msc3401.call.member#@user:example.com"); - - expect( - parsed.capability, - "org.matrix.msc2762.send.state_event", - ); - expect( - parsed.eventType, - "org.matrix.msc3401.call.member", - ); - expect( - parsed.eventKey, - "@user:example.com", + "org.matrix.msc2762.send.state_event:org.matrix.msc3401.call.member#@user:example.com", ); + + expect(parsed.capability, "org.matrix.msc2762.send.state_event"); + expect(parsed.eventType, "org.matrix.msc3401.call.member"); + expect(parsed.eventKey, "@user:example.com"); }); } diff --git a/commet/unit_test/notifying_list_test.dart b/commet/unit_test/notifying_list_test.dart index 7c789fd93..a974a8c0e 100644 --- a/commet/unit_test/notifying_list_test.dart +++ b/commet/unit_test/notifying_list_test.dart @@ -16,21 +16,13 @@ void main() async { listUpdatedCalled = false; } - list.onAdd.listen( - (event) => addedCalled = true, - ); + list.onAdd.listen((event) => addedCalled = true); - list.onItemUpdated.listen( - (event) => itemUpdatedCalled = true, - ); + list.onItemUpdated.listen((event) => itemUpdatedCalled = true); - list.onListUpdated.listen( - (event) => listUpdatedCalled = true, - ); + list.onListUpdated.listen((event) => listUpdatedCalled = true); - list.onRemove.listen( - (event) => removedCalled = true, - ); + list.onRemove.listen((event) => removedCalled = true); test("Add", () { resetFlags(); diff --git a/commet/unit_test/password_validator_test.dart b/commet/unit_test/password_validator_test.dart index 2c9c95754..068b643a0 100644 --- a/commet/unit_test/password_validator_test.dart +++ b/commet/unit_test/password_validator_test.dart @@ -1,86 +1,107 @@ import 'package:commet/utils/text_utils.dart'; import 'package:flutter_test/flutter_test.dart'; + void main() async { test("Force Digits: 'abcdefg'", () async { expect( - TextUtils.isValidPassword("abcdefg", forceDigits: true) == - NewPasswordResult.noNumbers, - isTrue); + TextUtils.isValidPassword("abcdefg", forceDigits: true) == + NewPasswordResult.noNumbers, + isTrue, + ); }); test("Force Digits: 'abcdefg123'", () async { expect( - TextUtils.isValidPassword("abcdefg123", forceDigits: true) == - NewPasswordResult.valid, - isTrue); + TextUtils.isValidPassword("abcdefg123", forceDigits: true) == + NewPasswordResult.valid, + isTrue, + ); }); test("Force length 10: 'abc'", () async { expect( - TextUtils.isValidPassword("abc", forceLength: 10) == - NewPasswordResult.tooShort, - isTrue); + TextUtils.isValidPassword("abc", forceLength: 10) == + NewPasswordResult.tooShort, + isTrue, + ); }); test("Force length 10: 'abcdefghijklmnopqrstuvqxyz'", () async { expect( - TextUtils.isValidPassword("abcdefghijklmnopqrstuvqxyz", - forceLength: 10) == - NewPasswordResult.valid, - isTrue); + TextUtils.isValidPassword( + "abcdefghijklmnopqrstuvqxyz", + forceLength: 10, + ) == + NewPasswordResult.valid, + isTrue, + ); }); test("Force Special Characters: 'abcdef'", () async { expect( - TextUtils.isValidPassword("abcdef", forceSpecialCharacter: true) == - NewPasswordResult.noSymbols, - isTrue); + TextUtils.isValidPassword("abcdef", forceSpecialCharacter: true) == + NewPasswordResult.noSymbols, + isTrue, + ); }); test("Force Special Characters: 'abcdef!'", () async { expect( - TextUtils.isValidPassword("abcdef!", forceSpecialCharacter: true) == - NewPasswordResult.valid, - isTrue); + TextUtils.isValidPassword("abcdef!", forceSpecialCharacter: true) == + NewPasswordResult.valid, + isTrue, + ); }); test("Force All: 'a'", () async { expect( - TextUtils.isValidPassword("a", - forceSpecialCharacter: true, - forceLength: 10, - forceDigits: true) != - NewPasswordResult.valid, - isTrue); + TextUtils.isValidPassword( + "a", + forceSpecialCharacter: true, + forceLength: 10, + forceDigits: true, + ) != + NewPasswordResult.valid, + isTrue, + ); }); test("Force All: 'a1'", () async { expect( - TextUtils.isValidPassword("a1", - forceSpecialCharacter: true, - forceLength: 10, - forceDigits: true) != - NewPasswordResult.valid, - isTrue); + TextUtils.isValidPassword( + "a1", + forceSpecialCharacter: true, + forceLength: 10, + forceDigits: true, + ) != + NewPasswordResult.valid, + isTrue, + ); }); test("Force All: 'a1!'", () async { expect( - TextUtils.isValidPassword("a1!", - forceSpecialCharacter: true, - forceLength: 10, - forceDigits: true) != - NewPasswordResult.valid, - isTrue); + TextUtils.isValidPassword( + "a1!", + forceSpecialCharacter: true, + forceLength: 10, + forceDigits: true, + ) != + NewPasswordResult.valid, + isTrue, + ); }); test("Force All: 'a1!bcdefghijklmnop'", () async { expect( - TextUtils.isValidPassword("a1!bcdefghijklmnop", - forceSpecialCharacter: true, - forceLength: 10, - forceDigits: true) == - NewPasswordResult.valid, - isTrue); + TextUtils.isValidPassword( + "a1!bcdefghijklmnop", + forceSpecialCharacter: true, + forceLength: 10, + forceDigits: true, + ) == + NewPasswordResult.valid, + isTrue, + ); }); } diff --git a/commet/unit_test/tracking_parameter_test.dart b/commet/unit_test/tracking_parameter_test.dart index a50ba796c..379240ad7 100644 --- a/commet/unit_test/tracking_parameter_test.dart +++ b/commet/unit_test/tracking_parameter_test.dart @@ -5,7 +5,7 @@ void main() async { final pairs = [ ( "https://deezer.com/track/891177062?utm_source=deezer", - "https://deezer.com/track/891177062" + "https://deezer.com/track/891177062", ), ( "https://youtu.be/dQw4w9WgXcQ?si=VIB_lCxCeWJxCjS5", @@ -13,7 +13,7 @@ void main() async { ), ( "https://open.spotify.com/track/4PTG3Z6ehGkBFwjybzWkR8?si=R9xmSd-dTvCCQTlOCYbluw", - "https://open.spotify.com/track/4PTG3Z6ehGkBFwjybzWkR8" + "https://open.spotify.com/track/4PTG3Z6ehGkBFwjybzWkR8", ), ( "https://example.com?utm_source=remove_this&important=83746", @@ -21,17 +21,15 @@ void main() async { ), ( "https://www.instagram.com/reel/xxxxxxxxxxx/?igsh=xxxxxxxxxxxxxxxxxx==", - "https://www.instagram.com/reel/xxxxxxxxxxx/" + "https://www.instagram.com/reel/xxxxxxxxxxx/", ), ( "https://x.com/airyz_/status/0000000000000000000?s=46&t=v1Vs9upYM9FGppwyLTA7cg", - "https://x.com/airyz_/status/0000000000000000000" + "https://x.com/airyz_/status/0000000000000000000", ), ]; - final unchangedUrls = [ - "https://youtu.be/dQw4w9WgXcQ", - ]; + final unchangedUrls = ["https://youtu.be/dQw4w9WgXcQ"]; TestWidgetsFlutterBinding.ensureInitialized(); @@ -40,8 +38,9 @@ void main() async { var uri = Uri.parse(pair.$1); var expected = Uri.parse(pair.$2); - var clean = - await UrlTrackingParametersCleaner.cleanTrackingParameters(uri); + var clean = await UrlTrackingParametersCleaner.cleanTrackingParameters( + uri, + ); print("Before: $uri after: $clean"); expect(clean.toString(), expected.toString()); @@ -52,8 +51,9 @@ void main() async { for (var url in unchangedUrls) { var uri = Uri.parse(url); - var clean = - await UrlTrackingParametersCleaner.cleanTrackingParameters(uri); + var clean = await UrlTrackingParametersCleaner.cleanTrackingParameters( + uri, + ); expect(clean.toString(), url.toString()); }