diff --git a/lib/enums/user_page_visibility.dart b/lib/enums/user_page_visibility.dart index 832951c..ca2361b 100644 --- a/lib/enums/user_page_visibility.dart +++ b/lib/enums/user_page_visibility.dart @@ -3,3 +3,12 @@ /// @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/helpers/database/database_contract.dart b/lib/helpers/database/database_contract.dart new file mode 100644 index 0000000..a408826 --- /dev/null +++ b/lib/helpers/database/database_contract.dart @@ -0,0 +1,20 @@ +/// Database contract +/// +/// @author Pierre HUBERT + +/// Main information +class DatabaseContract { + static const DATABASE_VERSION = 1; + static const DATABASE_FILE_NAME = "database.sqlite"; +} + +/// User table contract +abstract class UserTableContract { + static const TABLE_NAME = "users"; + static const C_ID = "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"; +} \ No newline at end of file diff --git a/lib/helpers/database/database_helper.dart b/lib/helpers/database/database_helper.dart new file mode 100644 index 0000000..14c7ac5 --- /dev/null +++ b/lib/helpers/database/database_helper.dart @@ -0,0 +1,53 @@ +import 'package:comunic/helpers/database/database_contract.dart'; +import 'package:path/path.dart'; +import 'package:sqflite/sqflite.dart'; + +/// Database Helper +/// +/// Manage the connection to the local SQLite database +/// +/// @author Pierre HUBERT + +abstract class DatabaseHelper { + static Database _db; + + /// Open the database + static Future open() async { + if (_db != null && _db.isOpen) return; + + var databasePath = await getDatabasesPath(); + _db = await openDatabase( + join(databasePath, DatabaseContract.DATABASE_FILE_NAME), + version: DatabaseContract.DATABASE_VERSION, + onUpgrade: _performDatabaseUpdate, + onCreate: _initializeDatabase); + } + + /// Get a database instance + static Future get() async { + await open(); + return _db; + } + + /// Perform database update + /// + /// Currently : delete all the database tables and initialize it again + static Future _performDatabaseUpdate( + Database db, int oldVersion, int newVersion) async { + //Initialize database again + await _initializeDatabase(db, newVersion); + } + + /// 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" + ")"); + } +} diff --git a/lib/helpers/database/users_database_helper.dart b/lib/helpers/database/users_database_helper.dart new file mode 100644 index 0000000..cff3a99 --- /dev/null +++ b/lib/helpers/database/users_database_helper.dart @@ -0,0 +1,62 @@ +import 'package:comunic/models/user.dart'; + +import 'database_contract.dart'; +import 'database_helper.dart'; + +/// User database helper +/// +/// @author Pierre HUBERT + +class UsersDatabaseHelper { + /// Insert a user in the database + Future _insertDB(User user) async { + await (await DatabaseHelper.get()) + .insert(UserTableContract.TABLE_NAME, user.toMap()); + } + + /// Update a user in the database + Future _updateDB(User user) async { + await (await DatabaseHelper.get()).update( + UserTableContract.TABLE_NAME, + user.toMap(), + where: "${UserTableContract.C_ID} = ?", + whereArgs: [user.id], + ); + } + + /// Get a user from the database with a specified [id] + /// + /// Returns null if none found + Future get(int id) async { + List maps = await (await DatabaseHelper.get()).query( + UserTableContract.TABLE_NAME, + where: '${UserTableContract.C_ID} = ?', + whereArgs: [id], + ); + + if (maps.length > 0) return User.fromMap(maps[0]); + + return null; + } + + /// Check out whether a user information specified with its [id] is present + /// or not in the local database + Future has(int id) async { + return (await get(id)) != null; + } + + /// Insert or update information about a user (depends of the presence + /// of previous user information in the database + Future insertOrUpdate(User user) async { + if (await has(user.id)) + await _updateDB(user); + else + await _insertDB(user); + } + + /// Insert or update an important amount of user information + Future insertOrUpdateAll(List list) async { + for(int i = 0; i < list.length; i++) + await insertOrUpdate(list[i]); + } +} diff --git a/lib/helpers/users_helper.dart b/lib/helpers/users_helper.dart index e4ebf3c..27ed978 100644 --- a/lib/helpers/users_helper.dart +++ b/lib/helpers/users_helper.dart @@ -1,4 +1,5 @@ import 'package:comunic/enums/user_page_visibility.dart'; +import 'package:comunic/helpers/database/users_database_helper.dart'; import 'package:comunic/lists/users_list.dart'; import 'package:comunic/models/api_request.dart'; import 'package:comunic/models/user.dart'; @@ -10,6 +11,9 @@ import 'package:comunic/models/user.dart'; /// @author Pierre HUBERT class UsersHelper { + + final UsersDatabaseHelper _usersDatabaseHelper = UsersDatabaseHelper(); + /// Download information about some given users ID /// /// Return the list of users information in case of success, null in case of @@ -42,6 +46,9 @@ class UsersHelper { ), ); + // Save the list + _usersDatabaseHelper.insertOrUpdateAll(list); + return list; } } diff --git a/lib/main.dart b/lib/main.dart index a37e685..fe13af6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:comunic/helpers/account_helper.dart'; +import 'package:comunic/helpers/database/database_helper.dart'; import 'package:comunic/models/config.dart'; import 'package:comunic/ui/routes/home_route.dart'; import 'package:comunic/ui/routes/login_route.dart'; @@ -20,6 +21,9 @@ void main() { serviceName: "ComunicFlutter", serviceToken: "G9sZCBmb3IgVWJ1bnR1CkNvbW1lbnRbbmVdPeCkieCkrOCkq")); + // Connect to database + DatabaseHelper.open(); + runApp(ComunicApplication()); } diff --git a/lib/models/user.dart b/lib/models/user.dart index a397d49..318d81d 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -1,4 +1,5 @@ import 'package:comunic/enums/user_page_visibility.dart'; +import 'package:comunic/helpers/database/database_contract.dart'; import 'package:meta/meta.dart'; /// Single user information @@ -28,4 +29,24 @@ class User { /// Get user full name String get fullName => firstName + " " + lastName; + + 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, + }; + } + + User.fromMap(Map map) + : this.id = map[UserTableContract.C_ID], + 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]; } diff --git a/pubspec.lock b/pubspec.lock index 5cc348c..2a87485 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -100,6 +100,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.5.4" + sqflite: + dependency: "direct main" + description: + name: sqflite + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.5" stack_trace: dependency: transitive description: @@ -121,6 +128,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.4" + synchronized: + dependency: transitive + description: + name: synchronized + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" term_glyph: dependency: transitive description: @@ -151,4 +165,4 @@ packages: version: "2.0.8" sdks: dart: ">=2.1.0 <3.0.0" - flutter: ">=0.1.4 <2.0.0" + flutter: ">=1.2.1 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 76cc0d4..d97dd06 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,6 +27,9 @@ dependencies: # Preferences are useful for a lot of things (ex: login tokens) shared_preferences: ^0.5.2 + # SQLite database is used for caching + sqflite: ^1.1.5 + dev_dependencies: flutter_test: sdk: flutter