Browse Source

WIP - Start working on service classes and move models dir

feature/add-notifications
Tovi Jaeschke-Rogers 2 years ago
parent
commit
74922b2804
41 changed files with 454 additions and 415 deletions
  1. +0
    -1
      mobile/lib/components/custom_circle_avatar.dart
  2. +3
    -3
      mobile/lib/components/qr_reader.dart
  3. +1
    -2
      mobile/lib/components/user_search_result.dart
  4. +3
    -2
      mobile/lib/components/view_image.dart
  5. +3
    -3
      mobile/lib/database/models/conversation_users.dart
  6. +6
    -40
      mobile/lib/database/models/conversations.dart
  7. +0
    -0
      mobile/lib/database/models/friends.dart
  8. +3
    -3
      mobile/lib/database/models/image_message.dart
  9. +5
    -5
      mobile/lib/database/models/messages.dart
  10. +0
    -0
      mobile/lib/database/models/my_profile.dart
  11. +2
    -2
      mobile/lib/database/models/text_messages.dart
  12. +2
    -1
      mobile/lib/main.dart
  13. +290
    -0
      mobile/lib/services/conversations_service.dart
  14. +6
    -10
      mobile/lib/services/friends_service.dart
  15. +1
    -1
      mobile/lib/utils/encryption/aes_helper.dart
  16. +9
    -9
      mobile/lib/utils/encryption/crypto_utils.dart
  17. +2
    -2
      mobile/lib/utils/encryption/rsa_key_helper.dart
  18. +1
    -1
      mobile/lib/utils/encryption/string_utils.dart
  19. +0
    -202
      mobile/lib/utils/storage/conversations.dart
  20. +6
    -6
      mobile/lib/utils/storage/messages.dart
  21. +2
    -2
      mobile/lib/utils/strings.dart
  22. +1
    -1
      mobile/lib/views/authentication/login.dart
  23. +2
    -2
      mobile/lib/views/authentication/signup.dart
  24. +1
    -1
      mobile/lib/views/main/conversation/create_add_users.dart
  25. +3
    -2
      mobile/lib/views/main/conversation/create_add_users_list.dart
  26. +3
    -3
      mobile/lib/views/main/conversation/detail.dart
  27. +2
    -2
      mobile/lib/views/main/conversation/edit_details.dart
  28. +10
    -6
      mobile/lib/views/main/conversation/list.dart
  29. +2
    -2
      mobile/lib/views/main/conversation/list_item.dart
  30. +5
    -5
      mobile/lib/views/main/conversation/message.dart
  31. +5
    -14
      mobile/lib/views/main/conversation/permissions.dart
  32. +37
    -48
      mobile/lib/views/main/conversation/settings.dart
  33. +2
    -2
      mobile/lib/views/main/conversation/settings_user_list_item.dart
  34. +1
    -1
      mobile/lib/views/main/friend/add_search.dart
  35. +5
    -5
      mobile/lib/views/main/friend/list.dart
  36. +13
    -9
      mobile/lib/views/main/friend/list_item.dart
  37. +2
    -2
      mobile/lib/views/main/friend/request_list_item.dart
  38. +7
    -7
      mobile/lib/views/main/home.dart
  39. +1
    -1
      mobile/lib/views/main/profile/change_password.dart
  40. +1
    -1
      mobile/lib/views/main/profile/change_server_url.dart
  41. +6
    -6
      mobile/lib/views/main/profile/profile.dart

+ 0
- 1
mobile/lib/components/custom_circle_avatar.dart View File

