From 74922b28041e9374f0e8090f550967ea4cf836c1 Mon Sep 17 00:00:00 2001 From: Tovi Jaeschke-Rogers Date: Tue, 18 Oct 2022 21:15:52 +1030 Subject: [PATCH] WIP - Start working on service classes and move models dir --- .../lib/components/custom_circle_avatar.dart | 1 - mobile/lib/components/qr_reader.dart | 6 +- mobile/lib/components/user_search_result.dart | 3 +- mobile/lib/components/view_image.dart | 5 +- .../models/conversation_users.dart | 6 +- .../{ => database}/models/conversations.dart | 46 +-- mobile/lib/{ => database}/models/friends.dart | 0 .../{ => database}/models/image_message.dart | 6 +- .../lib/{ => database}/models/messages.dart | 10 +- .../lib/{ => database}/models/my_profile.dart | 0 .../{ => database}/models/text_messages.dart | 4 +- mobile/lib/main.dart | 3 +- .../lib/services/conversations_service.dart | 290 ++++++++++++++++++ .../friends_service.dart} | 16 +- mobile/lib/utils/encryption/aes_helper.dart | 2 +- mobile/lib/utils/encryption/crypto_utils.dart | 18 +- .../lib/utils/encryption/rsa_key_helper.dart | 4 +- mobile/lib/utils/encryption/string_utils.dart | 2 +- mobile/lib/utils/storage/conversations.dart | 202 ------------ mobile/lib/utils/storage/messages.dart | 12 +- mobile/lib/utils/strings.dart | 4 +- mobile/lib/views/authentication/login.dart | 2 +- mobile/lib/views/authentication/signup.dart | 4 +- .../main/conversation/create_add_users.dart | 2 +- .../conversation/create_add_users_list.dart | 5 +- .../lib/views/main/conversation/detail.dart | 6 +- .../views/main/conversation/edit_details.dart | 4 +- mobile/lib/views/main/conversation/list.dart | 16 +- .../views/main/conversation/list_item.dart | 4 +- .../lib/views/main/conversation/message.dart | 10 +- .../views/main/conversation/permissions.dart | 19 +- .../lib/views/main/conversation/settings.dart | 85 +++-- .../conversation/settings_user_list_item.dart | 4 +- mobile/lib/views/main/friend/add_search.dart | 2 +- mobile/lib/views/main/friend/list.dart | 10 +- mobile/lib/views/main/friend/list_item.dart | 22 +- .../views/main/friend/request_list_item.dart | 4 +- mobile/lib/views/main/home.dart | 14 +- .../views/main/profile/change_password.dart | 2 +- .../views/main/profile/change_server_url.dart | 2 +- mobile/lib/views/main/profile/profile.dart | 12 +- 41 files changed, 454 insertions(+), 415 deletions(-) rename mobile/lib/{ => database}/models/conversation_users.dart (97%) rename mobile/lib/{ => database}/models/conversations.dart (90%) rename mobile/lib/{ => database}/models/friends.dart (100%) rename mobile/lib/{ => database}/models/image_message.dart (96%) rename mobile/lib/{ => database}/models/messages.dart (94%) rename mobile/lib/{ => database}/models/my_profile.dart (100%) rename mobile/lib/{ => database}/models/text_messages.dart (97%) create mode 100644 mobile/lib/services/conversations_service.dart rename mobile/lib/{utils/storage/friends.dart => services/friends_service.dart} (80%) delete mode 100644 mobile/lib/utils/storage/conversations.dart diff --git a/mobile/lib/components/custom_circle_avatar.dart b/mobile/lib/components/custom_circle_avatar.dart index aa9d459..940cb84 100644 --- a/mobile/lib/components/custom_circle_avatar.dart +++ b/mobile/lib/components/custom_circle_avatar.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:path/path.dart'; enum AvatarTypes { initials, diff --git a/mobile/lib/components/qr_reader.dart b/mobile/lib/components/qr_reader.dart index cc133cc..8a41ac1 100644 --- a/mobile/lib/components/qr_reader.dart +++ b/mobile/lib/components/qr_reader.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'dart:io'; -import 'package:Envelope/components/custom_title_bar.dart'; import 'package:flutter/material.dart'; import 'package:pointycastle/impl.dart'; import 'package:qr_code_scanner/qr_code_scanner.dart'; @@ -9,8 +8,9 @@ import 'package:sqflite/sqflite.dart'; import 'package:uuid/uuid.dart'; import 'package:http/http.dart' as http; -import '/models/friends.dart'; -import '/models/my_profile.dart'; +import '/components/custom_title_bar.dart'; +import '/database/models/friends.dart'; +import '/database/models/my_profile.dart'; import '/utils/encryption/aes_helper.dart'; import '/utils/encryption/crypto_utils.dart'; import '/utils/storage/database.dart'; diff --git a/mobile/lib/components/user_search_result.dart b/mobile/lib/components/user_search_result.dart index 2885e7e..94a2819 100644 --- a/mobile/lib/components/user_search_result.dart +++ b/mobile/lib/components/user_search_result.dart @@ -2,13 +2,12 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:http/http.dart' as http; import 'package:pointycastle/impl.dart'; import '/components/custom_circle_avatar.dart'; import '/data_models/user_search.dart'; -import '/models/my_profile.dart'; +import '/database/models/my_profile.dart'; import '/utils/encryption/aes_helper.dart'; import '/utils/storage/session_cookie.dart'; import '/utils/strings.dart'; diff --git a/mobile/lib/components/view_image.dart b/mobile/lib/components/view_image.dart index 79e7d88..d7a3382 100644 --- a/mobile/lib/components/view_image.dart +++ b/mobile/lib/components/view_image.dart @@ -1,7 +1,8 @@ -import 'package:Envelope/components/custom_title_bar.dart'; -import 'package:Envelope/models/image_message.dart'; import 'package:flutter/material.dart'; +import '/components/custom_title_bar.dart'; +import '/database/models/image_message.dart'; + class ViewImage extends StatelessWidget { const ViewImage({ Key? key, diff --git a/mobile/lib/models/conversation_users.dart b/mobile/lib/database/models/conversation_users.dart similarity index 97% rename from mobile/lib/models/conversation_users.dart rename to mobile/lib/database/models/conversation_users.dart index 04ca747..f8d74d6 100644 --- a/mobile/lib/models/conversation_users.dart +++ b/mobile/lib/database/models/conversation_users.dart @@ -1,12 +1,12 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'package:Envelope/utils/encryption/aes_helper.dart'; -import 'package:Envelope/utils/encryption/crypto_utils.dart'; import 'package:pointycastle/impl.dart'; -import '/models/conversations.dart'; +import '/database/models/conversations.dart'; import '/utils/storage/database.dart'; +import '/utils/encryption/aes_helper.dart'; +import '/utils/encryption/crypto_utils.dart'; Future getConversationUser(Conversation conversation, String userId) async { final db = await getDatabaseConnection(); diff --git a/mobile/lib/models/conversations.dart b/mobile/lib/database/models/conversations.dart similarity index 90% rename from mobile/lib/models/conversations.dart rename to mobile/lib/database/models/conversations.dart index c2a05ca..f391743 100644 --- a/mobile/lib/models/conversations.dart +++ b/mobile/lib/database/models/conversations.dart @@ -2,21 +2,21 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; -import 'package:Envelope/models/messages.dart'; -import 'package:Envelope/models/text_messages.dart'; import 'package:mime/mime.dart'; import 'package:pointycastle/export.dart'; import 'package:sqflite/sqflite.dart'; import 'package:uuid/uuid.dart'; -import '../utils/storage/write_file.dart'; -import '/models/conversation_users.dart'; -import '/models/friends.dart'; -import '/models/my_profile.dart'; +import '/database/models/messages.dart'; +import '/database/models/text_messages.dart'; +import '/database/models/conversation_users.dart'; +import '/database/models/friends.dart'; +import '/database/models/my_profile.dart'; import '/utils/encryption/aes_helper.dart'; import '/utils/encryption/crypto_utils.dart'; import '/utils/storage/database.dart'; import '/utils/strings.dart'; +import '/utils/storage/write_file.dart'; Future createConversation(String title, List friends, bool twoUser) async { final db = await getDatabaseConnection(); @@ -103,40 +103,6 @@ Future createConversation(String title, List friends, bool } -Future addUsersToConversation(Conversation conversation, List friends) async { - final db = await getDatabaseConnection(); - - var uuid = const Uuid(); - - for (Friend friend in friends) { - await db.insert( - 'conversation_users', - ConversationUser( - id: uuid.v4(), - userId: friend.friendId, - conversationId: conversation.id, - username: friend.username, - associationKey: uuid.v4(), - publicKey: friend.publicKey, - admin: false, - ).toMap(), - conflictAlgorithm: ConflictAlgorithm.replace, - ); - } - - return conversation; -} - -Conversation findConversationByDetailId(List conversations, String id) { - for (var conversation in conversations) { - if (conversation.id == id) { - return conversation; - } - } - // Or return `null`. - throw ArgumentError.value(id, 'id', 'No element with that id'); -} - Future getConversationById(String id) async { final db = await getDatabaseConnection(); diff --git a/mobile/lib/models/friends.dart b/mobile/lib/database/models/friends.dart similarity index 100% rename from mobile/lib/models/friends.dart rename to mobile/lib/database/models/friends.dart diff --git a/mobile/lib/models/image_message.dart b/mobile/lib/database/models/image_message.dart similarity index 96% rename from mobile/lib/models/image_message.dart rename to mobile/lib/database/models/image_message.dart index ff11a8a..0f1442a 100644 --- a/mobile/lib/models/image_message.dart +++ b/mobile/lib/database/models/image_message.dart @@ -2,15 +2,15 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; -import 'package:Envelope/models/my_profile.dart'; import 'package:Envelope/utils/storage/get_file.dart'; import 'package:Envelope/utils/storage/write_file.dart'; import 'package:mime/mime.dart'; import 'package:pointycastle/pointycastle.dart'; import 'package:uuid/uuid.dart'; -import '/models/conversations.dart'; -import '/models/messages.dart'; +import '/database/models/my_profile.dart'; +import '/database/models/conversations.dart'; +import '/database/models/messages.dart'; import '/utils/encryption/aes_helper.dart'; import '/utils/encryption/crypto_utils.dart'; import '/utils/strings.dart'; diff --git a/mobile/lib/models/messages.dart b/mobile/lib/database/models/messages.dart similarity index 94% rename from mobile/lib/models/messages.dart rename to mobile/lib/database/models/messages.dart index debb69f..371d407 100644 --- a/mobile/lib/models/messages.dart +++ b/mobile/lib/database/models/messages.dart @@ -5,11 +5,11 @@ import 'dart:typed_data'; import 'package:pointycastle/pointycastle.dart'; import 'package:uuid/uuid.dart'; -import '/models/image_message.dart'; -import '/models/conversation_users.dart'; -import '/models/my_profile.dart'; -import '/models/text_messages.dart'; -import '/models/conversations.dart'; +import '/database/models/image_message.dart'; +import '/database/models/conversation_users.dart'; +import '/database/models/my_profile.dart'; +import '/database/models/text_messages.dart'; +import '/database/models/conversations.dart'; import '/utils/encryption/crypto_utils.dart'; import '/utils/storage/database.dart'; diff --git a/mobile/lib/models/my_profile.dart b/mobile/lib/database/models/my_profile.dart similarity index 100% rename from mobile/lib/models/my_profile.dart rename to mobile/lib/database/models/my_profile.dart diff --git a/mobile/lib/models/text_messages.dart b/mobile/lib/database/models/text_messages.dart similarity index 97% rename from mobile/lib/models/text_messages.dart rename to mobile/lib/database/models/text_messages.dart index 0b85c59..9427462 100644 --- a/mobile/lib/models/text_messages.dart +++ b/mobile/lib/database/models/text_messages.dart @@ -4,8 +4,8 @@ import 'dart:typed_data'; import 'package:pointycastle/pointycastle.dart'; import 'package:uuid/uuid.dart'; -import '/models/conversations.dart'; -import '/models/messages.dart'; +import '/database/models/conversations.dart'; +import '/database/models/messages.dart'; import '/utils/encryption/aes_helper.dart'; import '/utils/encryption/crypto_utils.dart'; import '/utils/strings.dart'; diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index a63a1b6..daa8ffc 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -1,7 +1,8 @@ -import 'package:Envelope/models/my_profile.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; + +import '/database/models/my_profile.dart'; import '/views/main/home.dart'; import '/views/authentication/unauthenticated_landing.dart'; import '/views/authentication/login.dart'; diff --git a/mobile/lib/services/conversations_service.dart b/mobile/lib/services/conversations_service.dart new file mode 100644 index 0000000..2f844e6 --- /dev/null +++ b/mobile/lib/services/conversations_service.dart @@ -0,0 +1,290 @@ +import 'dart:convert'; + +import 'package:Envelope/utils/storage/get_file.dart'; +import 'package:http/http.dart' as http; +import 'package:pointycastle/export.dart'; +import 'package:sqflite/sqflite.dart'; +import 'package:uuid/uuid.dart'; + +import '/database/models/friends.dart'; +import '/database/models/conversation_users.dart'; +import '/database/models/conversations.dart'; +import '/database/models/my_profile.dart'; +import '/exceptions/update_data_exception.dart'; +import '/utils/encryption/aes_helper.dart'; +import '/utils/storage/database.dart'; +import '/utils/storage/session_cookie.dart'; + +class _BaseConversationsResult { + List conversations; + List detailIds; + + + _BaseConversationsResult({ + required this.conversations, + required this.detailIds, + }); +} + +class ConversationsService { + static Future saveConversation(Conversation conversation) async { + final db = await getDatabaseConnection(); + + db.update( + 'conversations', + conversation.toMap(), + where: 'id = ?', + whereArgs: [conversation.id], + ); + } + + static Future addUsersToConversation(Conversation conversation, List friends) async { + final db = await getDatabaseConnection(); + + var uuid = const Uuid(); + + for (Friend friend in friends) { + await db.insert( + 'conversation_users', + ConversationUser( + id: uuid.v4(), + userId: friend.friendId, + conversationId: conversation.id, + username: friend.username, + associationKey: uuid.v4(), + publicKey: friend.publicKey, + admin: false, + ).toMap(), + conflictAlgorithm: ConflictAlgorithm.replace, + ); + } + + return conversation; + } + + static Future updateConversation( + Conversation conversation, + { + includeUsers = false, + updatedImage = false, + saveConversation = true, + } ) async { + + if (saveConversation) { + await saveConversation(conversation); + } + + String sessionCookie = await getSessionCookie(); + + Map conversationJson = await conversation.payloadJson(includeUsers: includeUsers); + + var resp = await http.put( + await MyProfile.getServerUrl('api/v1/auth/conversations'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'cookie': sessionCookie, + }, + body: jsonEncode(conversationJson), + ); + + if (resp.statusCode != 204) { + throw UpdateDataException('Unable to update conversation, please try again later.'); + } + + if (!updatedImage) { + return; + } + + Map attachmentJson = conversation.payloadImageJson(); + + resp = await http.post( + await MyProfile.getServerUrl('api/v1/auth/conversations/${conversation.id}/image'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'cookie': sessionCookie, + }, + body: jsonEncode(attachmentJson), + ); + + if (resp.statusCode != 204) { + throw UpdateDataException('Unable to update conversation image, please try again later.'); + } + } + + static Future<_BaseConversationsResult> _getBaseConversations() async { + RSAPrivateKey privKey = await MyProfile.getPrivateKey(); + + http.Response resp = await http.get( + await MyProfile.getServerUrl('api/v1/auth/conversations'), + headers: { + 'cookie': await getSessionCookie(), + } + ); + + if (resp.statusCode != 200) { + throw Exception(resp.body); + } + + _BaseConversationsResult result = _BaseConversationsResult( + conversations: [], + detailIds: [] + ); + + List conversationsJson = jsonDecode(resp.body); + + if (conversationsJson.isEmpty) { + return result; + } + + for (var i = 0; i < conversationsJson.length; i++) { + Conversation conversation = Conversation.fromJson( + conversationsJson[i] as Map, + privKey, + ); + result.conversations.add(conversation); + result.detailIds.add(conversation.id); + } + + return result; + } + + static Conversation _findConversationByDetailId(List conversations, String id) { + for (var conversation in conversations) { + if (conversation.id == id) { + return conversation; + } + } + // Or return `null`. + throw ArgumentError.value(id, 'id', 'No element with that id'); + } + + + static Future _storeConversations(Database db, Conversation conversation, Map detailsJson) async { + conversation.messageExpiryDefault = detailsJson['message_expiry']; + + conversation.twoUser = AesHelper.aesDecrypt( + base64.decode(conversation.symmetricKey), + base64.decode(detailsJson['two_user']), + ) == 'true'; + + if (conversation.twoUser) { + MyProfile profile = await MyProfile.getProfile(); + + final db = await getDatabaseConnection(); + + List> maps = await db.query( + 'conversation_users', + where: 'conversation_id = ? AND user_id != ?', + whereArgs: [ conversation.id, profile.id ], + ); + + if (maps.length != 1) { + throw ArgumentError('Invalid user id'); + } + + conversation.name = maps[0]['username']; + } else { + conversation.name = AesHelper.aesDecrypt( + base64.decode(conversation.symmetricKey), + base64.decode(detailsJson['name']), + ); + } + + if (detailsJson['attachment_id'] != null) { + conversation.icon = await getFile( + '$defaultServerUrl/files/${detailsJson['attachment']['image_link']}', + conversation.id, + conversation.symmetricKey, + ).catchError((dynamic) async {}); + } + + await db.insert( + 'conversations', + conversation.toMap(), + conflictAlgorithm: ConflictAlgorithm.replace, + ); + + List usersData = detailsJson['users']; + + for (var i = 0; i < usersData.length; i++) { + ConversationUser conversationUser = ConversationUser.fromJson( + usersData[i] as Map, + base64.decode(conversation.symmetricKey), + ); + + await db.insert( + 'conversation_users', + conversationUser.toMap(), + conflictAlgorithm: ConflictAlgorithm.replace, + ); + } + } + + static Future updateConversations() async { + _BaseConversationsResult baseConvs = await _getBaseConversations(); + + Map params = {}; + params['conversation_detail_ids'] = baseConvs.detailIds.join(','); + var uri = await MyProfile.getServerUrl('api/v1/auth/conversation_details'); + uri = uri.replace(queryParameters: params); + + http.Response resp = await http.get( + uri, + headers: { + 'cookie': await getSessionCookie(), + } + ); + + if (resp.statusCode != 200) { + throw Exception(resp.body); + } + + final db = await getDatabaseConnection(); + + List conversationsDetailsJson = jsonDecode(resp.body); + for (var i = 0; i < conversationsDetailsJson.length; i++) { + Map detailsJson = conversationsDetailsJson[i] as Map; + Conversation conversation = _findConversationByDetailId(baseConvs.conversations, detailsJson['id']); + await _storeConversations(db, conversation, detailsJson); + } + } + + static Future uploadConversation(Conversation conversation) async { + String sessionCookie = await getSessionCookie(); + + Map conversationJson = await conversation.payloadJson(); + + var resp = await http.post( + await MyProfile.getServerUrl('api/v1/auth/conversations'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'cookie': sessionCookie, + }, + body: jsonEncode(conversationJson), + ); + + if (resp.statusCode != 204) { + throw Exception('Failed to create conversation'); + } + } + + static Future updateMessageExpiry(String id, String messageExpiry) async { + http.Response resp = await http.post( + await MyProfile.getServerUrl( + 'api/v1/auth/conversations/$id/message_expiry' + ), + headers: { + 'cookie': await getSessionCookie(), + }, + body: jsonEncode({ + 'message_expiry': messageExpiry, + }), + ); + + if (resp.statusCode == 204) { + return; + } + + throw Exception('Cannot set message expiry for conversation'); + } +} diff --git a/mobile/lib/utils/storage/friends.dart b/mobile/lib/services/friends_service.dart similarity index 80% rename from mobile/lib/utils/storage/friends.dart rename to mobile/lib/services/friends_service.dart index 52fe63e..b6d2fd8 100644 --- a/mobile/lib/utils/storage/friends.dart +++ b/mobile/lib/services/friends_service.dart @@ -4,15 +4,15 @@ import 'package:http/http.dart' as http; import 'package:pointycastle/export.dart'; import 'package:sqflite/sqflite.dart'; -import '/models/friends.dart'; -import '/models/my_profile.dart'; +import '/database/models/friends.dart'; +import '/database/models/my_profile.dart'; import '/utils/storage/database.dart'; import '/utils/storage/session_cookie.dart'; -Future updateFriends() async { - RSAPrivateKey privKey = await MyProfile.getPrivateKey(); +class FriendsService { + static Future updateFriends() async { + RSAPrivateKey privKey = await MyProfile.getPrivateKey(); - // try { var resp = await http.get( await MyProfile.getServerUrl('api/v1/auth/friend_requests'), headers: { @@ -40,9 +40,5 @@ Future updateFriends() async { conflictAlgorithm: ConflictAlgorithm.replace, ); } - - // } catch (SocketException) { - // return; - // } + } } - diff --git a/mobile/lib/utils/encryption/aes_helper.dart b/mobile/lib/utils/encryption/aes_helper.dart index 07f7d93..9b7283c 100644 --- a/mobile/lib/utils/encryption/aes_helper.dart +++ b/mobile/lib/utils/encryption/aes_helper.dart @@ -1,6 +1,6 @@ import 'dart:convert'; import 'dart:typed_data'; -import "package:pointycastle/export.dart"; +import 'package:pointycastle/export.dart'; Uint8List createUint8ListFromString(String s) { var ret = Uint8List(s.length); diff --git a/mobile/lib/utils/encryption/crypto_utils.dart b/mobile/lib/utils/encryption/crypto_utils.dart index d580eda..98f7f69 100644 --- a/mobile/lib/utils/encryption/crypto_utils.dart +++ b/mobile/lib/utils/encryption/crypto_utils.dart @@ -5,7 +5,7 @@ import 'dart:typed_data'; import 'package:pointycastle/asn1/object_identifiers.dart'; import 'package:pointycastle/export.dart'; import 'package:pointycastle/pointycastle.dart'; -import 'package:pointycastle/src/utils.dart' as thing; +import 'package:pointycastle/src/utils.dart' as crypt_util; import 'package:pointycastle/ecc/ecc_fp.dart' as ecc_fp; import './string_utils.dart'; @@ -36,25 +36,25 @@ class CryptoUtils { /// Converts the [RSAPublicKey.modulus] from the given [publicKey] to a [Uint8List]. /// static Uint8List rsaPublicKeyModulusToBytes(RSAPublicKey publicKey) => - thing.encodeBigInt(publicKey.modulus); + crypt_util.encodeBigInt(publicKey.modulus); /// /// Converts the [RSAPublicKey.exponent] from the given [publicKey] to a [Uint8List]. /// static Uint8List rsaPublicKeyExponentToBytes(RSAPublicKey publicKey) => - thing.encodeBigInt(publicKey.exponent); + crypt_util.encodeBigInt(publicKey.exponent); /// /// Converts the [RSAPrivateKey.modulus] from the given [privateKey] to a [Uint8List]. /// static Uint8List rsaPrivateKeyModulusToBytes(RSAPrivateKey privateKey) => - thing.encodeBigInt(privateKey.modulus); + crypt_util.encodeBigInt(privateKey.modulus); /// /// Converts the [RSAPrivateKey.exponent] from the given [privateKey] to a [Uint8List]. /// static Uint8List rsaPrivateKeyExponentToBytes(RSAPrivateKey privateKey) => - thing.encodeBigInt(privateKey.exponent); + crypt_util.encodeBigInt(privateKey.exponent); /// /// Get a SHA1 Thumbprint for the given [bytes]. @@ -591,7 +591,7 @@ class CryptoUtils { var outer = ASN1Sequence(); var version = ASN1Integer(BigInt.from(1)); - var privateKeyAsBytes = thing.encodeBigInt(ecPrivateKey.d); + var privateKeyAsBytes = crypt_util.encodeBigInt(ecPrivateKey.d); var privateKey = ASN1OctetString(octets: privateKeyAsBytes); var choice = ASN1Sequence(tag: 0xA0); @@ -722,7 +722,7 @@ class CryptoUtils { x = privateKeyAsOctetString.valueBytes!; } - return ECPrivateKey(thing.decodeBigInt(x), ECDomainParameters(curveName)); + return ECPrivateKey(crypt_util.decodeBigInt(x), ECDomainParameters(curveName)); } /// @@ -760,8 +760,8 @@ class CryptoUtils { var x = pubBytes.sublist(1, (pubBytes.length / 2).round()); var y = pubBytes.sublist(1 + x.length, pubBytes.length); var params = ECDomainParameters(curveName); - var bigX = thing.decodeBigIntWithSign(1, x); - var bigY = thing.decodeBigIntWithSign(1, y); + var bigX = crypt_util.decodeBigIntWithSign(1, x); + var bigY = crypt_util.decodeBigIntWithSign(1, y); var pubKey = ECPublicKey( ecc_fp.ECPoint( params.curve as ecc_fp.ECCurve, diff --git a/mobile/lib/utils/encryption/rsa_key_helper.dart b/mobile/lib/utils/encryption/rsa_key_helper.dart index 72e854b..23f055c 100644 --- a/mobile/lib/utils/encryption/rsa_key_helper.dart +++ b/mobile/lib/utils/encryption/rsa_key_helper.dart @@ -1,8 +1,8 @@ import 'dart:convert'; import 'dart:math'; import 'dart:typed_data'; -import "package:pointycastle/export.dart"; -import "package:asn1lib/asn1lib.dart"; +import 'package:pointycastle/export.dart'; +import 'package:asn1lib/asn1lib.dart'; /* var rsaKeyHelper = RsaKeyHelper(); diff --git a/mobile/lib/utils/encryption/string_utils.dart b/mobile/lib/utils/encryption/string_utils.dart index ca40eee..907405b 100644 --- a/mobile/lib/utils/encryption/string_utils.dart +++ b/mobile/lib/utils/encryption/string_utils.dart @@ -5,7 +5,7 @@ import 'dart:math'; /// Helper class for String operations /// class StringUtils { - static AsciiCodec asciiCodec = AsciiCodec(); + static AsciiCodec asciiCodec = const AsciiCodec(); /// /// Returns the given string or the default string if the given string is null diff --git a/mobile/lib/utils/storage/conversations.dart b/mobile/lib/utils/storage/conversations.dart deleted file mode 100644 index 096b9ba..0000000 --- a/mobile/lib/utils/storage/conversations.dart +++ /dev/null @@ -1,202 +0,0 @@ -import 'dart:convert'; - -import 'package:Envelope/exceptions/update_data_exception.dart'; -import 'package:Envelope/utils/storage/get_file.dart'; -import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; -import 'package:pointycastle/export.dart'; -import 'package:sqflite/sqflite.dart'; - -import '/components/flash_message.dart'; -import '/models/conversation_users.dart'; -import '/models/conversations.dart'; -import '/models/my_profile.dart'; -import '/utils/encryption/aes_helper.dart'; -import '/utils/storage/database.dart'; -import '/utils/storage/session_cookie.dart'; - -Future updateConversation( - Conversation conversation, - { - includeUsers = false, - updatedImage = false, - } ) async { - String sessionCookie = await getSessionCookie(); - - Map conversationJson = await conversation.payloadJson(includeUsers: includeUsers); - - var resp = await http.put( - await MyProfile.getServerUrl('api/v1/auth/conversations'), - headers: { - 'Content-Type': 'application/json; charset=UTF-8', - 'cookie': sessionCookie, - }, - body: jsonEncode(conversationJson), - ); - - if (resp.statusCode != 204) { - throw UpdateDataException('Unable to update conversation, please try again later.'); - } - - if (!updatedImage) { - return; - } - - Map attachmentJson = conversation.payloadImageJson(); - - resp = await http.post( - await MyProfile.getServerUrl('api/v1/auth/conversations/${conversation.id}/image'), - headers: { - 'Content-Type': 'application/json; charset=UTF-8', - 'cookie': sessionCookie, - }, - body: jsonEncode(attachmentJson), - ); - - if (resp.statusCode != 204) { - throw UpdateDataException('Unable to update conversation image, please try again later.'); - } -} - -// TODO: Refactor this function -Future updateConversations() async { - RSAPrivateKey privKey = await MyProfile.getPrivateKey(); - - // try { - var resp = await http.get( - await MyProfile.getServerUrl('api/v1/auth/conversations'), - headers: { - 'cookie': await getSessionCookie(), - } - ); - - if (resp.statusCode != 200) { - throw Exception(resp.body); - } - - List conversations = []; - List conversationsDetailIds = []; - - List conversationsJson = jsonDecode(resp.body); - - if (conversationsJson.isEmpty) { - return; - } - - for (var i = 0; i < conversationsJson.length; i++) { - Conversation conversation = Conversation.fromJson( - conversationsJson[i] as Map, - privKey, - ); - conversations.add(conversation); - conversationsDetailIds.add(conversation.id); - } - - Map params = {}; - params['conversation_detail_ids'] = conversationsDetailIds.join(','); - var uri = await MyProfile.getServerUrl('api/v1/auth/conversation_details'); - uri = uri.replace(queryParameters: params); - - resp = await http.get( - uri, - headers: { - 'cookie': await getSessionCookie(), - } - ); - - if (resp.statusCode != 200) { - throw Exception(resp.body); - } - - final db = await getDatabaseConnection(); - - List conversationsDetailsJson = jsonDecode(resp.body); - for (var i = 0; i < conversationsDetailsJson.length; i++) { - var conversationDetailJson = conversationsDetailsJson[i] as Map; - var conversation = findConversationByDetailId(conversations, conversationDetailJson['id']); - - conversation.messageExpiryDefault = conversationDetailJson['message_expiry']; - - conversation.twoUser = AesHelper.aesDecrypt( - base64.decode(conversation.symmetricKey), - base64.decode(conversationDetailJson['two_user']), - ) == 'true'; - - if (conversation.twoUser) { - MyProfile profile = await MyProfile.getProfile(); - - final db = await getDatabaseConnection(); - - List> maps = await db.query( - 'conversation_users', - where: 'conversation_id = ? AND user_id != ?', - whereArgs: [ conversation.id, profile.id ], - ); - - if (maps.length != 1) { - throw ArgumentError('Invalid user id'); - } - - conversation.name = maps[0]['username']; - } else { - conversation.name = AesHelper.aesDecrypt( - base64.decode(conversation.symmetricKey), - base64.decode(conversationDetailJson['name']), - ); - } - - // TODO: Handle exception here - if (conversationDetailJson['attachment_id'] != null) { - conversation.icon = await getFile( - '$defaultServerUrl/files/${conversationDetailJson['attachment']['image_link']}', - conversation.id, - conversation.symmetricKey, - ); - } - - await db.insert( - 'conversations', - conversation.toMap(), - conflictAlgorithm: ConflictAlgorithm.replace, - ); - - List usersData = conversationDetailJson['users']; - - for (var i = 0; i < usersData.length; i++) { - ConversationUser conversationUser = ConversationUser.fromJson( - usersData[i] as Map, - base64.decode(conversation.symmetricKey), - ); - - await db.insert( - 'conversation_users', - conversationUser.toMap(), - conflictAlgorithm: ConflictAlgorithm.replace, - ); - } - } - // } catch (SocketException) { - // return; - // } -} - - -Future uploadConversation(Conversation conversation) async { - String sessionCookie = await getSessionCookie(); - - Map conversationJson = await conversation.payloadJson(); - - var resp = await http.post( - await MyProfile.getServerUrl('api/v1/auth/conversations'), - headers: { - 'Content-Type': 'application/json; charset=UTF-8', - 'cookie': sessionCookie, - }, - body: jsonEncode(conversationJson), - ); - - if (resp.statusCode != 204) { - throw Exception('Failed to create conversation'); - } -} - diff --git a/mobile/lib/utils/storage/messages.dart b/mobile/lib/utils/storage/messages.dart index be07ca1..4372fa3 100644 --- a/mobile/lib/utils/storage/messages.dart +++ b/mobile/lib/utils/storage/messages.dart @@ -1,17 +1,17 @@ import 'dart:convert'; import 'dart:io'; -import 'package:Envelope/models/messages.dart'; import 'package:Envelope/utils/storage/write_file.dart'; import 'package:http/http.dart' as http; import 'package:sqflite/sqflite.dart'; import 'package:uuid/uuid.dart'; -import '/models/image_message.dart'; -import '/models/text_messages.dart'; -import '/models/conversation_users.dart'; -import '/models/conversations.dart'; -import '/models/my_profile.dart'; +import '/database/models/messages.dart'; +import '/database/models/image_message.dart'; +import '/database/models/text_messages.dart'; +import '/database/models/conversation_users.dart'; +import '/database/models/conversations.dart'; +import '/database/models/my_profile.dart'; import '/utils/storage/database.dart'; import '/utils/storage/session_cookie.dart'; diff --git a/mobile/lib/utils/strings.dart b/mobile/lib/utils/strings.dart index 1c8b117..92b3b67 100644 --- a/mobile/lib/utils/strings.dart +++ b/mobile/lib/utils/strings.dart @@ -2,7 +2,7 @@ import 'dart:math'; String generateRandomString(int len) { var r = Random(); - const _chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890'; - return List.generate(len, (index) => _chars[r.nextInt(_chars.length)]).join(); + const chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890'; + return List.generate(len, (index) => chars[r.nextInt(chars.length)]).join(); } diff --git a/mobile/lib/views/authentication/login.dart b/mobile/lib/views/authentication/login.dart index 3b38289..e89633b 100644 --- a/mobile/lib/views/authentication/login.dart +++ b/mobile/lib/views/authentication/login.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import '/components/flash_message.dart'; -import '/models/my_profile.dart'; +import '/database/models/my_profile.dart'; import '/utils/storage/session_cookie.dart'; class LoginResponse { diff --git a/mobile/lib/views/authentication/signup.dart b/mobile/lib/views/authentication/signup.dart index effb89e..5739101 100644 --- a/mobile/lib/views/authentication/signup.dart +++ b/mobile/lib/views/authentication/signup.dart @@ -1,11 +1,11 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'package:Envelope/components/flash_message.dart'; -import 'package:Envelope/models/my_profile.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; +import '/components/flash_message.dart'; +import '/database/models/my_profile.dart'; import '/utils/encryption/aes_helper.dart'; import '/utils/encryption/crypto_utils.dart'; diff --git a/mobile/lib/views/main/conversation/create_add_users.dart b/mobile/lib/views/main/conversation/create_add_users.dart index e1ddf59..d75d856 100644 --- a/mobile/lib/views/main/conversation/create_add_users.dart +++ b/mobile/lib/views/main/conversation/create_add_users.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '/models/friends.dart'; +import '/database/models/friends.dart'; import '/views/main/conversation/create_add_users_list.dart'; class ConversationAddFriendsList extends StatefulWidget { diff --git a/mobile/lib/views/main/conversation/create_add_users_list.dart b/mobile/lib/views/main/conversation/create_add_users_list.dart index fec37f6..7ea928a 100644 --- a/mobile/lib/views/main/conversation/create_add_users_list.dart +++ b/mobile/lib/views/main/conversation/create_add_users_list.dart @@ -1,7 +1,8 @@ -import 'package:Envelope/components/custom_circle_avatar.dart'; -import 'package:Envelope/models/friends.dart'; import 'package:flutter/material.dart'; +import '/components/custom_circle_avatar.dart'; +import '/database/models/friends.dart'; + class ConversationAddFriendItem extends StatefulWidget{ final Friend friend; final ValueChanged isSelected; diff --git a/mobile/lib/views/main/conversation/detail.dart b/mobile/lib/views/main/conversation/detail.dart index b46a34f..7f1dd30 100644 --- a/mobile/lib/views/main/conversation/detail.dart +++ b/mobile/lib/views/main/conversation/detail.dart @@ -6,9 +6,9 @@ import 'package:image_picker/image_picker.dart'; import '/components/custom_title_bar.dart'; import '/components/file_picker.dart'; -import '/models/conversations.dart'; -import '/models/messages.dart'; -import '/models/my_profile.dart'; +import '/database/models/conversations.dart'; +import '/database/models/messages.dart'; +import '/database/models/my_profile.dart'; import '/utils/storage/messages.dart'; import '/views/main/conversation/settings.dart'; diff --git a/mobile/lib/views/main/conversation/edit_details.dart b/mobile/lib/views/main/conversation/edit_details.dart index 9106dac..ce717e1 100644 --- a/mobile/lib/views/main/conversation/edit_details.dart +++ b/mobile/lib/views/main/conversation/edit_details.dart @@ -1,11 +1,11 @@ import 'dart:io'; -import 'package:Envelope/components/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import '/components/custom_circle_avatar.dart'; -import '/models/conversations.dart'; +import '/components/file_picker.dart'; +import '/database/models/conversations.dart'; class ConversationEditDetails extends StatefulWidget { final Function(String conversationName, File? conversationIcon) saveCallback; diff --git a/mobile/lib/views/main/conversation/list.dart b/mobile/lib/views/main/conversation/list.dart index 7c1b6b2..a82067b 100644 --- a/mobile/lib/views/main/conversation/list.dart +++ b/mobile/lib/views/main/conversation/list.dart @@ -2,15 +2,15 @@ import 'dart:io'; import 'package:Envelope/components/custom_title_bar.dart'; import 'package:Envelope/components/flash_message.dart'; -import 'package:Envelope/models/friends.dart'; -import 'package:Envelope/utils/storage/conversations.dart'; +import 'package:Envelope/services/conversations_service.dart'; import 'package:flutter/material.dart'; -import '/models/conversations.dart'; -import '/views/main/conversation/edit_details.dart'; -import '/views/main/conversation/list_item.dart'; import 'create_add_users.dart'; import 'detail.dart'; +import '/database/models/friends.dart'; +import '/database/models/conversations.dart'; +import '/views/main/conversation/edit_details.dart'; +import '/views/main/conversation/list_item.dart'; class ConversationList extends StatefulWidget { final List conversations; @@ -80,11 +80,15 @@ class _ConversationListState extends State { false, ); - uploadConversation(conversation) + ConversationsService.uploadConversation(conversation) .catchError((dynamic) { showMessage('Failed to create conversation', context); }); + if (!mounted) { + return; + } + Navigator.of(context).popUntil((route) => route.isFirst); Navigator.push(context, MaterialPageRoute(builder: (context) { return ConversationDetail( diff --git a/mobile/lib/views/main/conversation/list_item.dart b/mobile/lib/views/main/conversation/list_item.dart index 670919e..ecd3f9a 100644 --- a/mobile/lib/views/main/conversation/list_item.dart +++ b/mobile/lib/views/main/conversation/list_item.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import '/models/messages.dart'; +import '/database/models/messages.dart'; import '/components/custom_circle_avatar.dart'; -import '/models/conversations.dart'; +import '/database/models/conversations.dart'; import '/views/main/conversation/detail.dart'; import '/utils/time.dart'; diff --git a/mobile/lib/views/main/conversation/message.dart b/mobile/lib/views/main/conversation/message.dart index f83b4ce..e4e7570 100644 --- a/mobile/lib/views/main/conversation/message.dart +++ b/mobile/lib/views/main/conversation/message.dart @@ -1,10 +1,10 @@ -import 'package:Envelope/components/view_image.dart'; -import 'package:Envelope/models/image_message.dart'; -import 'package:Envelope/models/my_profile.dart'; -import 'package:Envelope/utils/time.dart'; import 'package:flutter/material.dart'; -import '/models/messages.dart'; +import '/components/view_image.dart'; +import '/database/models/image_message.dart'; +import '/database/models/my_profile.dart'; +import '/database/models/messages.dart'; +import '/utils/time.dart'; @immutable class ConversationMessage extends StatefulWidget { diff --git a/mobile/lib/views/main/conversation/permissions.dart b/mobile/lib/views/main/conversation/permissions.dart index 6524fdb..803d8d2 100644 --- a/mobile/lib/views/main/conversation/permissions.dart +++ b/mobile/lib/views/main/conversation/permissions.dart @@ -1,11 +1,10 @@ -import 'package:Envelope/components/flash_message.dart'; -import 'package:Envelope/exceptions/update_data_exception.dart'; -import 'package:Envelope/utils/storage/conversations.dart'; -import 'package:Envelope/utils/storage/database.dart'; import 'package:flutter/material.dart'; import '/components/custom_title_bar.dart'; -import '/models/conversations.dart'; +import '/components/flash_message.dart'; +import '/database/models/conversations.dart'; +import '/exceptions/update_data_exception.dart'; +import '/services/conversations_service.dart'; class ConversationPermissions extends StatefulWidget { const ConversationPermissions({ @@ -47,15 +46,7 @@ class _ConversationPermissionsState extends State { ) ), beforeBack: () async { - final db = await getDatabaseConnection(); - db.update( - 'conversations', - widget.conversation.toMap(), - where: 'id = ?', - whereArgs: [widget.conversation.id], - ); - - updateConversation(widget.conversation) + ConversationsService.updateConversation(widget.conversation) .catchError((error) { String message = error.toString(); if (error.runtimeType != UpdateDataException) { diff --git a/mobile/lib/views/main/conversation/settings.dart b/mobile/lib/views/main/conversation/settings.dart index ce29174..2920359 100644 --- a/mobile/lib/views/main/conversation/settings.dart +++ b/mobile/lib/views/main/conversation/settings.dart @@ -1,8 +1,6 @@ import 'dart:convert'; import 'dart:io'; -import 'package:Envelope/utils/storage/session_cookie.dart'; -import 'package:Envelope/views/main/conversation/permissions.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; @@ -10,18 +8,20 @@ import '/components/custom_title_bar.dart'; import '/components/flash_message.dart'; import '/components/select_message_ttl.dart'; import '/exceptions/update_data_exception.dart'; -import '/models/friends.dart'; import '/utils/encryption/crypto_utils.dart'; import '/utils/storage/write_file.dart'; import '/views/main/conversation/create_add_users.dart'; -import '/models/conversation_users.dart'; -import '/models/conversations.dart'; -import '/models/my_profile.dart'; +import '/database/models/friends.dart'; +import '/database/models/conversation_users.dart'; +import '/database/models/conversations.dart'; +import '/database/models/my_profile.dart'; import '/views/main/conversation/settings_user_list_item.dart'; import '/views/main/conversation/edit_details.dart'; import '/components/custom_circle_avatar.dart'; import '/utils/storage/database.dart'; -import '/utils/storage/conversations.dart'; +import '/services/conversations_service.dart'; +import '/utils/storage/session_cookie.dart'; +import '/views/main/conversation/permissions.dart'; class ConversationSettings extends StatefulWidget { const ConversationSettings({ @@ -128,9 +128,7 @@ class _ConversationSettingsState extends State { widget.conversation.name = conversationName; widget.conversation.icon = writtenFile; - await saveConversation(); - - await updateConversation(widget.conversation, updatedImage: updatedImage) + await ConversationsService.updateConversation(widget.conversation, updatedImage: updatedImage) .catchError((error) { String message = error.toString(); if (error.runtimeType != UpdateDataException) { @@ -139,7 +137,13 @@ class _ConversationSettingsState extends State { showMessage(message, context); }); + setState(() {}); + + if (!mounted) { + return; + } + Navigator.pop(context); }, conversation: widget.conversation, @@ -212,17 +216,26 @@ class _ConversationSettingsState extends State { padding: const EdgeInsets.all(0), onPressed: () async { List friends = await unselectedFriends(); + if (!mounted) { + return; + } + Navigator.of(context).push( MaterialPageRoute(builder: (context) => ConversationAddFriendsList( friends: friends, saveCallback: (List selectedFriends) async { - addUsersToConversation( + ConversationsService.addUsersToConversation( widget.conversation, selectedFriends, ); - await updateConversation(widget.conversation, includeUsers: true); + await ConversationsService.updateConversation(widget.conversation, includeUsers: true); await getUsers(); + + if (!mounted) { + return; + } + Navigator.pop(context); }, )) @@ -264,28 +277,14 @@ class _ConversationSettingsState extends State { backCallback: (String messageExpiry) async { widget.conversation.messageExpiryDefault = messageExpiry; - http.post( - await MyProfile.getServerUrl( - 'api/v1/auth/conversations/${widget.conversation.id}/message_expiry' - ), - headers: { - 'cookie': await getSessionCookie(), - }, - body: jsonEncode({ - 'message_expiry': messageExpiry, - }), - ).then((http.Response response) { - if (response.statusCode == 204) { - return; - } - - showMessage( - 'Could not change the default message expiry, please try again later.', - context, - ); - }); - - saveConversation(); + ConversationsService.updateMessageExpiry(widget.conversation.id, messageExpiry) + .catchError((dynamic) { + showMessage( + 'Could not change the default message expiry, please try again later.', + context, + ); + }); + ConversationsService.saveConversation(widget.conversation); } )) ); @@ -299,10 +298,10 @@ class _ConversationSettingsState extends State { icon: const Icon(Icons.lock), style: ButtonStyle( alignment: Alignment.centerLeft, -foregroundColor: MaterialStateProperty.resolveWith( -(Set states) { -return Theme.of(context).colorScheme.onBackground; -}, + foregroundColor: MaterialStateProperty.resolveWith( + (Set states) { + return Theme.of(context).colorScheme.onBackground; + }, ) ), onPressed: () { @@ -368,15 +367,5 @@ return Theme.of(context).colorScheme.onBackground; getUsers(); setState(() {}); } - - saveConversation() async { - final db = await getDatabaseConnection(); - db.update( - 'conversations', - widget.conversation.toMap(), - where: 'id = ?', - whereArgs: [widget.conversation.id], - ); - } } diff --git a/mobile/lib/views/main/conversation/settings_user_list_item.dart b/mobile/lib/views/main/conversation/settings_user_list_item.dart index 5be6a6b..4491510 100644 --- a/mobile/lib/views/main/conversation/settings_user_list_item.dart +++ b/mobile/lib/views/main/conversation/settings_user_list_item.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import '/components/custom_circle_avatar.dart'; -import '/models/conversation_users.dart'; -import '/models/my_profile.dart'; +import '/database/models/conversation_users.dart'; +import '/database/models/my_profile.dart'; class ConversationSettingsUserListItem extends StatefulWidget{ final ConversationUser user; diff --git a/mobile/lib/views/main/friend/add_search.dart b/mobile/lib/views/main/friend/add_search.dart index 3b10e38..0429b51 100644 --- a/mobile/lib/views/main/friend/add_search.dart +++ b/mobile/lib/views/main/friend/add_search.dart @@ -6,7 +6,7 @@ import 'package:http/http.dart' as http; import '/utils/storage/session_cookie.dart'; import '/components/user_search_result.dart'; import '/data_models/user_search.dart'; -import '/models/my_profile.dart'; +import '/database/models/my_profile.dart'; class FriendAddSearch extends StatefulWidget { const FriendAddSearch({ diff --git a/mobile/lib/views/main/friend/list.dart b/mobile/lib/views/main/friend/list.dart index 53b7244..73ec21b 100644 --- a/mobile/lib/views/main/friend/list.dart +++ b/mobile/lib/views/main/friend/list.dart @@ -1,12 +1,12 @@ -import 'package:Envelope/components/custom_title_bar.dart'; -import 'package:Envelope/components/qr_reader.dart'; -import 'package:Envelope/views/main/friend/add_search.dart'; -import 'package:Envelope/views/main/friend/request_list_item.dart'; import 'package:flutter/material.dart'; -import '/models/friends.dart'; +import '/components/custom_title_bar.dart'; +import '/components/qr_reader.dart'; import '/components/custom_expandable_fab.dart'; +import '/database/models/friends.dart'; import '/views/main/friend/list_item.dart'; +import '/views/main/friend/add_search.dart'; +import '/views/main/friend/request_list_item.dart'; class FriendList extends StatefulWidget { final List friends; diff --git a/mobile/lib/views/main/friend/list_item.dart b/mobile/lib/views/main/friend/list_item.dart index bb83f6e..d8d9076 100644 --- a/mobile/lib/views/main/friend/list_item.dart +++ b/mobile/lib/views/main/friend/list_item.dart @@ -1,13 +1,13 @@ -import 'package:Envelope/components/custom_circle_avatar.dart'; -import 'package:Envelope/components/flash_message.dart'; -import 'package:Envelope/models/conversations.dart'; -import 'package:Envelope/models/friends.dart'; -import 'package:Envelope/utils/storage/conversations.dart'; -import 'package:Envelope/utils/storage/messages.dart'; -import 'package:Envelope/utils/strings.dart'; -import 'package:Envelope/views/main/conversation/detail.dart'; import 'package:flutter/material.dart'; +import '/components/custom_circle_avatar.dart'; +import '/components/flash_message.dart'; +import '/database/models/conversations.dart'; +import '/database/models/friends.dart'; +import '/services/conversations_service.dart'; +import '/utils/strings.dart'; +import '/views/main/conversation/detail.dart'; + class FriendListItem extends StatefulWidget{ final Friend friend; const FriendListItem({ @@ -69,11 +69,15 @@ class _FriendListItemState extends State { true, ); - uploadConversation(conversation) + ConversationsService.uploadConversation(conversation) .catchError((dynamic d) async { showMessage('Failed to create conversation', context); }); + if (!mounted) { + return; + } + Navigator.push(context, MaterialPageRoute(builder: (context){ return ConversationDetail( conversation: conversation!, diff --git a/mobile/lib/views/main/friend/request_list_item.dart b/mobile/lib/views/main/friend/request_list_item.dart index 4eccf46..2fa3354 100644 --- a/mobile/lib/views/main/friend/request_list_item.dart +++ b/mobile/lib/views/main/friend/request_list_item.dart @@ -6,8 +6,8 @@ import 'package:http/http.dart' as http; import '/components/flash_message.dart'; import '/components/custom_circle_avatar.dart'; -import '/models/friends.dart'; -import '/models/my_profile.dart'; +import '/database/models/friends.dart'; +import '/database/models/my_profile.dart'; import '/utils/storage/session_cookie.dart'; import '/utils/storage/database.dart'; import '/utils/encryption/aes_helper.dart'; diff --git a/mobile/lib/views/main/home.dart b/mobile/lib/views/main/home.dart index 157c25b..2b8a2b3 100644 --- a/mobile/lib/views/main/home.dart +++ b/mobile/lib/views/main/home.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; -import '/models/conversations.dart'; -import '/models/friends.dart'; -import '/models/my_profile.dart'; -import '/utils/storage/conversations.dart'; -import '/utils/storage/friends.dart'; +import '/database/models/conversations.dart'; +import '/database/models/friends.dart'; +import '/database/models/my_profile.dart'; +import '/services/conversations_service.dart'; +import '/services/friends_service.dart'; import '/utils/storage/messages.dart'; import '/utils/storage/session_cookie.dart'; import '/views/main/conversation/list.dart'; @@ -153,8 +153,8 @@ class _HomeState extends State { return; } - await updateFriends(); - await updateConversations(); + await FriendsService.updateFriends(); + await ConversationsService.updateConversations(); await updateMessageThreads(); conversations = await getConversations(); diff --git a/mobile/lib/views/main/profile/change_password.dart b/mobile/lib/views/main/profile/change_password.dart index 358fc88..8689b71 100644 --- a/mobile/lib/views/main/profile/change_password.dart +++ b/mobile/lib/views/main/profile/change_password.dart @@ -7,7 +7,7 @@ import 'package:pointycastle/impl.dart'; import '/components/flash_message.dart'; import '/components/custom_title_bar.dart'; -import '/models/my_profile.dart'; +import '/database/models/my_profile.dart'; import '/utils/encryption/aes_helper.dart'; import '/utils/encryption/crypto_utils.dart'; import '/utils/storage/session_cookie.dart'; diff --git a/mobile/lib/views/main/profile/change_server_url.dart b/mobile/lib/views/main/profile/change_server_url.dart index 813397b..fe516ec 100644 --- a/mobile/lib/views/main/profile/change_server_url.dart +++ b/mobile/lib/views/main/profile/change_server_url.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '/components/custom_title_bar.dart'; -import '/models/my_profile.dart'; +import '/database/models/my_profile.dart'; import '/utils/storage/database.dart'; @immutable diff --git a/mobile/lib/views/main/profile/profile.dart b/mobile/lib/views/main/profile/profile.dart index 2e00671..4db22b7 100644 --- a/mobile/lib/views/main/profile/profile.dart +++ b/mobile/lib/views/main/profile/profile.dart @@ -2,11 +2,6 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; -import 'package:Envelope/components/file_picker.dart'; -import 'package:Envelope/components/flash_message.dart'; -import 'package:Envelope/utils/encryption/aes_helper.dart'; -import 'package:Envelope/utils/storage/session_cookie.dart'; -import 'package:Envelope/utils/storage/write_file.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:image_picker/image_picker.dart'; @@ -16,12 +11,17 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:sliding_up_panel/sliding_up_panel.dart'; import 'package:http/http.dart' as http; +import '/components/file_picker.dart'; +import '/components/flash_message.dart'; import '/components/select_message_ttl.dart'; import '/components/custom_circle_avatar.dart'; import '/components/custom_title_bar.dart'; -import '/models/my_profile.dart'; +import '/database/models/my_profile.dart'; import '/utils/encryption/crypto_utils.dart'; import '/utils/storage/database.dart'; +import '/utils/encryption/aes_helper.dart'; +import '/utils/storage/session_cookie.dart'; +import '/utils/storage/write_file.dart'; import '/views/main/profile/change_password.dart'; import '/views/main/profile/change_server_url.dart';