diff --git a/lib/enums/user_page_visibility.dart b/lib/enums/user_page_visibility.dart index ca2361b..832951c 100644 --- a/lib/enums/user_page_visibility.dart +++ b/lib/enums/user_page_visibility.dart @@ -3,12 +3,3 @@ /// @author Pierre HUBERT enum UserPageVisibility { PRIVATE, PUBLIC, OPEN } - -/// Find the visibility level matching a string -UserPageVisibility userPageVisibilityFromString(String str) { - for (int i = 0; i < UserPageVisibility.values.length; i++) - if (UserPageVisibility.values[i].toString() == str) - return UserPageVisibility.values[i]; - - throw "$str is not a valid user page visibility level!"; -} diff --git a/lib/generated_plugin_registrant.dart b/lib/generated_plugin_registrant.dart index fe73bc1..ef6f366 100644 --- a/lib/generated_plugin_registrant.dart +++ b/lib/generated_plugin_registrant.dart @@ -5,12 +5,13 @@ // ignore_for_file: lines_longer_than_80_chars import 'package:file_picker/src/file_picker_web.dart'; -import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:shared_preferences_web/shared_preferences_web.dart'; import 'package:url_launcher_web/url_launcher_web.dart'; import 'package:video_player_web/video_player_web.dart'; import 'package:wakelock_web/wakelock_web.dart'; +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; + // ignore: public_member_api_docs void registerPlugins(Registrar registrar) { FilePickerWeb.registerWith(registrar); diff --git a/lib/helpers/database/database_contract.dart b/lib/helpers/database/database_contract.dart index b41823c..1d95e0c 100644 --- a/lib/helpers/database/database_contract.dart +++ b/lib/helpers/database/database_contract.dart @@ -13,18 +13,6 @@ abstract class BaseTableContract { static const C_ID = "id"; } -/// User table contract -abstract class UserTableContract { - static const TABLE_NAME = "users"; - static const C_ID = BaseTableContract.C_ID; - static const C_FIRST_NAME = "first_name"; - static const C_LAST_NAME = "last_name"; - static const C_VISIBILITY = "visibility"; - static const C_VIRTUAL_DIRECTORY = "virtual_directory"; - static const C_ACCOUNT_IMAGE_URL = "account_image_url"; - static const C_CUSTOM_EMOJIES = "custom_emojies"; -} - /// Friends table contract abstract class FriendsListTableContract { static const TABLE_NAME = "friends"; diff --git a/lib/helpers/database/database_helper.dart b/lib/helpers/database/database_helper.dart index 8048bad..7d1675b 100644 --- a/lib/helpers/database/database_helper.dart +++ b/lib/helpers/database/database_helper.dart @@ -1,5 +1,4 @@ import 'package:comunic/helpers/database/database_contract.dart'; -import 'package:connectivity/connectivity.dart'; import 'package:path/path.dart'; import 'package:sqflite/sqflite.dart'; @@ -30,21 +29,11 @@ abstract class DatabaseHelper { return _db; } - /// Cleanup database - static Future cleanUpDatabase() async { - // If connected to a network, cleanup user information - if (await Connectivity().checkConnectivity() != ConnectivityResult.none) - await _db.execute("DELETE FROM ${UserTableContract.TABLE_NAME}"); - } - /// Perform database update /// /// Currently : delete all the database tables and initialize it again static Future _performDatabaseUpdate( Database db, int oldVersion, int newVersion) async { - // Drop users table - await db.execute("DROP TABLE IF EXISTS ${UserTableContract.TABLE_NAME}"); - // Drop friends list table await db .execute("DROP TABLE IF EXISTS ${FriendsListTableContract.TABLE_NAME}"); @@ -55,17 +44,6 @@ abstract class DatabaseHelper { /// Initialize the database static Future _initializeDatabase(Database db, int version) async { - // Create users table - await db.execute("CREATE TABLE ${UserTableContract.TABLE_NAME} (" - "${UserTableContract.C_ID} INTEGER PRIMARY KEY, " - "${UserTableContract.C_FIRST_NAME} TEXT, " - "${UserTableContract.C_LAST_NAME} TEXT, " - "${UserTableContract.C_VISIBILITY} TEXT, " - "${UserTableContract.C_VIRTUAL_DIRECTORY} TEXT, " - "${UserTableContract.C_ACCOUNT_IMAGE_URL} TEXT, " - "${UserTableContract.C_CUSTOM_EMOJIES} TEXT" - ")"); - // Friends list table await db.execute("CREATE TABLE ${FriendsListTableContract.TABLE_NAME} (" "${FriendsListTableContract.C_ID} INTEGER PRIMARY KEY, " diff --git a/lib/helpers/database/users_database_helper.dart b/lib/helpers/database/users_database_helper.dart deleted file mode 100644 index 8b2e413..0000000 --- a/lib/helpers/database/users_database_helper.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:comunic/helpers/database/model_database_helper.dart'; -import 'package:comunic/models/user.dart'; - -import 'database_contract.dart'; - -/// User database helper -/// -/// @author Pierre HUBERT - -class UsersDatabaseHelper extends ModelDatabaseHelper { - - - @override - String tableName() { - return UserTableContract.TABLE_NAME; - } - - @override - User initializeFromMap(Map map) { - return User.fromMap(map); - } - - -} diff --git a/lib/helpers/serialization/base_serialization_helper.dart b/lib/helpers/serialization/base_serialization_helper.dart index 01ef5ad..cc29648 100644 --- a/lib/helpers/serialization/base_serialization_helper.dart +++ b/lib/helpers/serialization/base_serialization_helper.dart @@ -102,6 +102,8 @@ abstract class BaseSerializationHelper { return _cache.any((element) => isContained(element)); } + Future has(T el) => any((t) => t == el); + /// Check if any entry in the last match the predicate Future first(bool filter(T t)) async { await _loadCache(); @@ -120,10 +122,26 @@ abstract class BaseSerializationHelper { await _saveCache(); } + /// Insert or replace many elements + Future insertOrReplaceElements(List list) async { + await _loadCache(); + + _cache.removeWhere((element) => list.any((newEl) => element == newEl)); + _cache.addAll(list); + + await _saveCache(); + } + /// Remove elements Future removeElement(bool isToRemove(T t)) async { await _loadCache(); _cache.removeWhere((element) => isToRemove(element)); await _saveCache(); } + + /// Remove all elements + Future removeAll() async { + _cache = []; + await _saveCache(); + } } diff --git a/lib/helpers/serialization/user_list_serialization_helper.dart b/lib/helpers/serialization/user_list_serialization_helper.dart new file mode 100644 index 0000000..fa385c3 --- /dev/null +++ b/lib/helpers/serialization/user_list_serialization_helper.dart @@ -0,0 +1,28 @@ +import 'package:comunic/helpers/serialization/base_serialization_helper.dart'; +import 'package:comunic/models/user.dart'; + +/// User serialization helper +/// +/// @author Pierre Hubert + +UsersListSerialisationHelper _singleton; + +class UsersListSerialisationHelper extends BaseSerializationHelper { + UsersListSerialisationHelper._(); + + factory UsersListSerialisationHelper() { + if (_singleton == null) _singleton = UsersListSerialisationHelper._(); + + return _singleton; + } + + @override + String get type => "users-list"; + + @override + User parse(Map m) => User.fromJson(m); + + /// Remove a user by its ID + Future removeUserByID(int userID) => + removeElement((t) => t.id == userID); +} diff --git a/lib/helpers/users_helper.dart b/lib/helpers/users_helper.dart index 0e555c0..7a1553c 100644 --- a/lib/helpers/users_helper.dart +++ b/lib/helpers/users_helper.dart @@ -1,5 +1,5 @@ import 'package:comunic/enums/user_page_visibility.dart'; -import 'package:comunic/helpers/database/users_database_helper.dart'; +import 'package:comunic/helpers/serialization/user_list_serialization_helper.dart'; import 'package:comunic/lists/custom_emojies_list.dart'; import 'package:comunic/lists/users_list.dart'; import 'package:comunic/models/advanced_user_info.dart'; @@ -27,7 +27,6 @@ class GetUserAdvancedUserError extends Error { } class UsersHelper { - final UsersDatabaseHelper _usersDatabaseHelper = UsersDatabaseHelper(); /// Download information about some given users ID /// @@ -64,7 +63,7 @@ class UsersHelper { ); // Save the list - _usersDatabaseHelper.insertOrUpdateAll(list); + await UsersListSerialisationHelper().insertOrReplaceElements(list); return list; } @@ -114,8 +113,8 @@ class UsersHelper { // Check cache for (int userID in users) { - if (!forceDownload && await _usersDatabaseHelper.has(userID)) - list.add(await _usersDatabaseHelper.get(userID)); + if (!forceDownload && await UsersListSerialisationHelper().any((u) => u.id == userID)) + list.add(await UsersListSerialisationHelper().first((u) => u.id == userID)); else toDownload.add(userID); } diff --git a/lib/main.dart b/lib/main.dart index 69ade1a..1f325db 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,12 @@ import 'package:comunic/helpers/account_helper.dart'; import 'package:comunic/helpers/database/database_helper.dart'; import 'package:comunic/helpers/preferences_helper.dart'; +import 'package:comunic/helpers/serialization/user_list_serialization_helper.dart'; import 'package:comunic/helpers/version_helper.dart'; import 'package:comunic/ui/widgets/init_widget.dart'; import 'package:comunic/utils/flutter_utils.dart'; import 'package:comunic/utils/intl_utils.dart'; +import 'package:connectivity/connectivity.dart'; import 'package:flutter/material.dart'; /// Main file of the application @@ -18,9 +20,11 @@ void subMain() async { await VersionHelper.ensureLoaded(); // Connect to database - if(!isWeb) { + if (!isWeb) { await DatabaseHelper.open(); - await DatabaseHelper.cleanUpDatabase(); + + if (await Connectivity().checkConnectivity() != ConnectivityResult.none) + await UsersListSerialisationHelper().removeAll(); } // Get current system language diff --git a/lib/models/user.dart b/lib/models/user.dart index 1a496e9..d72f974 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -1,9 +1,8 @@ import 'dart:convert'; import 'package:comunic/enums/user_page_visibility.dart'; -import 'package:comunic/helpers/database/database_contract.dart'; +import 'package:comunic/helpers/serialization/base_serialization_helper.dart'; import 'package:comunic/lists/custom_emojies_list.dart'; -import 'package:comunic/models/cache_model.dart'; import 'package:comunic/utils/ui_utils.dart'; import 'package:meta/meta.dart'; @@ -11,7 +10,8 @@ import 'package:meta/meta.dart'; /// /// @author Pierre HUBERT -class User extends CacheModel { +class User implements SerializableElement { + final int id; final String firstName; final String lastName; final UserPageVisibility pageVisibility; @@ -20,7 +20,7 @@ class User extends CacheModel { final CustomEmojiesList customEmojies; const User({ - @required int id, + @required this.id, @required this.firstName, @required this.lastName, @required this.pageVisibility, @@ -28,12 +28,12 @@ class User extends CacheModel { @required this.accountImageURL, @required this.customEmojies, }) : assert(id != null), + assert(id > 0), assert(firstName != null), assert(lastName != null), assert(pageVisibility != null), assert(accountImageURL != null), - assert(customEmojies != null), - super(id: id); + assert(customEmojies != null); /// Get user full name String get fullName => firstName + " " + lastName; @@ -44,27 +44,27 @@ class User extends CacheModel { bool get hasVirtualDirectory => virtualDirectory != null && virtualDirectory.length > 0; - Map toMap() { - return { - UserTableContract.C_ID: id, - UserTableContract.C_FIRST_NAME: firstName, - UserTableContract.C_LAST_NAME: lastName, - UserTableContract.C_VISIBILITY: pageVisibility.toString(), - UserTableContract.C_VIRTUAL_DIRECTORY: virtualDirectory, - UserTableContract.C_ACCOUNT_IMAGE_URL: accountImageURL, - UserTableContract.C_CUSTOM_EMOJIES: - jsonEncode(customEmojies.toSerializableList()), - }; - } + Map toJson() => { + "id": id, + "firstName": firstName, + "lastName": lastName, + "pageVisibility": pageVisibility.toString(), + "virtualDirectory": virtualDirectory, + "accountImageURL": accountImageURL, + "customEmojies": customEmojies.toSerializableList() + }; - User.fromMap(Map map) - : this.firstName = map[UserTableContract.C_FIRST_NAME], - this.lastName = map[UserTableContract.C_LAST_NAME], - this.pageVisibility = - userPageVisibilityFromString(map[UserTableContract.C_VISIBILITY]), - this.virtualDirectory = map[UserTableContract.C_VIRTUAL_DIRECTORY], - this.accountImageURL = map[UserTableContract.C_ACCOUNT_IMAGE_URL], + User.fromJson(Map map) + : this.id = map["id"], + this.firstName = map["firstName"], + this.lastName = map["lastName"], + this.pageVisibility = UserPageVisibility.values.firstWhere( + (element) => element.toString() == map["pageVisibility"]), + this.virtualDirectory = map["virtualDirectory"], + this.accountImageURL = map["accountImageURL"], this.customEmojies = CustomEmojiesList.fromSerializedList( - jsonDecode(map[UserTableContract.C_CUSTOM_EMOJIES])), - super.fromMap(map); + jsonDecode(map["customEmojies"])); + + @override + int compareTo(User other) => id.compareTo(other.id); } diff --git a/lib/ui/routes/settings/account_image_settings.dart b/lib/ui/routes/settings/account_image_settings.dart index 9572c83..53cccab 100644 --- a/lib/ui/routes/settings/account_image_settings.dart +++ b/lib/ui/routes/settings/account_image_settings.dart @@ -1,4 +1,4 @@ -import 'package:comunic/helpers/database/users_database_helper.dart'; +import 'package:comunic/helpers/serialization/user_list_serialization_helper.dart'; import 'package:comunic/helpers/settings_helper.dart'; import 'package:comunic/models/account_image_settings.dart'; import 'package:comunic/ui/dialogs/multi_choices_dialog.dart'; @@ -38,7 +38,7 @@ class _AccountImageSettingsScreenState @override void dispose() { // Remove current user information to force refresh of account image - UsersDatabaseHelper().delete(userID()); + UsersListSerialisationHelper().removeUserByID(userID()); super.dispose(); } diff --git a/lib/ui/routes/settings/general_account_settings.dart b/lib/ui/routes/settings/general_account_settings.dart index 486371a..6f23fd3 100644 --- a/lib/ui/routes/settings/general_account_settings.dart +++ b/lib/ui/routes/settings/general_account_settings.dart @@ -1,5 +1,5 @@ import 'package:comunic/enums/user_page_visibility.dart'; -import 'package:comunic/helpers/database/users_database_helper.dart'; +import 'package:comunic/helpers/serialization/user_list_serialization_helper.dart'; import 'package:comunic/helpers/settings_helper.dart'; import 'package:comunic/models/general_settings.dart'; import 'package:comunic/ui/dialogs/multi_choices_dialog.dart'; @@ -34,7 +34,7 @@ class _GeneralAccountSettingsScreenState @override void dispose() { // Remove current user information to force refresh of account image - UsersDatabaseHelper().delete(userID()); + UsersListSerialisationHelper().removeUserByID(userID()); super.dispose(); }