@ -1,7 +1,6 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path/path.dart';
enum AvatarTypes {
initials,


+ 3
- 3
mobile/lib/components/qr_reader.dart View File

@ -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';


+ 1
- 2
mobile/lib/components/user_search_result.dart View File

@ -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';


+ 3
- 2
mobile/lib/components/view_image.dart View File

@ -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,


mobile/lib/models/conversation_users.dart → mobile/lib/database/models/conversation_users.dart View File


mobile/lib/models/conversations.dart → mobile/lib/database/models/conversations.dart View File


mobile/lib/models/friends.dart → mobile/lib/database/models/friends.dart View File


mobile/lib/models/image_message.dart → mobile/lib/database/models/image_message.dart View File


mobile/lib/models/messages.dart → mobile/lib/database/models/messages.dart View File


mobile/lib/models/my_profile.dart → mobile/lib/database/models/my_profile.dart View File


mobile/lib/models/text_messages.dart → mobile/lib/database/models/text_messages.dart View File


+ 2
- 1
mobile/lib/main.dart View File

@ -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';


+ 290
- 0
mobile/lib/services/conversations_service.dart View File

@ -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<Conversation> conversations;
List<String> detailIds;
_BaseConversationsResult({
required this.conversations,
required this.detailIds,
});
}
class ConversationsService {
static Future<void> saveConversation(Conversation conversation) async {
final db = await getDatabaseConnection();
db.update(
'conversations',
conversation.toMap(),
where: 'id = ?',
whereArgs: [conversation.id],
);
}
static Future<Conversation> addUsersToConversation(Conversation conversation, List<Friend> 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<void> updateConversation(
Conversation conversation,
{
includeUsers = false,
updatedImage = false,
saveConversation = true,
} ) async {
if (saveConversation) {
await saveConversation(conversation);
}
String sessionCookie = await getSessionCookie();
Map<String, dynamic> conversationJson = await conversation.payloadJson(includeUsers: includeUsers);
var resp = await http.put(
await MyProfile.getServerUrl('api/v1/auth/conversations'),
headers: <String, String>{
'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<String, dynamic> attachmentJson = conversation.payloadImageJson();
resp = await http.post(
await MyProfile.getServerUrl('api/v1/auth/conversations/${conversation.id}/image'),
headers: <String, String>{
'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<dynamic> 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<String, dynamic>,
privKey,
);
result.conversations.add(conversation);
result.detailIds.add(conversation.id);
}
return result;
}
static Conversation _findConversationByDetailId(List<Conversation> 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<void> _storeConversations(Database db, Conversation conversation, Map<String, dynamic> 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<Map<String, dynamic>> 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<dynamic> usersData = detailsJson['users'];
for (var i = 0; i < usersData.length; i++) {
ConversationUser conversationUser = ConversationUser.fromJson(
usersData[i] as Map<String, dynamic>,
base64.decode(conversation.symmetricKey),
);
await db.insert(
'conversation_users',
conversationUser.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
}
static Future<void> updateConversations() async {
_BaseConversationsResult baseConvs = await _getBaseConversations();
Map<String, String> 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<dynamic> conversationsDetailsJson = jsonDecode(resp.body);
for (var i = 0; i < conversationsDetailsJson.length; i++) {
Map<String, dynamic> detailsJson = conversationsDetailsJson[i] as Map<String, dynamic>;
Conversation conversation = _findConversationByDetailId(baseConvs.conversations, detailsJson['id']);
await _storeConversations(db, conversation, detailsJson);
}
}
static Future<void> uploadConversation(Conversation conversation) async {
String sessionCookie = await getSessionCookie();
Map<String, dynamic> conversationJson = await conversation.payloadJson();
var resp = await http.post(
await MyProfile.getServerUrl('api/v1/auth/conversations'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'cookie': sessionCookie,
},
body: jsonEncode(conversationJson),
);
if (resp.statusCode != 204) {
throw Exception('Failed to create conversation');
}
}
static Future<void> 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');
}
}

mobile/lib/utils/storage/friends.dart → mobile/lib/services/friends_service.dart View File


+ 1
- 1
mobile/lib/utils/encryption/aes_helper.dart View File

@ -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);


+ 9
- 9
mobile/lib/utils/encryption/crypto_utils.dart View File

@ -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,


+ 2
- 2
mobile/lib/utils/encryption/rsa_key_helper.dart View File

@ -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();


+ 1
- 1
mobile/lib/utils/encryption/string_utils.dart View File

@ -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


+ 0
- 202
mobile/lib/utils/storage/conversations.dart View File

@ -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<void> updateConversation(
Conversation conversation,
{
includeUsers = false,
updatedImage = false,
} ) async {
String sessionCookie = await getSessionCookie();
Map<String, dynamic> conversationJson = await conversation.payloadJson(includeUsers: includeUsers);
var resp = await http.put(
await MyProfile.getServerUrl('api/v1/auth/conversations'),
headers: <String, String>{
'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<String, dynamic> attachmentJson = conversation.payloadImageJson();
resp = await http.post(
await MyProfile.getServerUrl('api/v1/auth/conversations/${conversation.id}/image'),
headers: <String, String>{
'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<void> 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<Conversation> conversations = [];
List<String> conversationsDetailIds = [];
List<dynamic> conversationsJson = jsonDecode(resp.body);
if (conversationsJson.isEmpty) {
return;
}
for (var i = 0; i < conversationsJson.length; i++) {
Conversation conversation = Conversation.fromJson(
conversationsJson[i] as Map<String, dynamic>,
privKey,
);
conversations.add(conversation);
conversationsDetailIds.add(conversation.id);
}
Map<String, String> 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<dynamic> conversationsDetailsJson = jsonDecode(resp.body);
for (var i = 0; i < conversationsDetailsJson.length; i++) {
var conversationDetailJson = conversationsDetailsJson[i] as Map<String, dynamic>;
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<Map<String, dynamic>> 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<dynamic> usersData = conversationDetailJson['users'];
for (var i = 0; i < usersData.length; i++) {
ConversationUser conversationUser = ConversationUser.fromJson(
usersData[i] as Map<String, dynamic>,
base64.decode(conversation.symmetricKey),
);
await db.insert(
'conversation_users',
conversationUser.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
}
// } catch (SocketException) {
// return;
// }
}
Future<void> uploadConversation(Conversation conversation) async {
String sessionCookie = await getSessionCookie();
Map<String, dynamic> conversationJson = await conversation.payloadJson();
var resp = await http.post(
await MyProfile.getServerUrl('api/v1/auth/conversations'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'cookie': sessionCookie,
},
body: jsonEncode(conversationJson),
);
if (resp.statusCode != 204) {
throw Exception('Failed to create conversation');
}
}

+ 6
- 6
mobile/lib/utils/storage/messages.dart View File

@ -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';


+ 2
- 2
mobile/lib/utils/strings.dart View File

@ -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();
}

+ 1
- 1
mobile/lib/views/authentication/login.dart View File

@ -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 {


+ 2
- 2
mobile/lib/views/authentication/signup.dart View File

@ -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';


+ 1
- 1
mobile/lib/views/main/conversation/create_add_users.dart View File

@ -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 {


+ 3
- 2
mobile/lib/views/main/conversation/create_add_users_list.dart View File

@ -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<bool> isSelected;


+ 3
- 3
mobile/lib/views/main/conversation/detail.dart View File

@ -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';


+ 2
- 2
mobile/lib/views/main/conversation/edit_details.dart View File

@ -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;


+ 10
- 6
mobile/lib/views/main/conversation/list.dart View File

@ -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<Conversation> conversations;
@ -80,11 +80,15 @@ class _ConversationListState extends State<ConversationList> {
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(


+ 2
- 2
mobile/lib/views/main/conversation/list_item.dart View File

@ -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';


+ 5
- 5
mobile/lib/views/main/conversation/message.dart View File

@ -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 {


+ 5
- 14
mobile/lib/views/main/conversation/permissions.dart View File

@ -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<ConversationPermissions> {
)
),
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) {


+ 37
- 48
mobile/lib/views/main/conversation/settings.dart View File

@ -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<ConversationSettings> {
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<ConversationSettings> {
showMessage(message, context);
});
setState(() {});
if (!mounted) {
return;
}
Navigator.pop(context);
},
conversation: widget.conversation,
@ -212,17 +216,26 @@ class _ConversationSettingsState extends State<ConversationSettings> {
padding: const EdgeInsets.all(0),
onPressed: () async {
List<Friend> friends = await unselectedFriends();
if (!mounted) {
return;
}
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => ConversationAddFriendsList(
friends: friends,
saveCallback: (List<Friend> 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<ConversationSettings> {
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<ConversationSettings> {
icon: const Icon(Icons.lock),
style: ButtonStyle(
alignment: Alignment.centerLeft,
foregroundColor: MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) {
return Theme.of(context).colorScheme.onBackground;
},
foregroundColor: MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> 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],
);
}
}

+ 2
- 2
mobile/lib/views/main/conversation/settings_user_list_item.dart View File

@ -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;


+ 1
- 1
mobile/lib/views/main/friend/add_search.dart View File

@ -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({


+ 5
- 5
mobile/lib/views/main/friend/list.dart View File

@ -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<Friend> friends;


+ 13
- 9
mobile/lib/views/main/friend/list_item.dart View File

@ -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<FriendListItem> {
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!,


+ 2
- 2
mobile/lib/views/main/friend/request_list_item.dart View File

@ -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';


+ 7
- 7
mobile/lib/views/main/home.dart View File

@ -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<Home> {
return;
}
await updateFriends();
await updateConversations();
await FriendsService.updateFriends();
await ConversationsService.updateConversations();
await updateMessageThreads();
conversations = await getConversations();


+ 1
- 1
mobile/lib/views/main/profile/change_password.dart View File

@ -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';


+ 1
- 1
mobile/lib/views/main/profile/change_server_url.dart View File

@ -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


+ 6
- 6
mobile/lib/views/main/profile/profile.dart View File

@ -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';


Loading…
Cancel
Save