diff --git a/analysis_options.yaml b/analysis_options.yaml index 1b09755..1a25be6 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -14,6 +14,7 @@ analyzer: - "lib/src/model/protobuf/**" - "lib/src/model/protobuf/api/websocket/**" - "lib/generated/**" + - "dependencies/**" - "test/drift/**" - "**.g.dart" diff --git a/lib/app.dart b/lib/app.dart index 2cb2768..5773553 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -106,7 +106,7 @@ class _AppState extends State with WidgetsBindingObserver { Locale('en', ''), Locale('de', ''), ], - onGenerateTitle: (BuildContext context) => "twonly", + onGenerateTitle: (BuildContext context) => 'twonly', theme: ThemeData( colorScheme: ColorScheme.fromSeed( seedColor: const Color(0xFF57CC99), @@ -132,8 +132,8 @@ class _AppState extends State with WidgetsBindingObserver { themeMode: context.watch().themeMode, initialRoute: '/', routes: { - "/": (context) => AppMainWidget(initialPage: 1), - "/chats": (context) => AppMainWidget(initialPage: 0) + '/': (context) => const AppMainWidget(initialPage: 1), + '/chats': (context) => const AppMainWidget(initialPage: 0) }, ); }, @@ -143,8 +143,8 @@ class _AppState extends State with WidgetsBindingObserver { class AppMainWidget extends StatefulWidget { const AppMainWidget({ - super.key, required this.initialPage, + super.key, }); final int initialPage; @override @@ -182,7 +182,7 @@ class _AppMainWidgetState extends State { ); }, ), - AppOutdated(), + const AppOutdated(), ], ); } diff --git a/lib/src/database/daos/contacts_dao.dart b/lib/src/database/daos/contacts_dao.dart index f6ea804..8970934 100644 --- a/lib/src/database/daos/contacts_dao.dart +++ b/lib/src/database/daos/contacts_dao.dart @@ -103,8 +103,8 @@ class ContactsDao extends DatabaseAccessor Future updateContact( int userId, ContactsCompanion updatedValues) async { - await ((update(contacts)..where((c) => c.userId.equals(userId))) - .write(updatedValues)); + await (update(contacts)..where((c) => c.userId.equals(userId))) + .write(updatedValues); if (updatedValues.blocked.present || updatedValues.displayName.present || updatedValues.nickName.present) { @@ -177,8 +177,9 @@ class ContactsDao extends DatabaseAccessor Stream watchContactsBlocked() { final count = contacts.userId.count(); - final query = selectOnly(contacts)..where(contacts.blocked.equals(true)); - query.addColumns([count]); + final query = selectOnly(contacts) + ..where(contacts.blocked.equals(true)) + ..addColumns([count]); return query.map((row) => row.read(count)).watchSingle(); } @@ -186,8 +187,8 @@ class ContactsDao extends DatabaseAccessor final count = contacts.requested.count(distinct: true); final query = selectOnly(contacts) ..where(contacts.requested.equals(true) & - contacts.accepted.equals(true).not()); - query.addColumns([count]); + contacts.accepted.equals(true).not()) + ..addColumns([count]); return query.map((row) => row.read(count)).watchSingle(); } @@ -204,15 +205,13 @@ class ContactsDao extends DatabaseAccessor u.lastMessageSend.isNotNull(), )) .watchSingle() - .asyncMap((contact) { - return getFlameCounterFromContact(contact); - }); + .asyncMap(getFlameCounterFromContact); } } String getContactDisplayName(Contact user) { - String name = user.username; - if (user.nickName != null && user.nickName != "") { + var name = user.username; + if (user.nickName != null && user.nickName != '') { name = user.nickName!; } else if (user.displayName != null) { name = user.displayName!; @@ -224,7 +223,7 @@ String getContactDisplayName(Contact user) { } String applyStrikethrough(String text) { - return text.split('').map((char) => '$char\u0336').join(''); + return text.split('').map((char) => '$char\u0336').join(); } int getFlameCounterFromContact(Contact contact) { @@ -233,7 +232,7 @@ int getFlameCounterFromContact(Contact contact) { } final now = DateTime.now(); final startOfToday = DateTime(now.year, now.month, now.day); - final twoDaysAgo = startOfToday.subtract(Duration(days: 2)); + final twoDaysAgo = startOfToday.subtract(const Duration(days: 2)); if (contact.lastMessageSend!.isAfter(twoDaysAgo) && contact.lastMessageReceived!.isAfter(twoDaysAgo)) { return contact.flameCounter + 1; diff --git a/lib/src/database/daos/media_downloads_dao.dart b/lib/src/database/daos/media_downloads_dao.dart index 99e6a14..5e5762e 100644 --- a/lib/src/database/daos/media_downloads_dao.dart +++ b/lib/src/database/daos/media_downloads_dao.dart @@ -21,7 +21,7 @@ class MediaDownloadsDao extends DatabaseAccessor try { return await into(mediaDownloads).insert(values); } catch (e) { - Log.error("Error while inserting media upload: $e"); + Log.error('Error while inserting media upload: $e'); return null; } } diff --git a/lib/src/database/daos/media_uploads_dao.dart b/lib/src/database/daos/media_uploads_dao.dart index 127328c..4ac6961 100644 --- a/lib/src/database/daos/media_uploads_dao.dart +++ b/lib/src/database/daos/media_uploads_dao.dart @@ -28,7 +28,7 @@ class MediaUploadsDao extends DatabaseAccessor try { return await into(mediaUploads).insert(values); } catch (e) { - Log.error("Error while inserting media upload: $e"); + Log.error('Error while inserting media upload: $e'); return null; } } diff --git a/lib/src/database/daos/message_retransmissions.dao.dart b/lib/src/database/daos/message_retransmissions.dao.dart index ae26720..1fb9cff 100644 --- a/lib/src/database/daos/message_retransmissions.dao.dart +++ b/lib/src/database/daos/message_retransmissions.dao.dart @@ -17,7 +17,7 @@ class MessageRetransmissionDao extends DatabaseAccessor try { return await into(messageRetransmissions).insert(message); } catch (e) { - Log.error("Error while inserting message for retransmission: $e"); + Log.error('Error while inserting message for retransmission: $e'); return null; } } @@ -29,7 +29,7 @@ class MessageRetransmissionDao extends DatabaseAccessor .go(); if (countDeleted > 0) { - Log.info("Deleted $countDeleted faulty retransmissions"); + Log.info('Deleted $countDeleted faulty retransmissions'); } return (await (select(messageRetransmissions) diff --git a/lib/src/database/daos/messages_dao.dart b/lib/src/database/daos/messages_dao.dart index 24c50b3..924201e 100644 --- a/lib/src/database/daos/messages_dao.dart +++ b/lib/src/database/daos/messages_dao.dart @@ -51,7 +51,7 @@ class MessagesDao extends DatabaseAccessor (t.openedAt.isNull() | t.mediaStored.equals(true) | t.openedAt.isBiggerThanValue( - DateTime.now().subtract(Duration(days: 1))))) + DateTime.now().subtract(const Duration(days: 1))))) ..orderBy([(t) => OrderingTerm.desc(t.sendAt)])) .watch(); } @@ -60,13 +60,13 @@ class MessagesDao extends DatabaseAccessor return (update(messages) ..where((t) => (t.openedAt.isSmallerThanValue( - DateTime.now().subtract(Duration(days: 1)), + DateTime.now().subtract(const Duration(days: 1)), ) | (t.sendAt.isSmallerThanValue( - DateTime.now().subtract(Duration(days: 1))) & + DateTime.now().subtract(const Duration(days: 1))) & t.errorWhileSending.equals(true))) & t.kind.equals(MessageKind.textMessage.name))) - .write(MessagesCompanion(contentJson: Value(null))); + .write(const MessagesCompanion(contentJson: Value(null))); } Future handleMediaFilesOlderThan7Days() { @@ -78,11 +78,11 @@ class MessagesDao extends DatabaseAccessor t.messageOtherId.isNull() & (t.sendAt.isSmallerThanValue( DateTime.now().subtract( - Duration(days: 8), + const Duration(days: 8), ), ))), )) - .write(MessagesCompanion(errorWhileSending: Value(true))); + .write(const MessagesCompanion(errorWhileSending: Value(true))); } Future> getAllMessagesPendingDownloading() { @@ -104,7 +104,7 @@ class MessagesDao extends DatabaseAccessor t.messageOtherId.isNull() & t.errorWhileSending.equals(false) & t.sendAt.isBiggerThanValue( - DateTime.now().subtract(Duration(minutes: 10)), + DateTime.now().subtract(const Duration(minutes: 10)), ))) .get(); } @@ -142,10 +142,10 @@ class MessagesDao extends DatabaseAccessor } Future resetPendingDownloadState() { - // All media files in the downloading state are reseteded to the pending state + // All media files in the downloading state are reset to the pending state // When the app is used in mobile network, they will not be downloaded at the start // if they are not yet downloaded... - final updates = + const updates = MessagesCompanion(downloadState: Value(DownloadState.pending)); return (update(messages) ..where((t) => @@ -198,7 +198,7 @@ class MessagesDao extends DatabaseAccessor return await into(messages).insert(message); } catch (e) { - Log.error("Error while inserting message: $e"); + Log.error('Error while inserting message: $e'); return null; } } @@ -244,7 +244,7 @@ class MessagesDao extends DatabaseAccessor } Future> getMessagesByMediaUploadId(int mediaUploadId) async { - return await (select(messages) + return (select(messages) ..where((t) => t.mediaUploadId.equals(mediaUploadId))) .get(); } diff --git a/lib/src/database/daos/signal_dao.dart b/lib/src/database/daos/signal_dao.dart index 46e7cae..3ce89cc 100644 --- a/lib/src/database/daos/signal_dao.dart +++ b/lib/src/database/daos/signal_dao.dart @@ -62,9 +62,9 @@ class SignalDao extends DatabaseAccessor with _$SignalDaoMixin { List preKeys) async { for (final preKey in preKeys) { try { - into(signalContactPreKeys).insert(preKey); + await into(signalContactPreKeys).insert(preKey); } catch (e) { - Log.error("$e"); + Log.error('$e'); } } } @@ -90,7 +90,7 @@ class SignalDao extends DatabaseAccessor with _$SignalDaoMixin { await (delete(signalContactSignedPreKeys) ..where((t) => (t.createdAt.isSmallerThanValue( DateTime.now().subtract( - Duration(days: 25), + const Duration(days: 25), ), )))) .go(); @@ -98,7 +98,7 @@ class SignalDao extends DatabaseAccessor with _$SignalDaoMixin { await (delete(twonlyDB.signalPreKeyStores) ..where((t) => (t.createdAt.isSmallerThanValue( DateTime.now().subtract( - Duration(days: 40), + const Duration(days: 40), ), )))) .go(); diff --git a/lib/src/database/signal/connect_identitiy_key_store.dart b/lib/src/database/signal/connect_identity_key_store.dart similarity index 100% rename from lib/src/database/signal/connect_identitiy_key_store.dart rename to lib/src/database/signal/connect_identity_key_store.dart diff --git a/lib/src/database/signal/connect_sender_key_store.dart b/lib/src/database/signal/connect_sender_key_store.dart index d798150..3639e73 100644 --- a/lib/src/database/signal/connect_sender_key_store.dart +++ b/lib/src/database/signal/connect_sender_key_store.dart @@ -1,15 +1,14 @@ import 'package:drift/drift.dart'; +import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/database/twonly_database.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; class ConnectSenderKeyStore extends SenderKeyStore { @override Future loadSenderKey(SenderKeyName senderKeyName) async { - SignalSenderKeyStore? identity = - await (twonlyDB.select(twonlyDB.signalSenderKeyStores) - ..where((t) => t.senderKeyName.equals(senderKeyName.serialize()))) - .getSingleOrNull(); + final identity = await (twonlyDB.select(twonlyDB.signalSenderKeyStores) + ..where((t) => t.senderKeyName.equals(senderKeyName.serialize()))) + .getSingleOrNull(); if (identity == null) { throw InvalidKeyIdException( 'No such sender key record! - $senderKeyName'); diff --git a/lib/src/database/signal/connect_session_store.dart b/lib/src/database/signal/connect_session_store.dart index 79b1395..889b749 100644 --- a/lib/src/database/signal/connect_session_store.dart +++ b/lib/src/database/signal/connect_session_store.dart @@ -1,6 +1,6 @@ import 'package:drift/drift.dart'; -import 'package:twonly/globals.dart'; import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; +import 'package:twonly/globals.dart'; import 'package:twonly/src/database/twonly_database.dart'; class ConnectSessionStore extends SessionStore { @@ -50,7 +50,7 @@ class ConnectSessionStore extends SessionStore { if (dbSession.isEmpty) { return SessionRecord(); } - Uint8List session = dbSession.first.sessionRecord; + final session = dbSession.first.sessionRecord; return SessionRecord.fromSerialized(session); } diff --git a/lib/src/database/signal/connect_signal_protocol_store.dart b/lib/src/database/signal/connect_signal_protocol_store.dart index 1a0107c..3a6913a 100644 --- a/lib/src/database/signal/connect_signal_protocol_store.dart +++ b/lib/src/database/signal/connect_signal_protocol_store.dart @@ -1,8 +1,8 @@ -import 'package:twonly/src/database/signal/connect_identitiy_key_store.dart'; +import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; +import 'package:twonly/src/database/signal/connect_identity_key_store.dart'; import 'package:twonly/src/database/signal/connect_pre_key_store.dart'; import 'package:twonly/src/database/signal/connect_session_store.dart'; import 'package:twonly/src/database/signal/connect_signed_pre_key_store.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; class ConnectSignalProtocolStore implements SignalProtocolStore { ConnectSignalProtocolStore( diff --git a/lib/src/database/tables/contacts_table.dart b/lib/src/database/tables/contacts_table.dart index 6781140..3b80a4c 100644 --- a/lib/src/database/tables/contacts_table.dart +++ b/lib/src/database/tables/contacts_table.dart @@ -8,24 +8,25 @@ class Contacts extends Table { TextColumn get nickName => text().nullable()(); TextColumn get avatarSvg => text().nullable()(); - IntColumn get myAvatarCounter => integer().withDefault(Constant(0))(); + IntColumn get myAvatarCounter => integer().withDefault(const Constant(0))(); - BoolColumn get accepted => boolean().withDefault(Constant(false))(); - BoolColumn get requested => boolean().withDefault(Constant(false))(); - BoolColumn get blocked => boolean().withDefault(Constant(false))(); - BoolColumn get verified => boolean().withDefault(Constant(false))(); - BoolColumn get archived => boolean().withDefault(Constant(false))(); - BoolColumn get pinned => boolean().withDefault(Constant(false))(); - BoolColumn get deleted => boolean().withDefault(Constant(false))(); + BoolColumn get accepted => boolean().withDefault(const Constant(false))(); + BoolColumn get requested => boolean().withDefault(const Constant(false))(); + BoolColumn get blocked => boolean().withDefault(const Constant(false))(); + BoolColumn get verified => boolean().withDefault(const Constant(false))(); + BoolColumn get archived => boolean().withDefault(const Constant(false))(); + BoolColumn get pinned => boolean().withDefault(const Constant(false))(); + BoolColumn get deleted => boolean().withDefault(const Constant(false))(); - BoolColumn get alsoBestFriend => boolean().withDefault(Constant(false))(); + BoolColumn get alsoBestFriend => + boolean().withDefault(const Constant(false))(); IntColumn get deleteMessagesAfterXMinutes => - integer().withDefault(Constant(60 * 24))(); + integer().withDefault(const Constant(60 * 24))(); DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)(); - IntColumn get totalMediaCounter => integer().withDefault(Constant(0))(); + IntColumn get totalMediaCounter => integer().withDefault(const Constant(0))(); DateTimeColumn get lastMessageSend => dateTime().nullable()(); DateTimeColumn get lastMessageReceived => dateTime().nullable()(); @@ -34,7 +35,7 @@ class Contacts extends Table { DateTimeColumn get lastMessageExchange => dateTime().withDefault(currentDateAndTime)(); - IntColumn get flameCounter => integer().withDefault(Constant(0))(); + IntColumn get flameCounter => integer().withDefault(const Constant(0))(); @override Set get primaryKey => {userId}; diff --git a/lib/src/database/tables/messages_table.dart b/lib/src/database/tables/messages_table.dart index 4ec3987..6a2af91 100644 --- a/lib/src/database/tables/messages_table.dart +++ b/lib/src/database/tables/messages_table.dart @@ -44,16 +44,18 @@ class Messages extends Table { IntColumn get responseToMessageId => integer().nullable()(); IntColumn get responseToOtherMessageId => integer().nullable()(); - BoolColumn get acknowledgeByUser => boolean().withDefault(Constant(false))(); - BoolColumn get mediaStored => boolean().withDefault(Constant(false))(); + BoolColumn get acknowledgeByUser => + boolean().withDefault(const Constant(false))(); + BoolColumn get mediaStored => boolean().withDefault(const Constant(false))(); IntColumn get downloadState => intEnum() .withDefault(Constant(DownloadState.downloaded.index))(); BoolColumn get acknowledgeByServer => - boolean().withDefault(Constant(false))(); + boolean().withDefault(const Constant(false))(); - BoolColumn get errorWhileSending => boolean().withDefault(Constant(false))(); + BoolColumn get errorWhileSending => + boolean().withDefault(const Constant(false))(); TextColumn get mediaRetransmissionState => textEnum() .withDefault(Constant(MediaRetransmitting.none.name))(); diff --git a/lib/src/model/json/signal_identity.dart b/lib/src/model/json/signal_identity.dart index 7b10c76..d455887 100644 --- a/lib/src/model/json/signal_identity.dart +++ b/lib/src/model/json/signal_identity.dart @@ -1,6 +1,8 @@ -import 'dart:typed_data'; -import 'package:json_annotation/json_annotation.dart'; import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:json_annotation/json_annotation.dart'; + part 'signal_identity.g.dart'; @JsonSerializable() @@ -9,13 +11,13 @@ class SignalIdentity { required this.identityKeyPairU8List, required this.registrationId, }); + factory SignalIdentity.fromJson(Map json) => + _$SignalIdentityFromJson(json); final int registrationId; @Uint8ListConverter() final Uint8List identityKeyPairU8List; - factory SignalIdentity.fromJson(Map json) => - _$SignalIdentityFromJson(json); Map toJson() => _$SignalIdentityToJson(this); } diff --git a/lib/src/model/json/userdata.dart b/lib/src/model/json/userdata.dart index 3f9b2d5..f77f5e0 100644 --- a/lib/src/model/json/userdata.dart +++ b/lib/src/model/json/userdata.dart @@ -11,6 +11,8 @@ class UserData { required this.subscriptionPlan, required this.isDemoUser, }); + factory UserData.fromJson(Map json) => + _$UserDataFromJson(json); final int userId; @@ -29,7 +31,7 @@ class UserData { // --- SUBSCRIPTION DTA --- - @JsonKey(defaultValue: "Preview") + @JsonKey(defaultValue: 'Preview') String subscriptionPlan; DateTime? lastImageSend; int? todaysImageCounter; @@ -81,9 +83,6 @@ class UserData { DateTime? nextTimeToShowBackupNotice; BackupServer? backupServer; TwonlySafeBackup? twonlySafeBackup; - - factory UserData.fromJson(Map json) => - _$UserDataFromJson(json); Map toJson() => _$UserDataToJson(this); } @@ -95,15 +94,14 @@ class TwonlySafeBackup { required this.backupId, required this.encryptionKey, }); + factory TwonlySafeBackup.fromJson(Map json) => + _$TwonlySafeBackupFromJson(json); int lastBackupSize = 0; LastBackupUploadState backupUploadState = LastBackupUploadState.none; DateTime? lastBackupDone; List backupId; List encryptionKey; - - factory TwonlySafeBackup.fromJson(Map json) => - _$TwonlySafeBackupFromJson(json); Map toJson() => _$TwonlySafeBackupToJson(this); } @@ -114,12 +112,11 @@ class BackupServer { required this.retentionDays, required this.maxBackupBytes, }); + factory BackupServer.fromJson(Map json) => + _$BackupServerFromJson(json); String serverUrl; int retentionDays; int maxBackupBytes; - - factory BackupServer.fromJson(Map json) => - _$BackupServerFromJson(json); Map toJson() => _$BackupServerToJson(this); } diff --git a/lib/src/providers/connection.provider.dart b/lib/src/providers/connection.provider.dart index d16e04a..9d0941c 100644 --- a/lib/src/providers/connection.provider.dart +++ b/lib/src/providers/connection.provider.dart @@ -3,7 +3,7 @@ import 'package:flutter/foundation.dart'; class CustomChangeProvider with ChangeNotifier, DiagnosticableTreeMixin { bool _isConnected = false; bool get isConnected => _isConnected; - String plan = "Preview"; + String plan = 'Preview'; Future updateConnectionState(bool update) async { _isConnected = update; notifyListeners(); diff --git a/lib/src/services/api.service.dart b/lib/src/services/api.service.dart index 44caad4..798b4c0 100644 --- a/lib/src/services/api.service.dart +++ b/lib/src/services/api.service.dart @@ -61,12 +61,13 @@ class ApiService { final HashMap messagesV0 = HashMap(); IOWebSocketChannel? _channel; + // ignore: cancel_subscriptions StreamSubscription>? connectivitySubscription; Future _connectTo(String apiUrl) async { if (appIsOutdated) return false; try { - var channel = IOWebSocketChannel.connect( + final channel = IOWebSocketChannel.connect( Uri.parse(apiUrl), ); _channel = channel; @@ -195,11 +196,11 @@ class ApiService { onClosed(); } - void _onData(dynamic msgBuffer) async { + Future _onData(dynamic msgBuffer) async { try { final msg = server.ServerToClient.fromBuffer(msgBuffer as Uint8List); if (msg.v0.hasResponse()) { - removeFromRetransmissionBuffer(msg.v0.seq); + await removeFromRetransmissionBuffer(msg.v0.seq); messagesV0[msg.v0.seq] = msg; } else { await handleServerMessage(msg); @@ -212,7 +213,7 @@ class ApiService { Future _waitForResponse(Int64 seq) async { final startTime = DateTime.now(); - final timeout = Duration(seconds: 20); + const timeout = Duration(seconds: 20); while (true) { if (messagesV0[seq] != null) { @@ -393,7 +394,7 @@ class ApiService { return; } - var handshake = Handshake() + final handshake = Handshake() ..getauthchallenge = Handshake_GetAuthChallenge(); final req = createClientToServerFromHandshake(handshake); @@ -445,7 +446,7 @@ class ApiService { final signedPreKey = (await signalStore.loadSignedPreKeys())[0]; - var register = Handshake_Register() + final register = Handshake_Register() ..username = username ..publicIdentityKey = (await signalStore.getIdentityKeyPair()).getPublicKey().serialize() @@ -614,7 +615,7 @@ class ApiService { ..userId = Int64(userId); final appData = ApplicationData()..getsignedprekeybyuserid = get; final req = createClientToServerFromApplicationData(appData); - Result res = await sendRequestSync(req, contactId: userId); + final res = await sendRequestSync(req, contactId: userId); if (res.isSuccess) { final ok = res.value as server.Response_Ok; if (ok.hasSignedprekey()) { @@ -628,11 +629,11 @@ class ApiService { final get = ApplicationData_GetPrekeysByUserId()..userId = Int64(userId); final appData = ApplicationData()..getprekeysbyuserid = get; final req = createClientToServerFromApplicationData(appData); - Result res = await sendRequestSync(req, contactId: userId); + final res = await sendRequestSync(req, contactId: userId); if (res.isSuccess) { final ok = res.value as server.Response_Ok; if (ok.hasUserdata()) { - server.Response_UserData data = ok.userdata; + final data = ok.userdata; if (data.hasSignedPrekey() && data.hasSignedPrekeyId() && data.hasSignedPrekeySignature()) { @@ -650,7 +651,7 @@ class ApiService { Future sendTextMessage( int target, Uint8List msg, List? pushData) async { - var testMessage = ApplicationData_TextMessage() + final testMessage = ApplicationData_TextMessage() ..userId = Int64(target) ..body = msg; diff --git a/lib/src/services/api/media_upload.dart b/lib/src/services/api/media_upload.dart index e69f9b6..1285929 100644 --- a/lib/src/services/api/media_upload.dart +++ b/lib/src/services/api/media_upload.dart @@ -114,7 +114,7 @@ Future initFileDownloader() async { Future checkForFailedUploads() async { final messages = await twonlyDB.messagesDao.getAllMessagesPendingUpload(); final mediaUploadIds = []; - for (var message in messages) { + for (final message in messages) { if (mediaUploadIds.contains(message.mediaUploadId)) { continue; } @@ -690,7 +690,7 @@ Future handleUploadWhenAppGoesBackground() async { Log.info('App goes into background. Enqueue uploads to the background.'); final keys = currentUploadTasks.keys.toList(); for (final key in keys) { - enqueueUploadTask(key); + await enqueueUploadTask(key); } } diff --git a/lib/src/services/api/server_messages.dart b/lib/src/services/api/server_messages.dart index 44f135f..1e09ff7 100644 --- a/lib/src/services/api/server_messages.dart +++ b/lib/src/services/api/server_messages.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_dynamic_calls + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/lib/src/services/api/utils.dart b/lib/src/services/api/utils.dart index ec74964..e67254d 100644 --- a/lib/src/services/api/utils.dart +++ b/lib/src/services/api/utils.dart @@ -37,8 +37,8 @@ Result asResult(server.ServerToClient? msg) { } ClientToServer createClientToServerFromHandshake(Handshake handshake) { - var v0 = client.V0() - ..seq = Int64(0) + final v0 = client.V0() + ..seq = Int64() ..handshake = handshake; return ClientToServer()..v0 = v0; } @@ -46,7 +46,7 @@ ClientToServer createClientToServerFromHandshake(Handshake handshake) { ClientToServer createClientToServerFromApplicationData( ApplicationData applicationData) { final v0 = client.V0() - ..seq = Int64(0) + ..seq = Int64() ..applicationdata = applicationData; return ClientToServer()..v0 = v0; } diff --git a/lib/src/services/flame.service.dart b/lib/src/services/flame.service.dart index 55346c2..1b75eea 100644 --- a/lib/src/services/flame.service.dart +++ b/lib/src/services/flame.service.dart @@ -4,20 +4,19 @@ import 'package:twonly/globals.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/twonly_database.dart'; +import 'package:twonly/src/model/json/message.dart' as my; import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/storage.dart'; -import 'package:twonly/src/model/json/message.dart' as my; Future syncFlameCounters() async { - var user = await getUser(); + final user = await getUser(); if (user == null) return; - List contacts = - await twonlyDB.contactsDao.getAllNotBlockedContacts(); + final contacts = await twonlyDB.contactsDao.getAllNotBlockedContacts(); if (contacts.isEmpty) return; - int maxMessageCounter = contacts.map((x) => x.totalMediaCounter).max; - Contact bestFriend = + final maxMessageCounter = contacts.map((x) => x.totalMediaCounter).max; + final bestFriend = contacts.firstWhere((x) => x.totalMediaCounter == maxMessageCounter); if (user.myBestFriendContactId != bestFriend.userId) { @@ -27,13 +26,13 @@ Future syncFlameCounters() async { }); } - for (Contact contact in contacts) { + for (final contact in contacts) { if (contact.lastFlameCounterChange == null) continue; if (contact.lastFlameSync != null) { if (isToday(contact.lastFlameSync!)) continue; } - int flameCounter = getFlameCounterFromContact(contact) - 1; + final flameCounter = getFlameCounterFromContact(contact) - 1; // only sync when flame counter is higher than three days if (flameCounter < 1 && bestFriend.userId != contact.userId) continue; diff --git a/lib/src/services/notifications/setup.notifications.dart b/lib/src/services/notifications/setup.notifications.dart index 3dcd399..4631320 100644 --- a/lib/src/services/notifications/setup.notifications.dart +++ b/lib/src/services/notifications/setup.notifications.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:io'; import 'dart:ui' as ui; -import 'package:flutter/services.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_svg/svg.dart'; import 'package:path_provider/path_provider.dart'; @@ -29,24 +28,18 @@ final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = int id = 0; Future setupPushNotification() async { - const AndroidInitializationSettings initializationSettingsAndroid = - AndroidInitializationSettings("ic_launcher_foreground"); + const initializationSettingsAndroid = + AndroidInitializationSettings('ic_launcher_foreground'); - final List darwinNotificationCategories = - []; + final darwinNotificationCategories = []; /// Note: permissions aren't requested here just to demonstrate that can be /// done later - final DarwinInitializationSettings initializationSettingsDarwin = - DarwinInitializationSettings( - requestAlertPermission: true, - requestBadgePermission: true, - requestSoundPermission: true, - requestProvisionalPermission: false, + final initializationSettingsDarwin = DarwinInitializationSettings( notificationCategories: darwinNotificationCategories, ); - final InitializationSettings initializationSettings = InitializationSettings( + final initializationSettings = InitializationSettings( android: initializationSettingsAndroid, iOS: initializationSettingsDarwin, ); @@ -65,23 +58,22 @@ Future createPushAvatars() async { final contacts = await twonlyDB.contactsDao.getAllNotBlockedContacts(); for (final contact in contacts) { - if (contact.avatarSvg == null) return null; + if (contact.avatarSvg == null) return; - final PictureInfo pictureInfo = + final pictureInfo = await vg.loadPicture(SvgStringLoader(contact.avatarSvg!), null); - final ui.Image image = await pictureInfo.picture.toImage(300, 300); + final image = await pictureInfo.picture.toImage(300, 300); - final ByteData? byteData = - await image.toByteData(format: ui.ImageByteFormat.png); - final Uint8List pngBytes = byteData!.buffer.asUint8List(); + final byteData = await image.toByteData(format: ui.ImageByteFormat.png); + final pngBytes = byteData!.buffer.asUint8List(); // Get the directory to save the image final directory = await getApplicationCacheDirectory(); final avatarsDirectory = Directory('${directory.path}/avatars'); // Create the avatars directory if it does not exist - if (!await avatarsDirectory.exists()) { + if (!avatarsDirectory.existsSync()) { await avatarsDirectory.create(recursive: true); } final filePath = '${avatarsDirectory.path}/${contact.userId}.png'; diff --git a/lib/src/services/signal/encryption.signal.dart b/lib/src/services/signal/encryption.signal.dart index 832c778..9307db5 100644 --- a/lib/src/services/signal/encryption.signal.dart +++ b/lib/src/services/signal/encryption.signal.dart @@ -43,18 +43,17 @@ Future signalEncryptMessage( ); } - final ECPublicKey? tempSignedPreKeyPublic = Curve.decodePoint( + final tempSignedPreKeyPublic = Curve.decodePoint( DjbECPublicKey(Uint8List.fromList(signedPreKey.signedPreKey)) .serialize(), 1, ); - final Uint8List? tempSignedPreKeySignature = Uint8List.fromList( + final tempSignedPreKeySignature = Uint8List.fromList( signedPreKey.signedPreKeySignature, ); - final IdentityKey? tempIdentityKey = - await signalStore.getIdentity(address); + final tempIdentityKey = await signalStore.getIdentity(address); if (tempIdentityKey != null) { final preKeyBundle = PreKeyBundle( target, @@ -79,9 +78,9 @@ Future signalEncryptMessage( final ciphertext = await session.encrypt(plaintextContent); - final b = BytesBuilder(); - b.add(ciphertext.serialize()); - b.add(intToBytes(ciphertext.getType())); + final b = BytesBuilder() + ..add(ciphertext.serialize()) + ..add(intToBytes(ciphertext.getType())); return b.takeBytes(); } catch (e) { diff --git a/lib/src/services/signal/prekeys.signal.dart b/lib/src/services/signal/prekeys.signal.dart index cbdd517..4f50493 100644 --- a/lib/src/services/signal/prekeys.signal.dart +++ b/lib/src/services/signal/prekeys.signal.dart @@ -1,10 +1,12 @@ +import 'dart:async'; + import 'package:drift/drift.dart'; import 'package:mutex/mutex.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/database/twonly_database.dart'; -import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart' as server; +import 'package:twonly/src/utils/log.dart'; class OtherPreKeys { OtherPreKeys({ @@ -20,21 +22,22 @@ class OtherPreKeys { } Mutex requestNewKeys = Mutex(); -DateTime lastPreKeyRequest = DateTime.now().subtract(Duration(hours: 1)); -DateTime lastSignedPreKeyRequest = DateTime.now().subtract(Duration(hours: 1)); +DateTime lastPreKeyRequest = DateTime.now().subtract(const Duration(hours: 1)); +DateTime lastSignedPreKeyRequest = + DateTime.now().subtract(const Duration(hours: 1)); Future requestNewPrekeysForContact(int contactId) async { if (lastPreKeyRequest - .isAfter(DateTime.now().subtract(Duration(seconds: 60)))) { + .isAfter(DateTime.now().subtract(const Duration(seconds: 60)))) { return; } - Log.info("Requesting new PREKEYS for $contactId"); + Log.info('Requesting new PREKEYS for $contactId'); lastPreKeyRequest = DateTime.now(); - requestNewKeys.protect(() async { + await requestNewKeys.protect(() async { final otherKeys = await apiService.getPreKeysByUserId(contactId); if (otherKeys != null) { Log.info( - "got fresh ${otherKeys.preKeys.length} pre keys from other $contactId!"); + 'got fresh ${otherKeys.preKeys.length} pre keys from other $contactId!'); final preKeys = otherKeys.preKeys .map( (preKey) => SignalContactPreKeysCompanion( @@ -46,30 +49,30 @@ Future requestNewPrekeysForContact(int contactId) async { .toList(); await twonlyDB.signalDao.insertPreKeys(preKeys); } else { - Log.error("could not load new pre keys for user $contactId"); + Log.error('could not load new pre keys for user $contactId'); } }); } Future getPreKeyByContactId(int contactId) async { - int count = await twonlyDB.signalDao.countPreKeysByContactId(contactId); + final count = await twonlyDB.signalDao.countPreKeysByContactId(contactId); if (count < 10) { - requestNewPrekeysForContact(contactId); + unawaited(requestNewPrekeysForContact(contactId)); } return twonlyDB.signalDao.popPreKeyByContactId(contactId); } Future requestNewSignedPreKeyForContact(int contactId) async { if (lastSignedPreKeyRequest - .isAfter(DateTime.now().subtract(Duration(seconds: 60)))) { - Log.info("last signed pre request was 60s before"); + .isAfter(DateTime.now().subtract(const Duration(seconds: 60)))) { + Log.info('last signed pre request was 60s before'); return; } lastSignedPreKeyRequest = DateTime.now(); await requestNewKeys.protect(() async { final signedPreKey = await apiService.getSignedKeyByUserId(contactId); if (signedPreKey != null) { - Log.info("got fresh signed pre keys from other $contactId!"); + Log.info('got fresh signed pre keys from other $contactId!'); await twonlyDB.signalDao.insertOrUpdateSignedPreKeyByContactId( SignalContactSignedPreKeysCompanion( contactId: Value(contactId), @@ -79,7 +82,7 @@ Future requestNewSignedPreKeyForContact(int contactId) async { signedPreKeyId: Value(signedPreKey.signedPrekeyId.toInt()), )); } else { - Log.error("could not load new signed pre key for user $contactId"); + Log.error('could not load new signed pre key for user $contactId'); } }); } @@ -87,19 +90,20 @@ Future requestNewSignedPreKeyForContact(int contactId) async { Future getSignedPreKeyByContactId( int contactId, ) async { - SignalContactSignedPreKey? signedPreKey = + final signedPreKey = await twonlyDB.signalDao.getSignedPreKeyByContactId(contactId); if (signedPreKey != null) { - DateTime fortyEightHoursAgo = DateTime.now().subtract(Duration(hours: 48)); - bool isOlderThan48Hours = - (signedPreKey.createdAt).isBefore(fortyEightHoursAgo); + final fortyEightHoursAgo = + DateTime.now().subtract(const Duration(hours: 48)); + final isOlderThan48Hours = + signedPreKey.createdAt.isBefore(fortyEightHoursAgo); if (isOlderThan48Hours) { - requestNewSignedPreKeyForContact(contactId); + unawaited(requestNewSignedPreKeyForContact(contactId)); } } else { - requestNewSignedPreKeyForContact(contactId); - Log.error("Contact $contactId does not have a signed pre key!"); + unawaited(requestNewSignedPreKeyForContact(contactId)); + Log.error('Contact $contactId does not have a signed pre key!'); } return signedPreKey; } diff --git a/lib/src/services/signal/session.signal.dart b/lib/src/services/signal/session.signal.dart index fb678da..19ee1a0 100644 --- a/lib/src/services/signal/session.signal.dart +++ b/lib/src/services/signal/session.signal.dart @@ -1,26 +1,24 @@ import 'dart:typed_data'; import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; -import 'package:twonly/src/model/json/userdata.dart'; import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart'; -import 'package:twonly/src/database/signal/connect_signal_protocol_store.dart'; import 'package:twonly/src/services/signal/consts.signal.dart'; import 'package:twonly/src/services/signal/utils.signal.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/storage.dart'; Future createNewSignalSession(Response_UserData userData) async { - SignalProtocolStore? signalStore = await getSignalStore(); + final SignalProtocolStore? signalStore = await getSignalStore(); if (signalStore == null) { return false; } - SignalProtocolAddress targetAddress = SignalProtocolAddress( + final targetAddress = SignalProtocolAddress( userData.userId.toString(), defaultDeviceId, ); - SessionBuilder sessionBuilder = SessionBuilder.fromSignalStore( + final sessionBuilder = SessionBuilder.fromSignalStore( signalStore, targetAddress, ); @@ -38,18 +36,18 @@ Future createNewSignalSession(Response_UserData userData) async { tempPreKeyId = userData.prekeys.first.id.toInt(); } - int tempSignedPreKeyId = userData.signedPrekeyId.toInt(); + final tempSignedPreKeyId = userData.signedPrekeyId.toInt(); - ECPublicKey? tempSignedPreKeyPublic = Curve.decodePoint( + final tempSignedPreKeyPublic = Curve.decodePoint( DjbECPublicKey(Uint8List.fromList(userData.signedPrekey)).serialize(), 1, ); - Uint8List? tempSignedPreKeySignature = Uint8List.fromList( + final tempSignedPreKeySignature = Uint8List.fromList( userData.signedPrekeySignature, ); - IdentityKey tempIdentityKey = IdentityKey( + final tempIdentityKey = IdentityKey( Curve.decodePoint( DjbECPublicKey(Uint8List.fromList(userData.publicIdentityKey)) .serialize(), @@ -57,7 +55,7 @@ Future createNewSignalSession(Response_UserData userData) async { ), ); - PreKeyBundle preKeyBundle = PreKeyBundle( + final preKeyBundle = PreKeyBundle( userData.userId.toInt(), defaultDeviceId, tempPreKeyId, @@ -72,32 +70,32 @@ Future createNewSignalSession(Response_UserData userData) async { await sessionBuilder.processPreKeyBundle(preKeyBundle); return true; } catch (e) { - Log.error("could not process pre key bundle: $e"); + Log.error('could not process pre key bundle: $e'); return false; } } Future deleteSessionWithTarget(int target) async { - ConnectSignalProtocolStore? signalStore = await getSignalStore(); + final signalStore = await getSignalStore(); if (signalStore == null) return; final address = SignalProtocolAddress(target.toString(), defaultDeviceId); await signalStore.sessionStore.deleteSession(address); } Future generateSessionFingerPrint(int target) async { - ConnectSignalProtocolStore? signalStore = await getSignalStore(); - UserData? user = await getUser(); + final signalStore = await getSignalStore(); + final user = await getUser(); if (signalStore == null || user == null) return null; try { - IdentityKey? targetIdentity = await signalStore + final targetIdentity = await signalStore .getIdentity(SignalProtocolAddress(target.toString(), defaultDeviceId)); if (targetIdentity != null) { final generator = NumericFingerprintGenerator(5200); final localFingerprint = generator.createFor( 1, - Uint8List.fromList([user.userId.toInt()]), + Uint8List.fromList([user.userId]), (await signalStore.getIdentityKeyPair()).getPublicKey(), - Uint8List.fromList([target.toInt()]), + Uint8List.fromList([target]), targetIdentity, ); diff --git a/lib/src/services/signal/utils.signal.dart b/lib/src/services/signal/utils.signal.dart index a1885cd..e883132 100644 --- a/lib/src/services/signal/utils.signal.dart +++ b/lib/src/services/signal/utils.signal.dart @@ -1,17 +1,19 @@ import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; -import 'package:twonly/src/model/json/signal_identity.dart'; import 'package:twonly/src/database/signal/connect_signal_protocol_store.dart'; +import 'package:twonly/src/model/json/signal_identity.dart'; import 'package:twonly/src/services/signal/identity.signal.dart'; Future getSignalStore() async { - return await getSignalStoreFromIdentity((await getSignalIdentity())!); + return getSignalStoreFromIdentity((await getSignalIdentity())!); } Future getSignalStoreFromIdentity( SignalIdentity signalIdentity) async { - final IdentityKeyPair identityKeyPair = + final identityKeyPair = IdentityKeyPair.fromSerialized(signalIdentity.identityKeyPairU8List); return ConnectSignalProtocolStore( - identityKeyPair, signalIdentity.registrationId.toInt()); + identityKeyPair, + signalIdentity.registrationId, + ); } diff --git a/lib/src/services/twonly_safe/common.twonly_safe.dart b/lib/src/services/twonly_safe/common.twonly_safe.dart index bafddd2..27d2189 100644 --- a/lib/src/services/twonly_safe/common.twonly_safe.dart +++ b/lib/src/services/twonly_safe/common.twonly_safe.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'package:drift/drift.dart'; import 'package:hashlib/hashlib.dart'; @@ -21,7 +22,7 @@ Future enableTwonlySafe(String password) async { ); return user; }); - performTwonlySafeBackup(force: true); + unawaited(performTwonlySafeBackup(force: true)); } Future disableTwonlySafe() async { @@ -35,9 +36,9 @@ Future disableTwonlySafe() async { // Add any other headers if required }, ); - Log.info("Download deleted with: ${response.statusCode}"); + Log.info('Download deleted with: ${response.statusCode}'); } catch (e) { - Log.error("Could not connect to the server."); + Log.error('Could not connect to the server.'); } } await updateUserdata((user) { @@ -50,21 +51,18 @@ Future<(Uint8List, Uint8List)> getMasterKey( String password, String username, ) async { - List passwordBytes = utf8.encode(password); - List saltBytes = utf8.encode(username); + final List passwordBytes = utf8.encode(password); + final List saltBytes = utf8.encode(username); // Values are derived from the Threema Whitepaper // https://threema.com/assets/documents/cryptography_whitepaper.pdf final scrypt = Scrypt( cost: 65536, - blockSize: 8, - parallelism: 1, - derivedKeyLength: 64, salt: saltBytes, ); - final key = (scrypt.convert(passwordBytes)).bytes; + final key = scrypt.convert(passwordBytes).bytes; return (key.sublist(0, 32), key.sublist(32, 64)); } @@ -81,13 +79,13 @@ Future getTwonlySafeBackupUrlFromServer( List backupId, BackupServer? backupServer, ) async { - String backupServerUrl = "https://safe.twonly.eu/"; + var backupServerUrl = 'https://safe.twonly.eu/'; if (backupServer != null) { backupServerUrl = backupServer.serverUrl; } - String backupIdHex = uint8ListToHex(backupId).toLowerCase(); + final backupIdHex = uint8ListToHex(backupId).toLowerCase(); - return "${backupServerUrl}backups/$backupIdHex"; + return '${backupServerUrl}backups/$backupIdHex'; } diff --git a/lib/src/services/twonly_safe/create_backup.twonly_safe.dart b/lib/src/services/twonly_safe/create_backup.twonly_safe.dart index 0c48785..e954c9b 100644 --- a/lib/src/services/twonly_safe/create_backup.twonly_safe.dart +++ b/lib/src/services/twonly_safe/create_backup.twonly_safe.dart @@ -1,3 +1,5 @@ +// ignore_for_file: parameter_assignments + import 'dart:convert'; import 'dart:io'; import 'package:background_downloader/background_downloader.dart'; @@ -31,8 +33,8 @@ Future performTwonlySafeBackup({bool force = false}) async { return; } - final DateTime? lastUpdateTime = user.twonlySafeBackup!.lastBackupDone; - if (!force && lastUpdateTime != null) { + final lastUpdateTime = user.twonlySafeBackup!.lastBackupDone; + if (force != true && lastUpdateTime != null) { if (lastUpdateTime .isAfter(DateTime.now().subtract(const Duration(days: 1)))) { return; @@ -179,8 +181,6 @@ Future performTwonlySafeBackup({bool force = false}) async { file: encryptedBackupBytesFile, httpRequestMethod: 'PUT', url: (await getTwonlySafeBackupUrl())!, - // requiresWiFi: true, - priority: 5, post: 'binary', retries: 2, headers: { diff --git a/lib/src/utils/log.dart b/lib/src/utils/log.dart index 39391e0..818c1b6 100644 --- a/lib/src/utils/log.dart +++ b/lib/src/utils/log.dart @@ -36,8 +36,8 @@ Future loadLogFile() async { final directory = await getApplicationSupportDirectory(); final logFile = File('${directory.path}/app.log'); - if (await logFile.exists()) { - return await logFile.readAsString(); + if (logFile.existsSync()) { + return logFile.readAsString(); } else { return 'Log file does not exist.'; } @@ -51,7 +51,7 @@ Future _writeLogToFile(LogRecord record) async { final logMessage = '${DateTime.now().toString().split(".")[0]} ${record.level.name} [twonly] ${record.loggerName} > ${record.message}\n'; - writeToLogGuard.protect(() async { + await writeToLogGuard.protect(() async { // Append the log message to the file await logFile.writeAsString(logMessage, mode: FileMode.append); }); @@ -61,7 +61,7 @@ Future deleteLogFile() async { final directory = await getApplicationSupportDirectory(); final logFile = File('${directory.path}/app.log'); - if (await logFile.exists()) { + if (logFile.existsSync()) { await logFile.delete(); return true; } @@ -69,18 +69,18 @@ Future deleteLogFile() async { } String _getCallerSourceCodeFilename() { - StackTrace stackTrace = StackTrace.current; - String stackTraceString = stackTrace.toString(); - String fileName = ""; - String lineNumber = ""; - List stackLines = stackTraceString.split('\n'); + final stackTrace = StackTrace.current; + final stackTraceString = stackTrace.toString(); + var fileName = ''; + var lineNumber = ''; + final stackLines = stackTraceString.split('\n'); if (stackLines.length > 2) { - String callerInfo = stackLines[2]; - List parts = callerInfo.split('/'); + final callerInfo = stackLines[2]; + final parts = callerInfo.split('/'); fileName = parts.last.split(':').first; // Extract the file name lineNumber = parts.last.split(':')[1]; // Extract the line number } else { - String firstLine = stackTraceString.split('\n')[0]; + final firstLine = stackTraceString.split('\n')[0]; fileName = firstLine.split('/').last.split(':').first; // Extract the file name lineNumber = firstLine.split(':')[1]; // Extract the line number diff --git a/lib/src/views/camera/camera_preview_components/permissions_view.dart b/lib/src/views/camera/camera_preview_components/permissions_view.dart index 54fc6e1..fead6f4 100644 --- a/lib/src/views/camera/camera_preview_components/permissions_view.dart +++ b/lib/src/views/camera/camera_preview_components/permissions_view.dart @@ -1,9 +1,11 @@ +// ignore_for_file: avoid_dynamic_calls + import 'package:flutter/material.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:twonly/src/utils/log.dart'; class PermissionHandlerView extends StatefulWidget { - const PermissionHandlerView({super.key, required this.onSuccess}); + const PermissionHandlerView({required this.onSuccess, super.key}); final Function onSuccess; @@ -25,7 +27,7 @@ Future checkPermissions() async { class PermissionHandlerViewState extends State { Future> permissionServices() async { // try { - Map statuses = await [ + final statuses = await [ Permission.camera, // Permission.microphone, Permission.notification @@ -57,18 +59,17 @@ class PermissionHandlerViewState extends State { return Scaffold( body: Center( child: Container( - padding: EdgeInsets.all(100), + padding: const EdgeInsets.all(100), child: Column( mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - "twonly needs access to the camera and microphone.", + const Text( + 'twonly needs access to the camera and microphone.', textAlign: TextAlign.center, ), - SizedBox(height: 50), + const SizedBox(height: 50), FilledButton.icon( - label: Text("Request permissions"), + label: const Text('Request permissions'), icon: const Icon(Icons.perm_camera_mic), onPressed: () async { try { diff --git a/lib/src/views/camera/camera_preview_components/save_to_gallery.dart b/lib/src/views/camera/camera_preview_components/save_to_gallery.dart index e4cc35f..111adbe 100644 --- a/lib/src/views/camera/camera_preview_components/save_to_gallery.dart +++ b/lib/src/views/camera/camera_preview_components/save_to_gallery.dart @@ -1,31 +1,31 @@ +import 'dart:async'; import 'dart:io'; import 'dart:math'; +import 'dart:typed_data'; + import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:path/path.dart'; import 'package:twonly/src/services/api/media_upload.dart'; import 'package:twonly/src/services/thumbnail.service.dart'; -import 'dart:typed_data'; - import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/storage.dart'; class SaveToGalleryButton extends StatefulWidget { + const SaveToGalleryButton({ + required this.getMergedImage, + required this.isLoading, + required this.displayButtonLabel, + super.key, + this.mediaUploadId, + this.videoFilePath, + }); final Future Function() getMergedImage; final bool displayButtonLabel; final File? videoFilePath; final int? mediaUploadId; final bool isLoading; - const SaveToGalleryButton({ - super.key, - required this.getMergedImage, - required this.isLoading, - required this.displayButtonLabel, - this.mediaUploadId, - this.videoFilePath, - }); - @override State createState() => SaveToGalleryButtonState(); } @@ -53,33 +53,33 @@ class SaveToGalleryButtonState extends State { }); String? res; - String memoryPath = await getMediaBaseFilePath("memories"); + var memoryPath = await getMediaBaseFilePath('memories'); if (widget.mediaUploadId != null) { - memoryPath = join(memoryPath, "${widget.mediaUploadId!}"); + memoryPath = join(memoryPath, '${widget.mediaUploadId!}'); } else { - final Random random = Random(); - String token = uint8ListToHex( + final random = Random(); + final token = uint8ListToHex( List.generate(32, (i) => random.nextInt(256))); memoryPath = join(memoryPath, token); } final user = await getUser(); if (user == null) return; - bool storeToGallery = user.storeMediaFilesInGallery; + final storeToGallery = user.storeMediaFilesInGallery; if (widget.videoFilePath != null) { - memoryPath += ".mp4"; + memoryPath += '.mp4'; await File(widget.videoFilePath!.path).copy(memoryPath); - createThumbnailsForVideo(File(memoryPath)); + unawaited(createThumbnailsForVideo(File(memoryPath))); if (storeToGallery) { res = await saveVideoToGallery(widget.videoFilePath!.path); } } else { - memoryPath += ".png"; - Uint8List? imageBytes = await widget.getMergedImage(); + memoryPath += '.png'; + final imageBytes = await widget.getMergedImage(); if (imageBytes == null || !mounted) return; await File(memoryPath).writeAsBytes(imageBytes); - createThumbnailsForImage(File(memoryPath)); + unawaited(createThumbnailsForImage(File(memoryPath))); if (storeToGallery) { res = await saveImageToGallery(imageBytes); } @@ -92,7 +92,7 @@ class SaveToGalleryButtonState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(res), - duration: Duration(seconds: 3), + duration: const Duration(seconds: 3), ), ); } @@ -102,15 +102,16 @@ class SaveToGalleryButtonState extends State { }, child: Row( children: [ - (_imageSaving || widget.isLoading) - ? SizedBox( - width: 12, - height: 12, - child: CircularProgressIndicator(strokeWidth: 1)) - : _imageSaved - ? Icon(Icons.check) - : FaIcon(FontAwesomeIcons.floppyDisk), - if (widget.displayButtonLabel) SizedBox(width: 10), + if (_imageSaving || widget.isLoading) + const SizedBox( + width: 12, + height: 12, + child: CircularProgressIndicator(strokeWidth: 1)) + else + _imageSaved + ? const Icon(Icons.check) + : const FaIcon(FontAwesomeIcons.floppyDisk), + if (widget.displayButtonLabel) const SizedBox(width: 10), if (widget.displayButtonLabel) Text(_imageSaved ? context.lang.shareImagedEditorSavedImage diff --git a/lib/src/views/camera/camera_preview_components/send_to.dart b/lib/src/views/camera/camera_preview_components/send_to.dart index 6992f1e..b061a9b 100644 --- a/lib/src/views/camera/camera_preview_components/send_to.dart +++ b/lib/src/views/camera/camera_preview_components/send_to.dart @@ -2,29 +2,28 @@ import 'package:flutter/material.dart'; import 'package:twonly/src/utils/misc.dart'; class SendToWidget extends StatelessWidget { - final String sendTo; - const SendToWidget({ - super.key, required this.sendTo, + super.key, }); + final String sendTo; @override Widget build(BuildContext context) { - TextStyle textStyle = TextStyle( + const textStyle = TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 24, decoration: TextDecoration.none, shadows: [ Shadow( - color: const Color.fromARGB(122, 0, 0, 0), - blurRadius: 5.0, + color: Color.fromARGB(122, 0, 0, 0), + blurRadius: 5, ), ], ); - TextStyle boldTextStyle = textStyle.copyWith( + final boldTextStyle = textStyle.copyWith( fontWeight: FontWeight.normal, fontSize: 28, ); diff --git a/lib/src/views/camera/camera_preview_components/video_recording_time.dart b/lib/src/views/camera/camera_preview_components/video_recording_time.dart index 27f9c37..a2478cb 100644 --- a/lib/src/views/camera/camera_preview_components/video_recording_time.dart +++ b/lib/src/views/camera/camera_preview_components/video_recording_time.dart @@ -1,14 +1,13 @@ import 'package:flutter/material.dart'; class VideoRecordingTimer extends StatelessWidget { - final DateTime? videoRecordingStarted; - final int maxVideoRecordingTime; - const VideoRecordingTimer({ - super.key, required this.videoRecordingStarted, required this.maxVideoRecordingTime, + super.key, }); + final DateTime? videoRecordingStarted; + final int maxVideoRecordingTime; @override Widget build(BuildContext context) { @@ -26,11 +25,12 @@ class VideoRecordingTimer extends StatelessWidget { children: [ Center( child: CircularProgressIndicator( - value: (currentTime.difference(videoRecordingStarted!)) + value: currentTime + .difference(videoRecordingStarted!) .inMilliseconds / (maxVideoRecordingTime * 1000), strokeWidth: 4, - valueColor: AlwaysStoppedAnimation(Colors.red), + valueColor: const AlwaysStoppedAnimation(Colors.red), backgroundColor: Colors.grey[300], ), ), @@ -46,7 +46,7 @@ class VideoRecordingTimer extends StatelessWidget { shadows: [ Shadow( color: Color.fromARGB(122, 0, 0, 0), - blurRadius: 5.0, + blurRadius: 5, ) ], ), diff --git a/lib/src/views/camera/camera_preview_components/zoom_selector.dart b/lib/src/views/camera/camera_preview_components/zoom_selector.dart index 08c1d5b..c4c7e19 100644 --- a/lib/src/views/camera/camera_preview_components/zoom_selector.dart +++ b/lib/src/views/camera/camera_preview_components/zoom_selector.dart @@ -1,14 +1,17 @@ +// ignore_for_file: avoid_dynamic_calls + import 'dart:math'; import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; class CameraZoomButtons extends StatefulWidget { - const CameraZoomButtons( - {super.key, - required this.controller, - required this.updateScaleFactor, - required this.scaleFactor}); + const CameraZoomButtons({ + required this.controller, + required this.updateScaleFactor, + required this.scaleFactor, + super.key, + }); final CameraController controller; final double scaleFactor; @@ -20,7 +23,7 @@ class CameraZoomButtons extends StatefulWidget { String beautifulZoomScale(double scale) { var tmp = scale.toStringAsFixed(1); - if (tmp[0] == "0") { + if (tmp[0] == '0') { tmp = tmp.substring(1, tmp.length); } return tmp; @@ -50,20 +53,20 @@ class _CameraZoomButtonsState extends State { @override Widget build(BuildContext context) { - var zoomButtonStyle = TextButton.styleFrom( + final zoomButtonStyle = TextButton.styleFrom( padding: EdgeInsets.zero, foregroundColor: Colors.white, - minimumSize: Size(40, 40), + minimumSize: const Size(40, 40), alignment: Alignment.center, tapTargetSize: MaterialTapTargetSize.shrinkWrap, ); - final zoomTextStyle = TextStyle(fontSize: 13); + const zoomTextStyle = TextStyle(fontSize: 13); final isMiddleFocused = widget.scaleFactor >= 1 && widget.scaleFactor < 2; return Center( child: ClipRRect( - borderRadius: BorderRadius.circular(40.0), - child: Container( + borderRadius: BorderRadius.circular(40), + child: ColoredBox( color: const Color.fromARGB(90, 0, 0, 0), child: Row( mainAxisAlignment: MainAxisAlignment.center, @@ -76,25 +79,24 @@ class _CameraZoomButtonsState extends State { ), ), onPressed: () async { - var level = await widget.controller.getMinZoomLevel(); + final level = await widget.controller.getMinZoomLevel(); widget.updateScaleFactor(level); }, child: FutureBuilder( future: widget.controller.getMinZoomLevel(), builder: (context, snap) { if (snap.hasData) { - var minLevel = - beautifulZoomScale(snap.data!.toDouble()); - var currentLevel = + final minLevel = beautifulZoomScale(snap.data!); + final currentLevel = beautifulZoomScale(widget.scaleFactor); return Text( widget.scaleFactor < 1 - ? "${currentLevel}x" - : "${minLevel}x", + ? '${currentLevel}x' + : '${minLevel}x', style: zoomTextStyle, ); } else { - return Text(""); + return const Text(''); } }, ), @@ -109,9 +111,9 @@ class _CameraZoomButtonsState extends State { widget.updateScaleFactor(1.0); }, child: Text( - (isMiddleFocused) - ? "${beautifulZoomScale(widget.scaleFactor)}x" - : "1.0x", + isMiddleFocused + ? '${beautifulZoomScale(widget.scaleFactor)}x' + : '1.0x', style: zoomTextStyle, )), TextButton( @@ -121,23 +123,24 @@ class _CameraZoomButtonsState extends State { ), ), onPressed: () async { - var level = min(await widget.controller.getMaxZoomLevel(), 2) - .toDouble(); + final level = + min(await widget.controller.getMaxZoomLevel(), 2) + .toDouble(); widget.updateScaleFactor(level); }, child: FutureBuilder( future: widget.controller.getMaxZoomLevel(), builder: (context, snap) { if (snap.hasData) { - var maxLevel = max( + final maxLevel = max( min((snap.data?.toInt())!, 2), widget.scaleFactor, ); return Text( - "${beautifulZoomScale(maxLevel.toDouble())}x", + '${beautifulZoomScale(maxLevel.toDouble())}x', style: zoomTextStyle); } else { - return Text(""); + return const Text(''); } }), ) diff --git a/lib/src/views/camera/camera_preview_controller_view.dart b/lib/src/views/camera/camera_preview_controller_view.dart index 612ed5a..0c02967 100644 --- a/lib/src/views/camera/camera_preview_controller_view.dart +++ b/lib/src/views/camera/camera_preview_controller_view.dart @@ -26,26 +26,28 @@ import 'package:twonly/src/views/home.view.dart'; int maxVideoRecordingTime = 15; Future<(SelectedCameraDetails, CameraController)?> initializeCameraController( - SelectedCameraDetails details, - int sCameraId, - bool init, - bool enableAudio) async { - if (sCameraId >= gCameras.length) return null; + SelectedCameraDetails details, + int sCameraId, + bool init, + bool enableAudio, +) async { + var cameraId = sCameraId; + if (cameraId >= gCameras.length) return null; if (init) { - for (; sCameraId < gCameras.length; sCameraId++) { - if (gCameras[sCameraId].lensDirection == CameraLensDirection.back) { + for (; cameraId < gCameras.length; cameraId++) { + if (gCameras[cameraId].lensDirection == CameraLensDirection.back) { break; } } } details.isZoomAble = false; - if (details.cameraId != sCameraId) { + if (details.cameraId != cameraId) { // switch between front and back details.scaleFactor = 1; } final cameraController = CameraController( - gCameras[sCameraId], + gCameras[cameraId], ResolutionPreset.high, enableAudio: enableAudio, ); @@ -64,9 +66,9 @@ Future<(SelectedCameraDetails, CameraController)?> initializeCameraController( details ..isZoomAble = details.maxAvailableZoom != details.minAvailableZoom ..cameraLoaded = true - ..cameraId = sCameraId; + ..cameraId = cameraId; }).catchError((Object e) { - Log.error("$e"); + Log.error('$e'); }); return (details, cameraController); } @@ -213,7 +215,7 @@ class _CameraPreviewViewState extends State { Future loadAndDeletePictureFromFile(XFile picture) async { try { // Load the image into bytes - final Uint8List imageBytes = await picture.readAsBytes(); + final imageBytes = await picture.readAsBytes(); // Remove the image file await File(picture.path).delete(); return imageBytes; @@ -400,7 +402,7 @@ class _CameraPreviewViewState extends State { videoRecordingTimer = null; } if (cameraController == null || !cameraController!.value.isRecordingVideo) { - return null; + return; } try { @@ -414,8 +416,8 @@ class _CameraPreviewViewState extends State { if (videoPath != null) { if (Platform.isAndroid) { // see https://github.com/flutter/flutter/issues/148335 - await File(videoPath.path).rename("${videoPath.path}.mp4"); - videoPathFile = File("${videoPath.path}.mp4"); + await File(videoPath.path).rename('${videoPath.path}.mp4'); + videoPathFile = File('${videoPath.path}.mp4'); } else { videoPathFile = File(videoPath.path); } @@ -426,12 +428,12 @@ class _CameraPreviewViewState extends State { } } on CameraException catch (e) { _showCameraException(e); - return null; + return; } } void _showCameraException(dynamic e) { - Log.error("$e"); + Log.error('$e'); try { if (context.mounted) { // ignore: use_build_context_synchronously @@ -536,10 +538,12 @@ class _CameraPreviewViewState extends State { : Colors.white.withAlpha(160), onPressed: () async { if (selectedCameraDetails.isFlashOn) { - cameraController?.setFlashMode(FlashMode.off); + await cameraController + ?.setFlashMode(FlashMode.off); selectedCameraDetails.isFlashOn = false; } else { - cameraController?.setFlashMode(FlashMode.always); + await cameraController + ?.setFlashMode(FlashMode.always); selectedCameraDetails.isFlashOn = true; } setState(() {}); @@ -566,16 +570,16 @@ class _CameraPreviewViewState extends State { Icons.mic_off_rounded, color: Colors.white.withAlpha(160), tooltipText: - "Allow microphone access for video recording.", + 'Allow microphone access for video recording.', onPressed: requestMicrophonePermission, ), if (hasAudioPermission) ActionButton( - (videoWithAudio) + videoWithAudio ? Icons.volume_up_rounded : Icons.volume_off_rounded, - tooltipText: "Record video with audio.", - color: (videoWithAudio) + tooltipText: 'Record video with audio.', + color: videoWithAudio ? Colors.white : Colors.white.withAlpha(160), onPressed: () async { @@ -614,13 +618,11 @@ class _CameraPreviewViewState extends State { const SizedBox(height: 30), Row( mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, children: [ if (!isVideoRecording) GestureDetector( onTap: pickImageFromGallery, child: Align( - alignment: Alignment.center, child: Container( height: 50, width: 80, @@ -640,7 +642,6 @@ class _CameraPreviewViewState extends State { // onLongPress: startVideoRecording, key: keyTriggerButton, child: Align( - alignment: Alignment.center, child: Container( height: 100, width: 100, diff --git a/lib/src/views/camera/camera_send_to_view.dart b/lib/src/views/camera/camera_send_to_view.dart index c0d572b..3955c50 100644 --- a/lib/src/views/camera/camera_send_to_view.dart +++ b/lib/src/views/camera/camera_send_to_view.dart @@ -44,7 +44,7 @@ class CameraSendToViewState extends State { Future toggleSelectedCamera() async { await cameraController?.dispose(); cameraController = null; - selectCamera((selectedCameraDetails.cameraId + 1) % 2, false, false); + await selectCamera((selectedCameraDetails.cameraId + 1) % 2, false, false); } @override @@ -54,7 +54,7 @@ class CameraSendToViewState extends State { onDoubleTap: toggleSelectedCamera, child: Stack( children: [ - SendToCameraPreview(), + const SendToCameraPreview(), CameraPreviewControllerView( selectCamera: selectCamera, sendTo: widget.sendTo, diff --git a/lib/src/views/camera/image_editor/action_button.dart b/lib/src/views/camera/image_editor/action_button.dart index 3d43fcb..b5d84e9 100644 --- a/lib/src/views/camera/image_editor/action_button.dart +++ b/lib/src/views/camera/image_editor/action_button.dart @@ -2,19 +2,20 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; class ActionButton extends StatelessWidget { + const ActionButton( + this.icon, { + required this.tooltipText, + super.key, + this.onPressed, + this.color, + this.disable = false, + }); final VoidCallback? onPressed; final IconData? icon; final Color? color; final String tooltipText; final bool disable; - const ActionButton(this.icon, - {super.key, - this.onPressed, - this.color, - required this.tooltipText, - this.disable = false}); - @override Widget build(BuildContext context) { return Tooltip( @@ -26,10 +27,10 @@ class ActionButton extends StatelessWidget { color: disable ? const Color.fromARGB(154, 255, 255, 255) : color ?? Colors.white, - shadows: [ + shadows: const [ Shadow( - color: const Color.fromARGB(122, 0, 0, 0), - blurRadius: 5.0, + color: Color.fromARGB(122, 0, 0, 0), + blurRadius: 5, ) ], ), diff --git a/lib/src/views/camera/image_editor/data/image_item.dart b/lib/src/views/camera/image_editor/data/image_item.dart index a429698..5b3ddb4 100755 --- a/lib/src/views/camera/image_editor/data/image_item.dart +++ b/lib/src/views/camera/image_editor/data/image_item.dart @@ -3,15 +3,14 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; class ImageItem { + ImageItem([dynamic image]) { + if (image != null) load(image); + } int width = 1; int height = 1; Uint8List bytes = Uint8List.fromList([]); Completer loader = Completer(); - ImageItem([dynamic image]) { - if (image != null) load(image); - } - Future load(dynamic image) async { loader = Completer(); @@ -24,7 +23,7 @@ class ImageItem { return loader.complete(true); } else if (image is Uint8List) { bytes = image; - var decodedImage = await decodeImageFromList(bytes); + final decodedImage = await decodeImageFromList(bytes); height = decodedImage.height; width = decodedImage.width; diff --git a/lib/src/views/camera/image_editor/data/layer.dart b/lib/src/views/camera/image_editor/data/layer.dart index cffa374..c2a8e42 100755 --- a/lib/src/views/camera/image_editor/data/layer.dart +++ b/lib/src/views/camera/image_editor/data/layer.dart @@ -1,18 +1,13 @@ +// ignore_for_file: comment_references + import 'package:flutter/material.dart'; import 'package:hand_signature/signature.dart'; import 'package:twonly/src/views/camera/image_editor/data/image_item.dart'; /// Layer class with some common properties class Layer { - Offset offset; - double rotation, scale, opacity; - bool isEditing; - bool isDeleted; - bool hasCustomActionButtons; - bool showCustomButtons; - Layer({ - this.offset = const Offset(0, 0), + this.offset = Offset.zero, this.opacity = 1, this.isEditing = false, this.isDeleted = false, @@ -21,24 +16,28 @@ class Layer { this.rotation = 0, this.scale = 1, }); + Offset offset; + double rotation; + double scale; + double opacity; + bool isEditing; + bool isDeleted; + bool hasCustomActionButtons; + bool showCustomButtons; } /// Attributes used by [BackgroundLayer] class BackgroundLayerData extends Layer { - ImageItem image; - BackgroundLayerData({ required this.image, }); + ImageItem image; } class FilterLayerData extends Layer {} /// Attributes used by [EmojiLayer] class EmojiLayerData extends Layer { - String text; - double size; - EmojiLayerData({ this.text = '', this.size = 64, @@ -48,31 +47,27 @@ class EmojiLayerData extends Layer { super.scale, super.isEditing, }); + String text; + double size; } /// Attributes used by [TextLayer] class TextLayerData extends Layer { - String text; - int textLayersBefore; TextLayerData({ - this.text = "", required this.textLayersBefore, + this.text = '', super.offset, super.opacity, super.rotation, super.scale, super.isEditing = true, }); + String text; + int textLayersBefore; } /// Attributes used by [DrawLayer] class DrawLayerData extends Layer { - final control = HandSignatureControl( - threshold: 3.0, - smoothRatio: 0.65, - velocityRange: 2.0, - ); - // String text; DrawLayerData({ super.offset, @@ -82,4 +77,5 @@ class DrawLayerData extends Layer { super.hasCustomActionButtons = true, super.isEditing = true, }); + final control = HandSignatureControl(); } diff --git a/lib/src/views/camera/image_editor/layers/background_layer.dart b/lib/src/views/camera/image_editor/layers/background_layer.dart index bfea351..e69ca60 100755 --- a/lib/src/views/camera/image_editor/layers/background_layer.dart +++ b/lib/src/views/camera/image_editor/layers/background_layer.dart @@ -3,14 +3,13 @@ import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; /// Main layer class BackgroundLayer extends StatefulWidget { - final BackgroundLayerData layerData; - final VoidCallback? onUpdate; - const BackgroundLayer({ - super.key, required this.layerData, + super.key, this.onUpdate, }); + final BackgroundLayerData layerData; + final VoidCallback? onUpdate; @override State createState() => _BackgroundLayerState(); diff --git a/lib/src/views/camera/image_editor/layers/draw_layer.dart b/lib/src/views/camera/image_editor/layers/draw_layer.dart index 0130ccb..22facf4 100644 --- a/lib/src/views/camera/image_editor/layers/draw_layer.dart +++ b/lib/src/views/camera/image_editor/layers/draw_layer.dart @@ -2,27 +2,26 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:hand_signature/signature.dart'; import 'package:screenshot/screenshot.dart'; +import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/views/camera/image_editor/action_button.dart'; import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; -import 'package:twonly/src/utils/misc.dart'; class DrawLayer extends StatefulWidget { - final DrawLayerData layerData; - final VoidCallback? onUpdate; - const DrawLayer({ - super.key, required this.layerData, + super.key, this.onUpdate, }); + final DrawLayerData layerData; + final VoidCallback? onUpdate; @override - createState() => _DrawLayerState(); + State createState() => _DrawLayerState(); } class _DrawLayerState extends State { Color currentColor = Colors.red; - var screenshotController = ScreenshotController(); + ScreenshotController screenshotController = ScreenshotController(); List undoList = []; bool skipNextEvent = false; @@ -48,7 +47,7 @@ class _DrawLayerState extends State { double _sliderValue = 0.125; - final colors = [ + final List colors = [ Colors.white, Colors.red, Colors.orange, @@ -61,11 +60,11 @@ class _DrawLayerState extends State { Color _getColorFromSliderValue(double value) { // Calculate the index based on the slider value - int index = (value * (colors.length - 1)).floor(); - int nextIndex = (index + 1).clamp(0, colors.length - 1); + final index = (value * (colors.length - 1)).floor(); + final nextIndex = (index + 1).clamp(0, colors.length - 1); // Calculate the interpolation factor - double factor = value * (colors.length - 1) - index; + final factor = value * (colors.length - 1) - index; // Interpolate between the two colors return Color.lerp(colors[index], colors[nextIndex], factor)!; @@ -85,17 +84,14 @@ class _DrawLayerState extends State { children: [ Positioned.fill( child: Container( - decoration: BoxDecoration( + decoration: const BoxDecoration( color: Colors.transparent, ), child: Screenshot( controller: screenshotController, child: HandSignature( control: widget.layerData.control, - color: currentColor, - width: 1.0, - maxWidth: 7.0, - type: SignatureDrawType.shape, + drawer: LineSignatureDrawer(color: currentColor, width: 7), ), ), ), @@ -112,9 +108,7 @@ class _DrawLayerState extends State { tooltipText: context.lang.imageEditorDrawOk, onPressed: () async { widget.layerData.isEditing = false; - if (widget.onUpdate != null) { - widget.onUpdate!(); - } + widget.onUpdate!(); setState(() {}); }, ), @@ -200,8 +194,6 @@ class _DrawLayerState extends State { showMagnifyingGlass = false; }) }, - min: 0.0, - max: 1.0, divisions: 100, ), ), @@ -226,10 +218,9 @@ class _DrawLayerState extends State { } class MagnifyingGlass extends StatelessWidget { + const MagnifyingGlass({required this.color, super.key}); final Color color; - const MagnifyingGlass({super.key, required this.color}); - @override Widget build(BuildContext context) { return SizedBox( diff --git a/lib/src/views/camera/image_editor/layers/emoji_layer.dart b/lib/src/views/camera/image_editor/layers/emoji_layer.dart index a5ff29a..30c795b 100755 --- a/lib/src/views/camera/image_editor/layers/emoji_layer.dart +++ b/lib/src/views/camera/image_editor/layers/emoji_layer.dart @@ -68,9 +68,7 @@ class _EmojiLayerState extends State { } if (deleteLayer) { widget.layerData.isDeleted = true; - if (widget.onUpdate != null) { - widget.onUpdate!(); - } + widget.onUpdate!(); } }); }, @@ -138,7 +136,7 @@ class _EmojiLayerState extends State { padding: const EdgeInsets.all(44), color: Colors.transparent, child: Text( - widget.layerData.text.toString(), + widget.layerData.text, style: TextStyle( fontSize: widget.layerData.size, ), @@ -157,7 +155,7 @@ class _EmojiLayerState extends State { child: GestureDetector( child: ActionButton( FontAwesomeIcons.trashCan, - tooltipText: "", + tooltipText: '', color: deleteLayer ? Colors.red : Colors.white, ), ), diff --git a/lib/src/views/camera/image_editor/layers/filter_layer.dart b/lib/src/views/camera/image_editor/layers/filter_layer.dart index 0e4b98c..b5318f6 100644 --- a/lib/src/views/camera/image_editor/layers/filter_layer.dart +++ b/lib/src/views/camera/image_editor/layers/filter_layer.dart @@ -60,7 +60,7 @@ class FilterText extends StatelessWidget { shadows: const [ Shadow( color: Color.fromARGB(122, 0, 0, 0), - blurRadius: 5.0, + blurRadius: 5, ) ], ), diff --git a/lib/src/views/camera/image_editor/layers/filters/datetime_filter.dart b/lib/src/views/camera/image_editor/layers/filters/datetime_filter.dart index 9d175db..0382721 100644 --- a/lib/src/views/camera/image_editor/layers/filters/datetime_filter.dart +++ b/lib/src/views/camera/image_editor/layers/filters/datetime_filter.dart @@ -9,8 +9,8 @@ class DateTimeFilter extends StatelessWidget { @override Widget build(BuildContext context) { - String currentTime = DateFormat('HH:mm').format(DateTime.now()); - String currentDate = DateFormat('dd.MM.yyyy').format(DateTime.now()); + final currentTime = DateFormat('HH:mm').format(DateTime.now()); + final currentDate = DateFormat('dd.MM.yyyy').format(DateTime.now()); return FilterSkeleton( child: Positioned( bottom: 80, diff --git a/lib/src/views/camera/image_editor/layers/filters/image_filter.dart b/lib/src/views/camera/image_editor/layers/filters/image_filter.dart index 6c6629d..25e1b90 100644 --- a/lib/src/views/camera/image_editor/layers/filters/image_filter.dart +++ b/lib/src/views/camera/image_editor/layers/filters/image_filter.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:twonly/src/views/camera/image_editor/layers/filter_layer.dart'; class ImageFilter extends StatelessWidget { - const ImageFilter({super.key, required this.imagePath}); + const ImageFilter({required this.imagePath, super.key}); final String imagePath; @override @@ -15,7 +15,7 @@ class ImageFilter extends StatelessWidget { right: 10, child: Center( child: CachedNetworkImage( - imageUrl: "https://twonly.eu/$imagePath", + imageUrl: 'https://twonly.eu/$imagePath', height: 150, ), ), diff --git a/lib/src/views/camera/image_editor/layers/filters/location_filter.dart b/lib/src/views/camera/image_editor/layers/filters/location_filter.dart index ad2aa5a..529b1d4 100644 --- a/lib/src/views/camera/image_editor/layers/filters/location_filter.dart +++ b/lib/src/views/camera/image_editor/layers/filters/location_filter.dart @@ -99,7 +99,6 @@ class _LocationFilterState extends State { bottom: 50, left: 40, child: Column( - mainAxisAlignment: MainAxisAlignment.start, children: [ FilterText(location!.city), FilterText(location!.county), @@ -131,8 +130,8 @@ Future> getStickerIndex() async { final indexFile = File('${directory.path}/stickers.json'); var res = []; - if (await indexFile.exists() && !kDebugMode) { - final lastModified = await indexFile.lastModified(); + if (indexFile.existsSync() && !kDebugMode) { + final lastModified = indexFile.lastModifiedSync(); final difference = DateTime.now().difference(lastModified); final content = await indexFile.readAsString(); final jsonList = json.decode(content) as List; diff --git a/lib/src/views/camera/image_editor/layers/text_layer.dart b/lib/src/views/camera/image_editor/layers/text_layer.dart index db30d54..a1ce9a9 100755 --- a/lib/src/views/camera/image_editor/layers/text_layer.dart +++ b/lib/src/views/camera/image_editor/layers/text_layer.dart @@ -1,3 +1,5 @@ +// ignore_for_file: prefer_null_aware_method_calls + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; @@ -8,16 +10,15 @@ import 'package:twonly/src/views/camera/image_editor/data/layer.dart'; /// Text layer class TextLayer extends StatefulWidget { - final TextLayerData layerData; - final VoidCallback? onUpdate; - const TextLayer({ - super.key, required this.layerData, + super.key, this.onUpdate, }); + final TextLayerData layerData; + final VoidCallback? onUpdate; @override - createState() => _TextViewState(); + State createState() => _TextViewState(); } class _TextViewState extends State { @@ -69,7 +70,7 @@ class _TextViewState extends State { minLines: 1, onEditingComplete: () { setState(() { - widget.layerData.isDeleted = textController.text == ""; + widget.layerData.isDeleted = textController.text == ''; widget.layerData.isEditing = false; widget.layerData.text = textController.text; }); @@ -83,10 +84,10 @@ class _TextViewState extends State { }, onTapOutside: (a) { widget.layerData.text = textController.text; - Future.delayed(Duration(milliseconds: 100), () { + Future.delayed(const Duration(milliseconds: 100), () { if (context.mounted) { setState(() { - widget.layerData.isDeleted = textController.text == ""; + widget.layerData.isDeleted = textController.text == ''; widget.layerData.isEditing = false; context .read() @@ -102,10 +103,10 @@ class _TextViewState extends State { .read() .updateSomeTextViewIsAlreadyEditing(false); }, - decoration: InputDecoration( + decoration: const InputDecoration( border: InputBorder.none, isDense: true, - contentPadding: const EdgeInsets.symmetric( + contentPadding: EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), @@ -136,7 +137,7 @@ class _TextViewState extends State { onScaleEnd: (d) { if (deleteLayer) { widget.layerData.isDeleted = true; - textController.text = ""; + textController.text = ''; } elementIsScaled = false; if (widget.onUpdate != null) { @@ -161,8 +162,8 @@ class _TextViewState extends State { widget.layerData.offset = Offset( 0, widget.layerData.offset.dy + detail.focalPointDelta.dy); } - final RenderBox renderBox = - _widgetKey.currentContext!.findRenderObject() as RenderBox; + final renderBox = + _widgetKey.currentContext!.findRenderObject()! as RenderBox; if (widget.layerData.offset.dy > renderBox.size.height - 80) { if (!deleteLayer) { @@ -198,11 +199,11 @@ class _TextViewState extends State { child: Center( child: GestureDetector( onTapUp: (d) { - textController.text = ""; + textController.text = ''; }, child: ActionButton( FontAwesomeIcons.trashCan, - tooltipText: "", + tooltipText: '', color: deleteLayer ? Colors.red : Colors.white, ), ), diff --git a/lib/src/views/camera/image_editor/modules/all_emojis.dart b/lib/src/views/camera/image_editor/modules/all_emojis.dart index a3e2aed..c995b4e 100755 --- a/lib/src/views/camera/image_editor/modules/all_emojis.dart +++ b/lib/src/views/camera/image_editor/modules/all_emojis.dart @@ -7,7 +7,7 @@ class Emojis extends StatefulWidget { const Emojis({super.key}); @override - createState() => _EmojisState(); + State createState() => _EmojisState(); } class _EmojisState extends State { @@ -57,7 +57,7 @@ class _EmojisState extends State { Widget build(BuildContext context) { return SingleChildScrollView( child: Container( - padding: const EdgeInsets.all(0.0), + padding: EdgeInsets.zero, height: 400, decoration: const BoxDecoration( borderRadius: BorderRadius.only( @@ -77,14 +77,12 @@ class _EmojisState extends State { const SizedBox(height: 16), Container( height: 315, - padding: const EdgeInsets.all(0.0), + padding: EdgeInsets.zero, child: GridView( shrinkWrap: true, physics: const ClampingScrollPhysics(), - scrollDirection: Axis.vertical, gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 0.0, - maxCrossAxisExtent: 60.0, + maxCrossAxisExtent: 60, ), children: lastUsed.map((String emoji) { return GridTile( diff --git a/lib/src/views/camera/share_image_components/best_friends_selector.dart b/lib/src/views/camera/share_image_components/best_friends_selector.dart index c372b7a..a58d9bc 100644 --- a/lib/src/views/camera/share_image_components/best_friends_selector.dart +++ b/lib/src/views/camera/share_image_components/best_friends_selector.dart @@ -58,7 +58,7 @@ class BestFriendsSelector extends StatelessWidget { color: Color.fromRGBO(0, 0, 0, 0.1), ), ], - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(8), ), child: Text(context.lang.shareImagedSelectAll, style: const TextStyle(fontSize: 10)), @@ -143,7 +143,7 @@ class UserCheckbox extends StatelessWidget { color: Color.fromRGBO(0, 0, 0, 0.1), ), ], - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(8), ), child: Row( children: [ diff --git a/lib/src/views/camera/share_image_editor_view.dart b/lib/src/views/camera/share_image_editor_view.dart index 7195094..0bf66da 100644 --- a/lib/src/views/camera/share_image_editor_view.dart +++ b/lib/src/views/camera/share_image_editor_view.dart @@ -61,7 +61,9 @@ class _ShareImageEditorView extends State { bool loadingImage = true; bool isDisposed = false; HashSet selectedUserIds = HashSet(); - double widthRatio = 1, heightRatio = 1, pixelRatio = 1; + double widthRatio = 1; + double heightRatio = 1; + double pixelRatio = 1; VideoPlayerController? videoController; ImageItem currentImage = ImageItem(); ScreenshotController screenshotController = ScreenshotController(); @@ -93,7 +95,7 @@ class _ShareImageEditorView extends State { } } - void initAsync() async { + Future initAsync() async { final user = await getUser(); if (user == null) return; if (user.defaultShowTime != null) { diff --git a/lib/src/views/camera/share_image_view.dart b/lib/src/views/camera/share_image_view.dart index ab1ea44..35a2d0b 100644 --- a/lib/src/views/camera/share_image_view.dart +++ b/lib/src/views/camera/share_image_view.dart @@ -56,7 +56,7 @@ class _ShareImageView extends State { final TextEditingController searchUserName = TextEditingController(); bool showRealTwonlyWarning = false; late StreamSubscription> contactSub; - String lastQuery = ""; + String lastQuery = ''; @override void initState() { diff --git a/lib/src/views/chats/chat_list_components/backup_notice.card.dart b/lib/src/views/chats/chat_list_components/backup_notice.card.dart index fa0525b..4241670 100644 --- a/lib/src/views/chats/chat_list_components/backup_notice.card.dart +++ b/lib/src/views/chats/chat_list_components/backup_notice.card.dart @@ -39,9 +39,9 @@ class _BackupNoticeCardState extends State { return Card( elevation: 4, - margin: EdgeInsets.all(10), + margin: const EdgeInsets.all(10), child: Padding( - padding: const EdgeInsets.all(10.0), + padding: const EdgeInsets.all(10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -52,7 +52,7 @@ class _BackupNoticeCardState extends State { fontWeight: FontWeight.bold, ), ), - SizedBox(height: 5), + const SizedBox(height: 5), Text( context.lang.backupNoticeDesc, style: const TextStyle(fontSize: 14), @@ -64,20 +64,20 @@ class _BackupNoticeCardState extends State { onPressed: () async { await updateUserdata((user) { user.nextTimeToShowBackupNotice = - DateTime.now().add(Duration(days: 7)); + DateTime.now().add(const Duration(days: 7)); return user; }); - initAsync(); + await initAsync(); }, child: Text(context.lang.backupNoticeLater), ), - SizedBox(width: 10), + const SizedBox(width: 10), FilledButton( onPressed: () { Navigator.push( context, MaterialPageRoute( - builder: (context) => BackupView(), + builder: (context) => const BackupView(), ), ); }, diff --git a/lib/src/views/chats/chat_list_components/connection_info.comp.dart b/lib/src/views/chats/chat_list_components/connection_info.comp.dart index d4d131d..267a64d 100644 --- a/lib/src/views/chats/chat_list_components/connection_info.comp.dart +++ b/lib/src/views/chats/chat_list_components/connection_info.comp.dart @@ -62,7 +62,7 @@ class _ConnectionInfoWidgetState extends State @override Widget build(BuildContext context) { if (!showAnimation || gIsDemoUser) return Container(); - double screenWidth = MediaQuery.of(context).size.width; + final screenWidth = MediaQuery.of(context).size.width; return SizedBox( width: screenWidth, @@ -70,8 +70,8 @@ class _ConnectionInfoWidgetState extends State child: AnimatedBuilder( animation: _controller, builder: (context, child) { - double barWidth = _widthAnim.value; - double left = _positionAnim.value * (screenWidth - barWidth); + final barWidth = _widthAnim.value; + final left = _positionAnim.value * (screenWidth - barWidth); return Stack( children: [ Positioned( diff --git a/lib/src/views/chats/chat_list_components/demo_user.card.dart b/lib/src/views/chats/chat_list_components/demo_user.card.dart index 5ebbc50..eb09495 100644 --- a/lib/src/views/chats/chat_list_components/demo_user.card.dart +++ b/lib/src/views/chats/chat_list_components/demo_user.card.dart @@ -8,11 +8,10 @@ class DemoUserCard extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( + return ColoredBox( color: isDarkMode(context) ? Colors.white : Colors.black, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'This is a Demo-Preview.', diff --git a/lib/src/views/chats/chat_messages.view.dart b/lib/src/views/chats/chat_messages.view.dart index 400b3f8..eeab56d 100644 --- a/lib/src/views/chats/chat_messages.view.dart +++ b/lib/src/views/chats/chat_messages.view.dart @@ -157,7 +157,8 @@ class _ChatMessagesViewState extends State { ); } - twonlyDB.messagesDao.openedAllNonMediaMessages(widget.contact.userId); + await twonlyDB.messagesDao + .openedAllNonMediaMessages(widget.contact.userId); setState(() { textReactionsToMessageId = tmpTextReactionsToMessageId; @@ -271,7 +272,7 @@ class _ChatMessagesViewState extends State { ), const SizedBox(width: 10), Expanded( - child: Container( + child: ColoredBox( color: Colors.transparent, child: Row( children: [ diff --git a/lib/src/views/chats/chat_messages_components/chat_media_entry.dart b/lib/src/views/chats/chat_messages_components/chat_media_entry.dart index 3b2994d..3d86dc6 100644 --- a/lib/src/views/chats/chat_messages_components/chat_media_entry.dart +++ b/lib/src/views/chats/chat_messages_components/chat_media_entry.dart @@ -1,25 +1,24 @@ import 'package:drift/drift.dart' show Value; import 'package:flutter/material.dart'; import 'package:twonly/globals.dart'; -import 'package:twonly/src/model/protobuf/push_notification/push_notification.pbserver.dart'; -import 'package:twonly/src/views/chats/chat_messages_components/in_chat_media_viewer.dart'; -import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/tables/messages_table.dart'; +import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/model/json/message.dart'; -import 'package:twonly/src/services/api/messages.dart'; -import 'package:twonly/src/services/api/media_download.dart' as received; - -import 'package:twonly/src/views/chats/media_viewer.view.dart'; import 'package:twonly/src/model/memory_item.model.dart'; +import 'package:twonly/src/model/protobuf/push_notification/push_notification.pbserver.dart'; +import 'package:twonly/src/services/api/media_download.dart' as received; +import 'package:twonly/src/services/api/messages.dart'; +import 'package:twonly/src/views/chats/chat_messages_components/in_chat_media_viewer.dart'; +import 'package:twonly/src/views/chats/media_viewer.view.dart'; import 'package:twonly/src/views/tutorial/tutorials.dart'; class ChatMediaEntry extends StatefulWidget { const ChatMediaEntry({ - super.key, required this.message, required this.contact, required this.content, required this.galleryItems, + super.key, }); final Message message; @@ -47,13 +46,13 @@ class _ChatMediaEntryState extends State { widget.message.mediaStored) { return; } - if (await received.existsMediaFile(widget.message.messageId, "png")) { + if (await received.existsMediaFile(widget.message.messageId, 'png')) { if (mounted) { setState(() { canBeReopened = true; }); } - Future.delayed(Duration(seconds: 1), () { + Future.delayed(const Duration(seconds: 1), () { if (!mounted) return; showReopenMediaFilesTutorial(context, reopenMediaFile); }); @@ -62,7 +61,7 @@ class _ChatMediaEntryState extends State { @override Widget build(BuildContext context) { - Color color = getMessageColorFromType( + final color = getMessageColorFromType( widget.content, context, ); @@ -75,7 +74,7 @@ class _ChatMediaEntryState extends State { widget.message.mediaStored) { return; } - if (await received.existsMediaFile(widget.message.messageId, "png")) { + if (await received.existsMediaFile(widget.message.messageId, 'png')) { await encryptAndSendMessageAsync( null, widget.contact.userId, @@ -93,7 +92,7 @@ class _ChatMediaEntryState extends State { ); await twonlyDB.messagesDao.updateMessageByMessageId( widget.message.messageId, - MessagesCompanion(openedAt: Value(null)), + const MessagesCompanion(openedAt: Value(null)), ); } }, @@ -108,9 +107,9 @@ class _ChatMediaEntryState extends State { initialMessage: widget.message); }), ); - checkIfTutorialCanBeShown(); + await checkIfTutorialCanBeShown(); } else if (widget.message.downloadState == DownloadState.pending) { - received.startDownloadMedia(widget.message, true); + await received.startDownloadMedia(widget.message, true); } } }, diff --git a/lib/src/views/chats/chat_messages_components/chat_text_entry.dart b/lib/src/views/chats/chat_messages_components/chat_text_entry.dart index 0e5e876..fdb6901 100644 --- a/lib/src/views/chats/chat_messages_components/chat_text_entry.dart +++ b/lib/src/views/chats/chat_messages_components/chat_text_entry.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/views/chats/chat_messages.view.dart'; import 'package:twonly/src/views/components/animate_icon.dart'; import 'package:twonly/src/views/components/better_text.dart'; -import 'package:twonly/src/database/twonly_database.dart'; class ChatTextEntry extends StatelessWidget { - const ChatTextEntry({super.key, required this.message, required this.text}); + const ChatTextEntry({required this.message, required this.text, super.key}); final String text; final Message message; @@ -14,10 +14,10 @@ class ChatTextEntry extends StatelessWidget { Widget build(BuildContext context) { if (EmojiAnimation.supported(text)) { return Container( - constraints: BoxConstraints( + constraints: const BoxConstraints( maxWidth: 100, ), - padding: EdgeInsets.symmetric( + padding: const EdgeInsets.symmetric( vertical: 4, horizontal: 10, ), @@ -28,10 +28,10 @@ class ChatTextEntry extends StatelessWidget { constraints: BoxConstraints( maxWidth: MediaQuery.of(context).size.width * 0.8, ), - padding: EdgeInsets.symmetric(vertical: 4, horizontal: 10), + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 10), decoration: BoxDecoration( color: getMessageColor(message), - borderRadius: BorderRadius.circular(12.0), + borderRadius: BorderRadius.circular(12), ), child: BetterText(text: text), ); diff --git a/lib/src/views/chats/chat_messages_components/chat_text_response_columns.dart b/lib/src/views/chats/chat_messages_components/chat_text_response_columns.dart index b7ffe03..3b9f702 100644 --- a/lib/src/views/chats/chat_messages_components/chat_text_response_columns.dart +++ b/lib/src/views/chats/chat_messages_components/chat_text_response_columns.dart @@ -49,8 +49,7 @@ class ChatTextResponseColumns extends StatelessWidget { children.insert( 0, Container( - padding: - const EdgeInsets.only(top: 5, bottom: 0, right: 10, left: 10), + padding: const EdgeInsets.only(top: 5, right: 10, left: 10), child: Container( constraints: BoxConstraints( maxWidth: MediaQuery.of(context).size.width * 0.8, diff --git a/lib/src/views/onboarding/recover.view.dart b/lib/src/views/onboarding/recover.view.dart index 782f594..67e312c 100644 --- a/lib/src/views/onboarding/recover.view.dart +++ b/lib/src/views/onboarding/recover.view.dart @@ -34,18 +34,18 @@ class _BackupRecoveryViewState extends State { backupServer, ); - Restart.restartApp( + await Restart.restartApp( notificationTitle: 'Backup successfully recovered.', notificationBody: 'Click here to open the app again', ); } catch (e) { // in case something was already written from the backup... - Log.error("$e"); + Log.error('$e'); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('$e'), - duration: Duration(seconds: 3), + duration: const Duration(seconds: 3), ), ); } @@ -60,23 +60,24 @@ class _BackupRecoveryViewState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text("twonly Safe ${context.lang.twonlySafeRecoverTitle}"), + title: Text('twonly Safe ${context.lang.twonlySafeRecoverTitle}'), actions: [ IconButton( onPressed: () { showAlertDialog( context, - "twonly Safe", + 'twonly Safe', context.lang.backupTwonlySafeLongDesc, ); }, - icon: FaIcon(FontAwesomeIcons.circleInfo), + icon: const FaIcon(FontAwesomeIcons.circleInfo), iconSize: 18, ) ], ), body: Padding( - padding: EdgeInsetsGeometry.symmetric(vertical: 40, horizontal: 40), + padding: + const EdgeInsetsGeometry.symmetric(vertical: 40, horizontal: 40), child: ListView( children: [ Text( @@ -95,7 +96,7 @@ class _BackupRecoveryViewState extends State { context.lang.registerUsernameDecoration, ), ), - SizedBox(height: 10), + const SizedBox(height: 10), Stack( children: [ TextField( @@ -130,30 +131,30 @@ class _BackupRecoveryViewState extends State { ) ], ), - SizedBox(height: 30), + const SizedBox(height: 30), Center( child: OutlinedButton( onPressed: () async { backupServer = await Navigator.push(context, MaterialPageRoute(builder: (context) { - return TwonlySafeServerView(); + return const TwonlySafeServerView(); })); setState(() {}); }, child: Text(context.lang.backupExpertSettings), ), ), - SizedBox(height: 10), + const SizedBox(height: 10), Center( child: FilledButton.icon( onPressed: (!isLoading) ? _recoverTwonlySafe : null, icon: isLoading - ? SizedBox( + ? const SizedBox( height: 12, width: 12, child: CircularProgressIndicator(strokeWidth: 1), ) - : Icon(Icons.lock_clock_rounded), + : const Icon(Icons.lock_clock_rounded), label: Text(context.lang.twonlySafeRecoverBtn), )) ], diff --git a/lib/src/views/settings/account/refund_credits.view.dart b/lib/src/views/settings/account/refund_credits.view.dart index 810c53c..2f6ea2e 100644 --- a/lib/src/views/settings/account/refund_credits.view.dart +++ b/lib/src/views/settings/account/refund_credits.view.dart @@ -4,7 +4,7 @@ import 'package:twonly/src/views/settings/subscription/voucher.view.dart'; // import 'package:url_launcher/url_launcher.dart'; class RefundCreditsView extends StatefulWidget { - const RefundCreditsView({super.key, required this.formattedBalance}); + const RefundCreditsView({required this.formattedBalance, super.key}); final String formattedBalance; @override @@ -19,7 +19,7 @@ class _RefundCreditsViewState extends State { title: const Text('Refund Credits'), ), body: Padding( - padding: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -32,13 +32,15 @@ class _RefundCreditsViewState extends State { const SizedBox(height: 20), // Space between balance and options ListTile( - title: Text("Create a Voucher"), + title: const Text('Create a Voucher'), onTap: () async { await Navigator.push(context, MaterialPageRoute(builder: (context) { - return VoucherView(); + return const VoucherView(); })); - Navigator.pop(context, false); + if (context.mounted) { + Navigator.pop(context, false); + } }, ), // ListTile( diff --git a/lib/src/views/settings/help/contact_us.view.dart b/lib/src/views/settings/help/contact_us.view.dart index f3984ec..8d5b6bd 100644 --- a/lib/src/views/settings/help/contact_us.view.dart +++ b/lib/src/views/settings/help/contact_us.view.dart @@ -38,7 +38,7 @@ class _ContactUsState extends State { final messageOnSuccess = TextMessage() ..body = [] - ..userId = Int64(0); + ..userId = Int64(); final uploadRequest = UploadRequest( messagesOnSuccess: [messageOnSuccess], @@ -116,6 +116,7 @@ class _ContactUsState extends State { 'Debug Log: https://api.twonly.eu/api/download/$token'; } } catch (e) { + if (!mounted) return ''; ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Could not upload the debug log!')), ); diff --git a/lib/src/views/settings/help/contact_us/submit_message.view.dart b/lib/src/views/settings/help/contact_us/submit_message.view.dart index b45a692..237d5b9 100644 --- a/lib/src/views/settings/help/contact_us/submit_message.view.dart +++ b/lib/src/views/settings/help/contact_us/submit_message.view.dart @@ -3,7 +3,7 @@ import 'package:http/http.dart' as http; import 'package:twonly/src/utils/misc.dart'; class SubmitMessage extends StatefulWidget { - const SubmitMessage({super.key, required this.fullMessage}); + const SubmitMessage({required this.fullMessage, super.key}); final String fullMessage; @@ -22,14 +22,14 @@ class _ContactUsState extends State { } Future _submitFeedback() async { - final String feedback = _controller.text; + final feedback = _controller.text; setState(() { isLoading = true; }); if (feedback.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Please enter your message.')), + const SnackBar(content: Text('Please enter your message.')), ); return; } @@ -57,7 +57,7 @@ class _ContactUsState extends State { } else { // Handle error response ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Failed to submit feedback.')), + const SnackBar(content: Text('Failed to submit feedback.')), ); } } @@ -69,30 +69,30 @@ class _ContactUsState extends State { title: Text(context.lang.settingsHelpContactUs), ), body: Padding( - padding: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(16), child: ListView( children: [ Text( context.lang.contactUsLastWarning, textAlign: TextAlign.center, ), - SizedBox(height: 10), + const SizedBox(height: 10), TextField( controller: _controller, decoration: InputDecoration( hintText: context.lang.contactUsYourMessage, - border: OutlineInputBorder(), + border: const OutlineInputBorder(), ), minLines: 5, maxLines: 20, ), Padding( - padding: EdgeInsets.symmetric(vertical: 40, horizontal: 40), + padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 40), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( - onPressed: (isLoading) ? null : _submitFeedback, + onPressed: isLoading ? null : _submitFeedback, child: Text(context.lang.submit), ), ], diff --git a/lib/src/views/settings/help/credits.view.dart b/lib/src/views/settings/help/credits.view.dart index d062807..bfe9488 100644 --- a/lib/src/views/settings/help/credits.view.dart +++ b/lib/src/views/settings/help/credits.view.dart @@ -6,19 +6,18 @@ import 'package:twonly/src/views/camera/image_editor/layers/filters/location_fil import 'package:url_launcher/url_launcher.dart'; class UrlListTitle extends StatelessWidget { + const UrlListTitle({ + required this.title, + required this.url, + super.key, + this.leading, + this.subtitle, + }); final String? title; final String url; final String? subtitle; final Widget? leading; - const UrlListTitle({ - super.key, - required this.title, - required this.url, - this.leading, - this.subtitle, - }); - @override Widget build(BuildContext context) { return ListTile( @@ -28,7 +27,7 @@ class UrlListTitle extends StatelessWidget { onTap: () { launchUrl(Uri.parse(url)); }, - trailing: FaIcon(FontAwesomeIcons.arrowUpRightFromSquare, size: 15), + trailing: const FaIcon(FontAwesomeIcons.arrowUpRightFromSquare, size: 15), ); } } @@ -50,7 +49,7 @@ class _CreditsViewState extends State { } Future initAsync() async { - sticker = (await getStickerIndex()).where((x) => x.source != "").toList(); + sticker = (await getStickerIndex()).where((x) => x.source != '').toList(); setState(() {}); } @@ -62,86 +61,86 @@ class _CreditsViewState extends State { ), body: ListView( children: [ - UrlListTitle( - title: "twonly Logo", - subtitle: "by Font Awesome (modified)", - url: "https://fontawesome.com/icons/link?f=classic&s=solid", + const UrlListTitle( + title: 'twonly Logo', + subtitle: 'by Font Awesome (modified)', + url: 'https://fontawesome.com/icons/link?f=classic&s=solid', ), - UrlListTitle( - title: "Most Icons", - subtitle: "by Font Awesome", - url: "https://github.com/FortAwesome/Font-Awesome", + const UrlListTitle( + title: 'Most Icons', + subtitle: 'by Font Awesome', + url: 'https://github.com/FortAwesome/Font-Awesome', ), - UrlListTitle( - title: "Animated Emoji", - subtitle: "CC BY 4.0", - url: "https://googlefonts.github.io/noto-emoji-animation/", + const UrlListTitle( + title: 'Animated Emoji', + subtitle: 'CC BY 4.0', + url: 'https://googlefonts.github.io/noto-emoji-animation/', ), - UrlListTitle( - title: "Avatar Icons", - url: "https://github.com/RoadTripMoustache/avatar_maker", + const UrlListTitle( + title: 'Avatar Icons', + url: 'https://github.com/RoadTripMoustache/avatar_maker', ), const Divider(), - ListTile( + const ListTile( title: Center( child: Text( - "Animations", - style: const TextStyle(fontWeight: FontWeight.bold), + 'Animations', + style: TextStyle(fontWeight: FontWeight.bold), )), ), - UrlListTitle( - title: "selfie fast Animation", - subtitle: "Brandon Ambuila", + const UrlListTitle( + title: 'selfie fast Animation', + subtitle: 'Brandon Ambuila', url: - "https://lottiefiles.com/free-animation/selfie-fast-JZx4Ftrg1E", + 'https://lottiefiles.com/free-animation/selfie-fast-JZx4Ftrg1E', ), - UrlListTitle( - title: "Security status - Safe Animation", - subtitle: "Yogesh Pal", + const UrlListTitle( + title: 'Security status - Safe Animation', + subtitle: 'Yogesh Pal', url: - "https://lottiefiles.com/free-animation/security-status-safe-CePJPAwLVx", + 'https://lottiefiles.com/free-animation/security-status-safe-CePJPAwLVx', ), - UrlListTitle( - title: "send mail Animation", - subtitle: "jignesh gajjar", - url: "https://lottiefiles.com/free-animation/send-mail-3pvzm2kmNq", + const UrlListTitle( + title: 'send mail Animation', + subtitle: 'jignesh gajjar', + url: 'https://lottiefiles.com/free-animation/send-mail-3pvzm2kmNq', ), - UrlListTitle( - title: "Present for you Animation", - subtitle: "Tatsiana Melnikova", + const UrlListTitle( + title: 'Present for you Animation', + subtitle: 'Tatsiana Melnikova', url: - "https://lottiefiles.com/free-animation/present-for-you-QalWyuNptY", + 'https://lottiefiles.com/free-animation/present-for-you-QalWyuNptY', ), - UrlListTitle( - title: "Take a photo Animation", - subtitle: "Nguyễn Như Lân", + const UrlListTitle( + title: 'Take a photo Animation', + subtitle: 'Nguyễn Như Lân', url: - "https://lottiefiles.com/free-animation/take-a-photo-CzOUerxwPP?color-palette=true", + 'https://lottiefiles.com/free-animation/take-a-photo-CzOUerxwPP?color-palette=true', ), - UrlListTitle( + const UrlListTitle( title: "Valentine's Day-Animation", - subtitle: "Strezha", + subtitle: 'Strezha', url: - "https://lottiefiles.com/de/free-animation/valentines-day-1UiMkPHnPK?color-palette=true", + 'https://lottiefiles.com/de/free-animation/valentines-day-1UiMkPHnPK?color-palette=true', ), - UrlListTitle( - title: "success-Animation", - subtitle: "Aman Awasthy", + const UrlListTitle( + title: 'success-Animation', + subtitle: 'Aman Awasthy', url: - "https://lottiefiles.com/de/free-animation/success-tick-cuwjLHAR7g", + 'https://lottiefiles.com/de/free-animation/success-tick-cuwjLHAR7g', ), - UrlListTitle( - title: "Failed-Animation", - subtitle: "Ahmed Shami أحمد شامي", - url: "https://lottiefiles.com/de/free-animation/failed-e5cQFDEtLv", + const UrlListTitle( + title: 'Failed-Animation', + subtitle: 'Ahmed Shami أحمد شامي', + url: 'https://lottiefiles.com/de/free-animation/failed-e5cQFDEtLv', ), const Divider(), if (sticker.isNotEmpty) - ListTile( + const ListTile( title: Center( child: Text( - "Filters", - style: const TextStyle(fontWeight: FontWeight.bold), + 'Filters', + style: TextStyle(fontWeight: FontWeight.bold), )), ), ...sticker.map( @@ -150,9 +149,9 @@ class _CreditsViewState extends State { height: 50, width: 50, child: CachedNetworkImage( - imageUrl: "https://twonly.eu/${x.imageSrc}"), + imageUrl: 'https://twonly.eu/${x.imageSrc}'), ), - title: "", + title: '', url: x.source, ), ), diff --git a/lib/src/views/settings/help/diagnostics.view.dart b/lib/src/views/settings/help/diagnostics.view.dart index 1eaa68f..67c8317 100644 --- a/lib/src/views/settings/help/diagnostics.view.dart +++ b/lib/src/views/settings/help/diagnostics.view.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:flutter/services.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; import 'package:twonly/src/utils/log.dart'; @@ -18,7 +18,7 @@ class _DiagnosticsViewState extends State { // Assuming the button is at the bottom of the scroll view _scrollController.animateTo( _scrollController.position.maxScrollExtent, // Scroll to the bottom - duration: Duration(milliseconds: 300), + duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); } @@ -42,12 +42,12 @@ class _DiagnosticsViewState extends State { Expanded( child: SingleChildScrollView( controller: _scrollController, - padding: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(16), child: Text(logText), ), ), Padding( - padding: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -65,7 +65,8 @@ class _DiagnosticsViewState extends State { final result = await SharePlus.instance.share(params); if (result.status != ShareResultStatus.success) { - Clipboard.setData(ClipboardData(text: logText)); + await Clipboard.setData( + ClipboardData(text: logText)); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( diff --git a/lib/src/views/settings/notification.view.dart b/lib/src/views/settings/notification.view.dart index 0106ae6..2b0cf1e 100644 --- a/lib/src/views/settings/notification.view.dart +++ b/lib/src/views/settings/notification.view.dart @@ -54,7 +54,7 @@ class NotificationView extends StatelessWidget { final pushData = await getPushData( user.userId, PushNotification( - messageId: Int64(0), + messageId: Int64(), kind: PushKind.testNotification, ), ); diff --git a/lib/src/views/settings/privacy.view.dart b/lib/src/views/settings/privacy.view.dart index 43cc069..0611bfa 100644 --- a/lib/src/views/settings/privacy.view.dart +++ b/lib/src/views/settings/privacy.view.dart @@ -43,7 +43,7 @@ class _PrivacyViewState extends State { onTap: () async { await Navigator.push(context, MaterialPageRoute(builder: (context) { - return PrivacyViewBlockUsers(); + return const PrivacyViewBlockUsers(); })); }, ), diff --git a/lib/src/views/settings/privacy_view_block.users.dart b/lib/src/views/settings/privacy_view_block.users.dart index db0b7e0..b98ffa0 100644 --- a/lib/src/views/settings/privacy_view_block.users.dart +++ b/lib/src/views/settings/privacy_view_block.users.dart @@ -2,10 +2,10 @@ import 'package:drift/drift.dart' hide Column; import 'package:flutter/material.dart'; import 'package:pie_menu/pie_menu.dart'; import 'package:twonly/globals.dart'; -import 'package:twonly/src/views/components/initialsavatar.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/utils/misc.dart'; +import 'package:twonly/src/views/components/initialsavatar.dart'; import 'package:twonly/src/views/components/user_context_menu.dart'; class PrivacyViewBlockUsers extends StatefulWidget { @@ -18,7 +18,7 @@ class PrivacyViewBlockUsers extends StatefulWidget { class _PrivacyViewBlockUsers extends State { late Stream> allUsers; List filteredUsers = []; - String filter = ""; + String filter = ''; @override void initState() { @@ -40,11 +40,12 @@ class _PrivacyViewBlockUsers extends State { body: PieCanvas( theme: getPieCanvasTheme(context), child: Padding( - padding: EdgeInsets.only(bottom: 20, left: 10, top: 20, right: 10), + padding: + const EdgeInsets.only(bottom: 20, left: 10, top: 20, right: 10), child: Column( children: [ Padding( - padding: EdgeInsets.symmetric(horizontal: 10), + padding: const EdgeInsets.symmetric(horizontal: 10), child: TextField( onChanged: (value) => setState(() { filter = value; @@ -110,7 +111,7 @@ class UserList extends StatelessWidget { restorationId: 'new_message_users_list', itemCount: users.length, itemBuilder: (BuildContext context, int i) { - Contact user = users[i]; + final user = users[i]; return UserContextMenuBlocked( contact: user, child: ListTile( diff --git a/lib/src/views/settings/profile/modify_avatar.view.dart b/lib/src/views/settings/profile/modify_avatar.view.dart index 3d10b42..866072a 100644 --- a/lib/src/views/settings/profile/modify_avatar.view.dart +++ b/lib/src/views/settings/profile/modify_avatar.view.dart @@ -24,9 +24,10 @@ class _ModifyAvatarState extends State { Future updateUserAvatar(String json, String svg) async { await updateUserdata((user) { - user.avatarJson = json; - user.avatarSvg = svg; - user.avatarCounter = user.avatarCounter + 1; + user + ..avatarJson = json + ..avatarSvg = svg + ..avatarCounter = user.avatarCounter + 1; return user; }); await notifyContactsAboutProfileChange(); @@ -35,7 +36,7 @@ class _ModifyAvatarState extends State { AvatarMakerThemeData getAvatarMakerTheme(BuildContext context) { if (isDarkMode(context)) { return AvatarMakerThemeData( - boxDecoration: BoxDecoration( + boxDecoration: const BoxDecoration( boxShadow: [BoxShadow()], ), unselectedTileDecoration: BoxDecoration( @@ -49,13 +50,13 @@ class _ModifyAvatarState extends State { selectedIconColor: Colors.white, unselectedIconColor: Colors.grey, primaryBgColor: Colors.black, // Dark mode background - secondaryBgColor: Colors.grey[850]!, // Dark mode secondary background + secondaryBgColor: Colors.grey[850], // Dark mode secondary background labelTextStyle: - TextStyle(color: Colors.white), // Light text for dark mode + const TextStyle(color: Colors.white), // Light text for dark mode ); } else { return AvatarMakerThemeData( - boxDecoration: BoxDecoration( + boxDecoration: const BoxDecoration( boxShadow: [BoxShadow()], ), unselectedTileDecoration: BoxDecoration( @@ -69,9 +70,9 @@ class _ModifyAvatarState extends State { selectedIconColor: Colors.black, unselectedIconColor: Colors.grey, primaryBgColor: Colors.white, // Light mode background - secondaryBgColor: Colors.grey[200]!, // Light mode secondary background + secondaryBgColor: Colors.grey[200], // Light mode secondary background labelTextStyle: - TextStyle(color: Colors.black), // Dark text for light mode + const TextStyle(color: Colors.black), // Dark text for light mode ); } } @@ -85,10 +86,9 @@ class _ModifyAvatarState extends State { body: Center( child: SingleChildScrollView( child: Column( - crossAxisAlignment: CrossAxisAlignment.center, children: [ Padding( - padding: const EdgeInsets.symmetric(vertical: 00), + padding: EdgeInsets.zero, child: AvatarMakerAvatar( radius: 130, backgroundColor: Colors.transparent, @@ -100,7 +100,7 @@ class _ModifyAvatarState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( - icon: FaIcon(FontAwesomeIcons.floppyDisk), + icon: const FaIcon(FontAwesomeIcons.floppyDisk), onPressed: () async { await _avatarMakerController.saveAvatarSVG(); final json = @@ -113,27 +113,23 @@ class _ModifyAvatarState extends State { }, ), IconButton( - icon: FaIcon(FontAwesomeIcons.shuffle), - onPressed: () { - _avatarMakerController.randomizedSelectedOptions(); - }, + icon: const FaIcon(FontAwesomeIcons.shuffle), + onPressed: + _avatarMakerController.randomizedSelectedOptions, ), IconButton( - icon: Icon(FontAwesomeIcons.rotateLeft), - onPressed: () { - _avatarMakerController.restoreState(); - }, + icon: const Icon(FontAwesomeIcons.rotateLeft), + onPressed: _avatarMakerController.restoreState, ), ], ), ), Padding( padding: - const EdgeInsets.symmetric(horizontal: 8.0, vertical: 30), + const EdgeInsets.symmetric(horizontal: 8, vertical: 30), child: AvatarMakerCustomizer( scaffoldWidth: min(600, MediaQuery.of(context).size.width * 0.85), - autosave: false, theme: getAvatarMakerTheme(context), controller: _avatarMakerController, ), diff --git a/lib/src/views/settings/profile/profile.view.dart b/lib/src/views/settings/profile/profile.view.dart index e8f7fe7..3e83c43 100644 --- a/lib/src/views/settings/profile/profile.view.dart +++ b/lib/src/views/settings/profile/profile.view.dart @@ -1,11 +1,11 @@ import 'package:avatar_maker/avatar_maker.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:twonly/src/views/components/better_list_title.dart'; import 'package:twonly/src/model/json/userdata.dart'; import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/storage.dart'; +import 'package:twonly/src/views/components/better_list_title.dart'; import 'package:twonly/src/views/settings/profile/modify_avatar.view.dart'; class ProfileView extends StatefulWidget { @@ -33,13 +33,14 @@ class _ProfileViewState extends State { Future updateUserDisplayName(String displayName) async { await updateUserdata((user) { - user.displayName = displayName; - user.avatarCounter = user.avatarCounter + 1; + user + ..displayName = displayName + ..avatarCounter = user.avatarCounter + 1; return user; }); await notifyContactsAboutProfileChange(); - initAsync(); + await initAsync(); } @override @@ -49,34 +50,34 @@ class _ProfileViewState extends State { title: Text(context.lang.settingsProfile), ), body: ListView( - physics: BouncingScrollPhysics(), + physics: const BouncingScrollPhysics(), children: [ - SizedBox(height: 25), + const SizedBox(height: 25), AvatarMakerAvatar( backgroundColor: Colors.transparent, radius: 80, controller: _avatarMakerController, ), - SizedBox(height: 10), + const SizedBox(height: 10), Center( child: SizedBox( height: 35, child: ElevatedButton.icon( - icon: Icon(Icons.edit), + icon: const Icon(Icons.edit), label: Text(context.lang.settingsProfileCustomizeAvatar), onPressed: () async { await Navigator.push( context, MaterialPageRoute( - builder: (context) => ModifyAvatar(), + builder: (context) => const ModifyAvatar(), ), ); - _avatarMakerController.performRestore(); + await _avatarMakerController.performRestore(); setState(() {}); }), ), ), - SizedBox(height: 20), + const SizedBox(height: 20), const Divider(), BetterListTile( icon: FontAwesomeIcons.userPen, @@ -85,8 +86,8 @@ class _ProfileViewState extends State { onTap: () async { final displayName = await showDisplayNameChangeDialog(context, user!.displayName); - if (context.mounted && displayName != null && displayName != "") { - updateUserDisplayName(displayName); + if (context.mounted && displayName != null && displayName != '') { + await updateUserDisplayName(displayName); } }, ), @@ -98,8 +99,7 @@ class _ProfileViewState extends State { Future showDisplayNameChangeDialog( BuildContext context, String currentName) { - final TextEditingController controller = - TextEditingController(text: currentName); + final controller = TextEditingController(text: currentName); return showDialog( context: context, diff --git a/lib/src/views/settings/settings_main.view.dart b/lib/src/views/settings/settings_main.view.dart index 054a61f..0d22132 100644 --- a/lib/src/views/settings/settings_main.view.dart +++ b/lib/src/views/settings/settings_main.view.dart @@ -67,7 +67,7 @@ class _SettingsMainViewState extends State { child: Row( children: [ ContactAvatar( - userData: userData!, + userData: userData, fontSize: 30, ), Container(width: 20, color: Colors.transparent), @@ -200,7 +200,7 @@ class _SettingsMainViewState extends State { onTap: () { Navigator.push(context, MaterialPageRoute( builder: (context) { - return HelpView(); + return const HelpView(); }, )); }, diff --git a/lib/src/views/settings/share_with_friends.view.dart b/lib/src/views/settings/share_with_friends.view.dart index 550cd88..c9b9f65 100644 --- a/lib/src/views/settings/share_with_friends.view.dart +++ b/lib/src/views/settings/share_with_friends.view.dart @@ -18,11 +18,11 @@ class _ShareWithFriendsView extends State { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { _controller.text = - context.lang.inviteFriendsShareText("https://twonly.eu/install"); + context.lang.inviteFriendsShareText('https://twonly.eu/install'); }); } - void _shareText() async { + Future _shareText() async { final textToShare = _controller.text; final params = ShareParams( text: textToShare, @@ -37,19 +37,18 @@ class _ShareWithFriendsView extends State { title: Text(context.lang.inviteFriends), ), body: Padding( - padding: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(16), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( controller: _controller, - style: const TextStyle(fontSize: 14.0), - decoration: InputDecoration(), + style: const TextStyle(fontSize: 14), ), - SizedBox(height: 16.0), + const SizedBox(height: 16), FilledButton.icon( onPressed: _shareText, - icon: FaIcon(FontAwesomeIcons.shareFromSquare), + icon: const FaIcon(FontAwesomeIcons.shareFromSquare), label: Text(context.lang.inviteFriendsShareBtn), ), ], diff --git a/lib/src/views/settings/subscription/additional_users.view.dart b/lib/src/views/settings/subscription/additional_users.view.dart index 5c45003..44c6dca 100644 --- a/lib/src/views/settings/subscription/additional_users.view.dart +++ b/lib/src/views/settings/subscription/additional_users.view.dart @@ -117,7 +117,7 @@ class _AdditionalUsersViewState extends State { ), ), Padding( - padding: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(16), child: GridView.count( crossAxisCount: 2, physics: const NeverScrollableScrollPhysics(), diff --git a/lib/src/views/settings/subscription/manage_subscription.view.dart b/lib/src/views/settings/subscription/manage_subscription.view.dart index 742b2e0..943fb40 100644 --- a/lib/src/views/settings/subscription/manage_subscription.view.dart +++ b/lib/src/views/settings/subscription/manage_subscription.view.dart @@ -88,7 +88,7 @@ class _ManageSubscriptionViewState extends State { ), onTap: toggleRenewalOption, trailing: Checkbox( - value: autoRenewal!, + value: autoRenewal, onChanged: (a) { toggleRenewalOption(); }, diff --git a/lib/src/views/settings/subscription/subscription.view.dart b/lib/src/views/settings/subscription/subscription.view.dart index 895b363..fa50b67 100644 --- a/lib/src/views/settings/subscription/subscription.view.dart +++ b/lib/src/views/settings/subscription/subscription.view.dart @@ -266,7 +266,7 @@ class _SubscriptionViewState extends State { PlanCard( planId: 'Tester', onTap: () async { - bool activate = await showAlertDialog( + final activate = await showAlertDialog( context, context.lang.testingAccountTitle, context.lang.testingAccountBody, diff --git a/lib/src/views/settings/subscription/transaction.view.dart b/lib/src/views/settings/subscription/transaction.view.dart index f3156c5..87de74c 100644 --- a/lib/src/views/settings/subscription/transaction.view.dart +++ b/lib/src/views/settings/subscription/transaction.view.dart @@ -4,8 +4,11 @@ import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart import 'package:twonly/src/utils/misc.dart'; class TransactionView extends StatefulWidget { - const TransactionView( - {super.key, required this.transactions, required this.formattedBalance}); + const TransactionView({ + required this.transactions, + required this.formattedBalance, + super.key, + }); final List? transactions; final String formattedBalance; @@ -23,7 +26,7 @@ class _TransactionViewState extends State { body: ListView( children: [ Padding( - padding: const EdgeInsets.all(32.0), + padding: const EdgeInsets.all(32), child: Center( child: Container( decoration: BoxDecoration( @@ -51,10 +54,9 @@ class _TransactionViewState extends State { } class TransactionCard extends StatefulWidget { + const TransactionCard({required this.transaction, super.key}); final Response_Transaction transaction; - const TransactionCard({super.key, required this.transaction}); - @override State createState() => _TransactionCardState(); } diff --git a/lib/src/views/settings/subscription/voucher.view.dart b/lib/src/views/settings/subscription/voucher.view.dart index a255e33..23cfbd1 100644 --- a/lib/src/views/settings/subscription/voucher.view.dart +++ b/lib/src/views/settings/subscription/voucher.view.dart @@ -111,7 +111,7 @@ class _VoucherCardState extends State { margin: const EdgeInsets.all(10), elevation: 5, child: Padding( - padding: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -160,7 +160,7 @@ Future redeemVoucher(BuildContext context) async { mainAxisSize: MainAxisSize.min, children: [ Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), + padding: const EdgeInsets.symmetric(vertical: 16), child: TextField( onChanged: (value) { // Convert to uppercase diff --git a/lib/src/views/tutorial/show_tutorial.dart b/lib/src/views/tutorial/show_tutorial.dart index df79326..e727aa9 100644 --- a/lib/src/views/tutorial/show_tutorial.dart +++ b/lib/src/views/tutorial/show_tutorial.dart @@ -76,7 +76,6 @@ TargetFocus getTargetFocus( left: 0, right: 0, top: top, bottom: bottom), child: Column( mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( diff --git a/lib/src/views/tutorial/tutorials.dart b/lib/src/views/tutorial/tutorials.dart index 3b3ba73..31f98fe 100644 --- a/lib/src/views/tutorial/tutorials.dart +++ b/lib/src/views/tutorial/tutorials.dart @@ -11,17 +11,18 @@ Future showChatListTutorialSearchOtherUsers( GlobalKey searchForOtherUsers, ) async { await lockDisplayTutorial.protect(() async { - if (await checkIfTutorialAlreadyShown("chat_list:search_users")) { + if (await checkIfTutorialAlreadyShown('chat_list:search_users')) { return; } if (!context.mounted) return; - List targets = []; - targets.add(getTargetFocus( - context, - searchForOtherUsers, - context.lang.tutorialChatListSearchUsersTitle, - context.lang.tutorialChatListSearchUsersDesc, - )); + final targets = [ + getTargetFocus( + context, + searchForOtherUsers, + context.lang.tutorialChatListSearchUsersTitle, + context.lang.tutorialChatListSearchUsersDesc, + ) + ]; await showTutorial(context, targets); }); } @@ -31,17 +32,18 @@ Future showChatListTutorialContextMenu( GlobalKey firstUserListItemKey, ) async { await lockDisplayTutorial.protect(() async { - if (await checkIfTutorialAlreadyShown("chat_list:context_menu")) { + if (await checkIfTutorialAlreadyShown('chat_list:context_menu')) { return; } if (!context.mounted) return; - List targets = []; - targets.add(getTargetFocus( - context, - firstUserListItemKey, - context.lang.tutorialChatListContextMenuTitle, - context.lang.tutorialChatListContextMenuDesc, - )); + final targets = [ + getTargetFocus( + context, + firstUserListItemKey, + context.lang.tutorialChatListContextMenuTitle, + context.lang.tutorialChatListContextMenuDesc, + ) + ]; await showTutorial(context, targets); }); } @@ -51,17 +53,18 @@ Future showVerifyShieldTutorial( GlobalKey firstUserListItemKey, ) async { await lockDisplayTutorial.protect(() async { - if (await checkIfTutorialAlreadyShown("chat_messages:verify_shield")) { + if (await checkIfTutorialAlreadyShown('chat_messages:verify_shield')) { return; } if (!context.mounted) return; - List targets = []; - targets.add(getTargetFocus( - context, - firstUserListItemKey, - context.lang.tutorialChatMessagesVerifyShieldTitle, - context.lang.tutorialChatMessagesVerifyShieldDesc, - )); + final targets = [ + getTargetFocus( + context, + firstUserListItemKey, + context.lang.tutorialChatMessagesVerifyShieldTitle, + context.lang.tutorialChatMessagesVerifyShieldDesc, + ) + ]; await showTutorial(context, targets); }); } @@ -71,17 +74,18 @@ Future showReopenMediaFilesTutorial( GlobalKey firstUserListItemKey, ) async { await lockDisplayTutorial.protect(() async { - if (await checkIfTutorialAlreadyShown("chat_messages:reopen_message")) { + if (await checkIfTutorialAlreadyShown('chat_messages:reopen_message')) { return; } if (!context.mounted) return; - List targets = []; - targets.add(getTargetFocus( - context, - firstUserListItemKey, - context.lang.tutorialChatMessagesReopenMessageTitle, - context.lang.tutorialChatMessagesReopenMessageDesc, - )); + final targets = [ + getTargetFocus( + context, + firstUserListItemKey, + context.lang.tutorialChatMessagesReopenMessageTitle, + context.lang.tutorialChatMessagesReopenMessageDesc, + ) + ]; await showTutorial(context, targets); }); } diff --git a/pubspec.yaml b/pubspec.yaml index 86d55ef..40d2793 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,12 +10,20 @@ environment: sdk: ^3.6.0 dependencies: + avatar_maker: ^0.4.0 + background_downloader: ^9.2.2 + cached_network_image: ^3.4.1 + camera: ^0.11.1 collection: ^1.18.0 connectivity_plus: ^6.1.2 + cryptography_flutter_plus: ^2.3.4 + cryptography_plus: ^2.7.0 + device_info_plus: ^11.5.0 drift: ^2.25.1 drift_flutter: ^0.2.4 firebase_core: ^3.11.0 firebase_messaging: ^15.2.2 + fixnum: ^1.1.1 flutter: sdk: flutter flutter_image_compress: ^2.4.0 @@ -25,15 +33,17 @@ dependencies: # flutter_secure_storage: ^10.0.0-beta.4 flutter_secure_storage: path: ./dependencies/flutter_secure_storage/flutter_secure_storage + flutter_svg: ^2.0.17 flutter_zxing: path: ./dependencies/flutter_zxing - # pie_menu: ^3.2.7 - pie_menu: - path: ./dependencies/flutter-pie-menu font_awesome_flutter: ^10.8.0 gal: ^2.3.1 + get: ^4.7.2 hand_signature: ^3.0.3 + hashlib: ^2.0.0 + http: ^1.3.0 image: ^4.3.0 + image_picker: ^1.1.2 intl: ^0.20.2 introduction_screen: ^3.1.14 json_annotation: ^4.9.0 @@ -41,46 +51,35 @@ dependencies: local_auth: ^2.3.0 logging: ^1.3.0 lottie: ^3.3.1 + mutex: ^3.1.0 no_screenshot: ^0.3.1 package_info_plus: ^8.2.1 path: ^1.9.0 path_provider: ^2.1.5 permission_handler: ^12.0.0+1 + photo_view: ^0.15.0 + pie_menu: + path: ./dependencies/flutter-pie-menu protobuf: ^4.0.0 - cryptography_plus: ^2.7.0 provider: ^6.1.2 restart_app: ^1.3.2 screenshot: ^3.0.0 - url_launcher: ^6.3.1 - web_socket_channel: ^3.0.1 - camera: ^0.11.1 - avatar_maker: ^0.4.0 - flutter_svg: ^2.0.17 - fixnum: ^1.1.1 - mutex: ^3.1.0 - cached_network_image: ^3.4.1 - image_picker: ^1.1.2 - http: ^1.3.0 - get: ^4.7.2 - video_player: ^2.9.5 - video_compress: ^3.1.4 share_plus: ^11.0.0 - photo_view: ^0.15.0 tutorial_coach_mark: ^1.3.0 - background_downloader: ^9.2.2 - hashlib: ^2.0.0 + url_launcher: ^6.3.1 + video_compress: ^3.1.4 + video_player: ^2.9.5 video_thumbnail: ^0.5.6 - device_info_plus: ^11.5.0 - cryptography_flutter_plus: ^2.3.4 + web_socket_channel: ^3.0.1 dev_dependencies: + build_runner: ^2.4.15 + drift_dev: ^2.25.2 + flutter_launcher_icons: ^0.14.1 + flutter_lints: ^6.0.0 flutter_test: sdk: flutter - build_runner: ^2.4.15 json_serializable: ^6.8.0 - flutter_lints: ^6.0.0 - flutter_launcher_icons: ^0.14.1 - drift_dev: ^2.25.2 very_good_analysis: ^9.0.0 flutter_launcher_icons: diff --git a/test/unit_test.dart b/test/unit_test.dart index a635eee..bff97e1 100644 --- a/test/unit_test.dart +++ b/test/unit_test.dart @@ -4,10 +4,10 @@ import 'package:twonly/src/views/components/animate_icon.dart'; void main() { group('isEmoji', () { test('test isEmoji function', () { - expect(isEmoji("Hallo"), false); - expect(isEmoji("😂"), true); - expect(isEmoji("😂😂"), false); - expect(isEmoji("Hallo 😂"), false); + expect(isEmoji('Hallo'), false); + expect(isEmoji('😂'), true); + expect(isEmoji('😂😂'), false); + expect(isEmoji('Hallo 😂'), false); }); }); }