From 084222eee8771e2a71f8f5ef2d5fdee584ab5eab Mon Sep 17 00:00:00 2001 From: otsmr Date: Fri, 24 Jan 2025 15:25:44 +0100 Subject: [PATCH] move utils to separate files --- lib/main.dart | 3 +- lib/src/app.dart | 6 +- lib/src/providers/api_provider.dart | 3 +- lib/src/providers/db_provider.dart | 2 +- .../signal/connect_signed_pre_key_store.dart | 3 +- lib/src/signal/signal_helper.dart | 2 +- lib/src/utils.dart | 143 ------------------ lib/src/utils/api.dart | 44 ++++++ lib/src/utils/misc.dart | 51 +++++++ lib/src/utils/storage.dart | 39 +++++ lib/src/views/profile_view.dart | 7 +- lib/src/views/register_view.dart | 10 +- lib/src/views/search_username_view.dart | 3 +- lib/src/views/share_image_editor_view.dart | 3 +- 14 files changed, 154 insertions(+), 165 deletions(-) delete mode 100644 lib/src/utils.dart create mode 100644 lib/src/utils/api.dart create mode 100644 lib/src/utils/misc.dart create mode 100644 lib/src/utils/storage.dart diff --git a/lib/main.dart b/lib/main.dart index 3dd175b..8934722 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,8 +3,7 @@ import 'package:twonly/src/providers/api_provider.dart'; import 'package:twonly/src/providers/db_provider.dart'; import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; -import 'package:twonly/src/utils.dart'; - +import 'package:twonly/src/utils/misc.dart'; import 'src/app.dart'; import 'src/settings/settings_controller.dart'; import 'src/settings/settings_service.dart'; diff --git a/lib/src/app.dart b/lib/src/app.dart index 940f984..8905437 100644 --- a/lib/src/app.dart +++ b/lib/src/app.dart @@ -1,8 +1,8 @@ import 'package:twonly/main.dart'; +import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/views/onboarding_view.dart'; -import 'views/home_view.dart'; -import 'views/register_view.dart'; -import 'utils.dart'; +import 'package:twonly/src/views/home_view.dart'; +import 'package:twonly/src/views/register_view.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; diff --git a/lib/src/providers/api_provider.dart b/lib/src/providers/api_provider.dart index 0fcccb7..965c1b1 100644 --- a/lib/src/providers/api_provider.dart +++ b/lib/src/providers/api_provider.dart @@ -11,7 +11,8 @@ import 'package:twonly/src/proto/api/error.pb.dart'; import 'package:twonly/src/proto/api/server_to_client.pb.dart' as server; import 'package:twonly/src/signal/signal_helper.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:twonly/src/utils.dart'; +import 'package:twonly/src/utils/misc.dart'; +import 'package:twonly/src/utils/storage.dart'; import 'package:web_socket_channel/io.dart'; import 'package:libsignal_protocol_dart/src/ecc/ed25519.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; diff --git a/lib/src/providers/db_provider.dart b/lib/src/providers/db_provider.dart index 8a3e068..11a231a 100644 --- a/lib/src/providers/db_provider.dart +++ b/lib/src/providers/db_provider.dart @@ -6,8 +6,8 @@ import 'package:twonly/src/model/model_constants.dart'; import 'package:twonly/src/model/pre_key_model.dart'; import 'package:twonly/src/model/sender_key_store_model.dart'; import 'package:twonly/src/model/session_store_model.dart'; -import 'package:twonly/src/utils.dart'; import 'package:sqflite_sqlcipher/sqflite.dart'; +import 'package:twonly/src/utils/misc.dart'; class DbProvider { Database? db; diff --git a/lib/src/signal/connect_signed_pre_key_store.dart b/lib/src/signal/connect_signed_pre_key_store.dart index 7267475..1182784 100644 --- a/lib/src/signal/connect_signed_pre_key_store.dart +++ b/lib/src/signal/connect_signed_pre_key_store.dart @@ -1,9 +1,8 @@ import 'dart:collection'; import 'dart:convert'; import 'dart:typed_data'; - -import 'package:twonly/src/utils.dart'; import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; +import 'package:twonly/src/utils/misc.dart'; class ConnectSignedPreKeyStore extends SignedPreKeyStore { // final store = HashMap(); diff --git a/lib/src/signal/signal_helper.dart b/lib/src/signal/signal_helper.dart index 7a9529f..10ae58d 100644 --- a/lib/src/signal/signal_helper.dart +++ b/lib/src/signal/signal_helper.dart @@ -6,7 +6,7 @@ import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:logging/logging.dart'; import 'package:twonly/src/model/signal_identity_json.dart'; import 'package:twonly/src/proto/api/server_to_client.pb.dart'; -import 'package:twonly/src/utils.dart'; +import 'package:twonly/src/utils/misc.dart'; import 'connect_sender_key_store.dart'; import 'connect_signal_protocol_store.dart'; diff --git a/lib/src/utils.dart b/lib/src/utils.dart deleted file mode 100644 index 8c23d32..0000000 --- a/lib/src/utils.dart +++ /dev/null @@ -1,143 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'dart:math'; -import 'dart:typed_data'; -import 'package:gal/gal.dart'; -import 'package:logging/logging.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:twonly/main.dart'; -import 'package:twonly/src/model/contacts_model.dart'; -import 'package:twonly/src/signal/signal_helper.dart'; -import 'package:twonly/src/providers/api_provider.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'model/user_data_json.dart'; - -// Just a helper function to get the secure storage -FlutterSecureStorage getSecureStorage() { - AndroidOptions _getAndroidOptions() => const AndroidOptions( - encryptedSharedPreferences: true, - ); - return FlutterSecureStorage(aOptions: _getAndroidOptions()); -} - -Future isUserCreated() async { - UserData? user = await getUser(); - if (user == null) { - return false; - } - return true; -} - -Future saveImageToGallery(path) async { - final hasAccess = await Gal.hasAccess(); - if (!hasAccess) { - await Gal.requestAccess(); - } - try { - await Gal.putImage(path); - return null; - } on GalException catch (e) { - return e.type.message; - } -} - -Future getUser() async { - final storage = getSecureStorage(); - String? userJson = await storage.read(key: "user_data"); - if (userJson == null) { - return null; - } - try { - final userMap = jsonDecode(userJson) as Map; - Logger("get_user").info("Found user: $userMap"); - final user = UserData.fromJson(userMap); - return user; - } catch (e) { - Logger("get_user").shout("Error getting user: $e"); - return null; - } -} - -Future deleteLocalUserData() async { - final storage = getSecureStorage(); - var password = await storage.read(key: "sqflite_database_password"); - await dbProvider.remove(); - await storage.write(key: "sqflite_database_password", value: password); - await storage.deleteAll(); - return true; -} - -Uint8List getRandomUint8List(int length) { - final Random random = Random.secure(); - final Uint8List randomBytes = Uint8List(length); - - for (int i = 0; i < length; i++) { - randomBytes[i] = random.nextInt(256); // Generate a random byte (0-255) - } - - return randomBytes; -} - -int userIdToRegistrationId(Uint8List userId) { - int result = 0; - for (int i = 8; i < 16; i++) { - result = (result << 8) | userId[i]; - } - return result; -} - -String uint8ListToHex(Uint8List list) { - final StringBuffer hexBuffer = StringBuffer(); - for (int byte in list) { - hexBuffer.write(byte.toRadixString(16).padLeft(2, '0')); - } - return hexBuffer.toString().toUpperCase(); -} - -Future addNewUser(String username) async { - final res = await apiProvider.getUserData(username); - - if (res.isSuccess) { - print(res.value); - print(res.value.userdata.userId); - - if (await SignalHelper.addNewContact(res.value.userdata)) { - await dbProvider.db!.insert(DbContacts.tableName, { - DbContacts.columnDisplayName: username, - DbContacts.columnUserId: res.value.userdata.userId.toInt() - }); - } - print("Add new user: ${res}"); - } - - return res.isSuccess; -} - -Future createNewUser(String username, String inviteCode) async { - final storage = getSecureStorage(); - - await SignalHelper.createIfNotExistsSignalIdentity(); - - final res = await apiProvider.register(username, inviteCode); - - if (res.isSuccess) { - Logger("create_new_user").info("Got user_id ${res.value} from server"); - final userData = UserData( - userId: res.value.userid, username: username, displayName: username); - storage.write(key: "user_data", value: jsonEncode(userData)); - } - - return res; -} - -Future writeLogToFile(LogRecord record) async { - final directory = await getApplicationDocumentsDirectory(); - final logFile = File('${directory.path}/app.log'); - - // Prepare the log message - final logMessage = - '${record.level.name}: ${record.loggerName}: ${record.message}\n'; - - // Append the log message to the file - await logFile.writeAsString(logMessage, mode: FileMode.append); -} diff --git a/lib/src/utils/api.dart b/lib/src/utils/api.dart new file mode 100644 index 0000000..25860eb --- /dev/null +++ b/lib/src/utils/api.dart @@ -0,0 +1,44 @@ +import 'dart:convert'; +import 'package:logging/logging.dart'; +import 'package:twonly/main.dart'; +import 'package:twonly/src/model/contacts_model.dart'; +import 'package:twonly/src/signal/signal_helper.dart'; +import 'package:twonly/src/providers/api_provider.dart'; +import 'package:twonly/src/utils/misc.dart'; +import 'package:twonly/src/model/user_data_json.dart'; + +Future addNewUser(String username) async { + final res = await apiProvider.getUserData(username); + + if (res.isSuccess) { + print(res.value); + print(res.value.userdata.userId); + + if (await SignalHelper.addNewContact(res.value.userdata)) { + await dbProvider.db!.insert(DbContacts.tableName, { + DbContacts.columnDisplayName: username, + DbContacts.columnUserId: res.value.userdata.userId.toInt() + }); + } + print("Add new user: ${res}"); + } + + return res.isSuccess; +} + +Future createNewUser(String username, String inviteCode) async { + final storage = getSecureStorage(); + + await SignalHelper.createIfNotExistsSignalIdentity(); + + final res = await apiProvider.register(username, inviteCode); + + if (res.isSuccess) { + Logger("create_new_user").info("Got user_id ${res.value} from server"); + final userData = UserData( + userId: res.value.userid, username: username, displayName: username); + storage.write(key: "user_data", value: jsonEncode(userData)); + } + + return res; +} diff --git a/lib/src/utils/misc.dart b/lib/src/utils/misc.dart new file mode 100644 index 0000000..cf959e7 --- /dev/null +++ b/lib/src/utils/misc.dart @@ -0,0 +1,51 @@ +import 'dart:io'; +import 'dart:math'; +import 'dart:typed_data'; +import 'package:gal/gal.dart'; +import 'package:logging/logging.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +Future writeLogToFile(LogRecord record) async { + final directory = await getApplicationDocumentsDirectory(); + final logFile = File('${directory.path}/app.log'); + + // Prepare the log message + final logMessage = + '${record.level.name}: ${record.loggerName}: ${record.message}\n'; + + // Append the log message to the file + await logFile.writeAsString(logMessage, mode: FileMode.append); +} + +// Just a helper function to get the secure storage +FlutterSecureStorage getSecureStorage() { + AndroidOptions _getAndroidOptions() => const AndroidOptions( + encryptedSharedPreferences: true, + ); + return FlutterSecureStorage(aOptions: _getAndroidOptions()); +} + +Future saveImageToGallery(path) async { + final hasAccess = await Gal.hasAccess(); + if (!hasAccess) { + await Gal.requestAccess(); + } + try { + await Gal.putImage(path); + return null; + } on GalException catch (e) { + return e.type.message; + } +} + +Uint8List getRandomUint8List(int length) { + final Random random = Random.secure(); + final Uint8List randomBytes = Uint8List(length); + + for (int i = 0; i < length; i++) { + randomBytes[i] = random.nextInt(256); // Generate a random byte (0-255) + } + + return randomBytes; +} diff --git a/lib/src/utils/storage.dart b/lib/src/utils/storage.dart new file mode 100644 index 0000000..eaf3c15 --- /dev/null +++ b/lib/src/utils/storage.dart @@ -0,0 +1,39 @@ +import 'dart:convert'; +import 'package:logging/logging.dart'; +import 'package:twonly/main.dart'; +import 'package:twonly/src/model/user_data_json.dart'; +import 'package:twonly/src/utils/misc.dart'; + +Future isUserCreated() async { + UserData? user = await getUser(); + if (user == null) { + return false; + } + return true; +} + +Future getUser() async { + final storage = getSecureStorage(); + String? userJson = await storage.read(key: "user_data"); + if (userJson == null) { + return null; + } + try { + final userMap = jsonDecode(userJson) as Map; + Logger("get_user").info("Found user: $userMap"); + final user = UserData.fromJson(userMap); + return user; + } catch (e) { + Logger("get_user").shout("Error getting user: $e"); + return null; + } +} + +Future deleteLocalUserData() async { + final storage = getSecureStorage(); + var password = await storage.read(key: "sqflite_database_password"); + await dbProvider.remove(); + await storage.write(key: "sqflite_database_password", value: password); + await storage.deleteAll(); + return true; +} diff --git a/lib/src/views/profile_view.dart b/lib/src/views/profile_view.dart index a1896e8..5c9659f 100644 --- a/lib/src/views/profile_view.dart +++ b/lib/src/views/profile_view.dart @@ -1,10 +1,9 @@ import 'package:twonly/src/model/user_data_json.dart'; - -import '../settings/settings_controller.dart'; -import '../settings/settings_view.dart'; -import '../utils.dart'; import 'package:restart_app/restart_app.dart'; import 'package:flutter/material.dart'; +import 'package:twonly/src/settings/settings_controller.dart'; +import 'package:twonly/src/settings/settings_view.dart'; +import 'package:twonly/src/utils/storage.dart'; class ProfileView extends StatefulWidget { const ProfileView({super.key, required this.settingsController}); diff --git a/lib/src/views/register_view.dart b/lib/src/views/register_view.dart index f33bb44..efd8e01 100644 --- a/lib/src/views/register_view.dart +++ b/lib/src/views/register_view.dart @@ -1,9 +1,9 @@ import 'package:twonly/main.dart'; import 'package:twonly/src/providers/api_provider.dart'; -import '../utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:twonly/src/utils/api.dart'; class RegisterView extends StatefulWidget { const RegisterView({super.key, required this.callbackOnSuccess}); @@ -130,9 +130,11 @@ class _RegisterViewState extends State { widget.callbackOnSuccess(); return; } - final errMsg = - ApiProvider.getLocalizedString(context, res.error); - showAlertDialog(context, "Oh no!", errMsg); + if (context.mounted) { + final errMsg = + ApiProvider.getLocalizedString(context, res.error); + showAlertDialog(context, "Oh no!", errMsg); + } }, style: ButtonStyle( padding: WidgetStateProperty.all( diff --git a/lib/src/views/search_username_view.dart b/lib/src/views/search_username_view.dart index 6e6a51b..8630493 100644 --- a/lib/src/views/search_username_view.dart +++ b/lib/src/views/search_username_view.dart @@ -1,9 +1,8 @@ import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:logging/logging.dart'; -import 'package:twonly/src/utils.dart'; +import 'package:twonly/src/utils/api.dart'; import 'package:twonly/src/views/register_view.dart'; class SearchUsernameView extends StatefulWidget { diff --git a/lib/src/views/share_image_editor_view.dart b/lib/src/views/share_image_editor_view.dart index e1d9155..004dee2 100644 --- a/lib/src/views/share_image_editor_view.dart +++ b/lib/src/views/share_image_editor_view.dart @@ -1,8 +1,7 @@ import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:twonly/src/utils.dart'; +import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/views/share_image_view.dart'; class ShareImageEditorView extends StatefulWidget {