From 32044b596fa06812d863742fe03b2c639892d6ce Mon Sep 17 00:00:00 2001 From: AhsanAli13503 Date: Thu, 16 May 2024 16:50:10 +0500 Subject: [PATCH] feat: floor database for events storage --- evently/lib/models/events.dart | 38 ++-- evently/lib/repository/repository.dart | 3 +- .../event_hub/event_hub_view_model.dart | 9 +- .../third_party_services/database.dart | 12 + .../third_party_services/database.g.dart | 205 ++++++++++++++++++ .../third_party_services/event_dao.dart | 17 ++ evently/lib/utils/di/di.dart | 2 + evently/pubspec.lock | 34 ++- evently/pubspec.yaml | 3 +- 9 files changed, 299 insertions(+), 24 deletions(-) create mode 100644 evently/lib/services/third_party_services/database.dart create mode 100644 evently/lib/services/third_party_services/database.g.dart create mode 100644 evently/lib/services/third_party_services/event_dao.dart diff --git a/evently/lib/models/events.dart b/evently/lib/models/events.dart index 579384d132..de4ffa4b5b 100644 --- a/evently/lib/models/events.dart +++ b/evently/lib/models/events.dart @@ -1,10 +1,31 @@ import 'package:equatable/equatable.dart'; +import 'package:floor/floor.dart'; import 'package:pylons_sdk/low_level.dart'; import 'package:fixnum/fixnum.dart'; enum FreeDrop { yes, no, unselected } +@entity class Events extends Equatable { + @primaryKey + final int? id; + + final String eventName; + final String hostName; + final String thumbnail; + final String startDate; + final String endDate; + final String startTime; + final String endTime; + final String location; + final String description; + final String numberOfTickets; + final String price; + final String listOfPerks; + final String isFreeDrops; + final String cookbookID; + final String recipeID; + const Events({ ///* overview data this.eventName = '', @@ -30,24 +51,9 @@ class Events extends Equatable { ///* other this.cookbookID = '', this.recipeID = '', + this.id, }); - final String eventName; - final String hostName; - final String thumbnail; - final String startDate; - final String endDate; - final String startTime; - final String endTime; - final String location; - final String description; - final String numberOfTickets; - final String price; - final String listOfPerks; - final String isFreeDrops; - final String cookbookID; - final String recipeID; - factory Events.fromRecipe(Recipe recipe) { Map map = _extractAttributeValues(recipe.entries.itemOutputs[0].strings); return Events( diff --git a/evently/lib/repository/repository.dart b/evently/lib/repository/repository.dart index 31bced463f..e265ad0cf1 100644 --- a/evently/lib/repository/repository.dart +++ b/evently/lib/repository/repository.dart @@ -141,8 +141,7 @@ class RepositoryImp implements Repository { final response = await localDataSource.getEvents(); return Right(response); - } on Exception catch (exception) { - crashlyticsHelper.recordFatalError(error: exception.toString()); + } on Exception catch (_) { return Left(CacheFailure(LocaleKeys.something_wrong.tr())); } } diff --git a/evently/lib/screens/event_hub/event_hub_view_model.dart b/evently/lib/screens/event_hub/event_hub_view_model.dart index 20d17b712b..627b48aa34 100644 --- a/evently/lib/screens/event_hub/event_hub_view_model.dart +++ b/evently/lib/screens/event_hub/event_hub_view_model.dart @@ -3,6 +3,7 @@ import 'package:evently/generated/locale_keys.g.dart'; import 'package:evently/models/events.dart'; import 'package:evently/repository/repository.dart'; import 'package:evently/utils/extension_util.dart'; +import 'package:evently/widgets/loading_with_progress.dart'; import 'package:flutter/cupertino.dart'; import 'package:injectable/injectable.dart'; import 'package:pylons_sdk/pylons_sdk.dart'; @@ -94,17 +95,17 @@ class EventHubViewModel extends ChangeNotifier { } Future getDraftsList() async { - // final loading = Loading()..showLoading(message: LocaleKeys.loading.tr()); + final loading = LoadingProgress()..showLoadingWithProgress(message: LocaleKeys.loading.tr()); - final getNftResponse = await repository.getEvents(); + final getEventResponse = await repository.getEvents(); - if (getNftResponse.isLeft()) { + if (getEventResponse.isLeft()) { loading.dismiss(); LocaleKeys.something_wrong.tr().show(); return; } - nftDraftList = getNftResponse.getOrElse(() => []); + // nftDraftList = getNftResponse.getOrElse(() => []); loading.dismiss(); diff --git a/evently/lib/services/third_party_services/database.dart b/evently/lib/services/third_party_services/database.dart new file mode 100644 index 0000000000..cda3365232 --- /dev/null +++ b/evently/lib/services/third_party_services/database.dart @@ -0,0 +1,12 @@ +import 'dart:async'; +import 'package:evently/models/events.dart'; +import 'package:evently/services/third_party_services/event_dao.dart'; +import 'package:floor/floor.dart'; +import 'package:sqflite/sqflite.dart' as sqflite; + +part 'database.g.dart'; + +@Database(version: 6, entities: [Events]) +abstract class AppDatabase extends FloorDatabase { + EventsDao get eventsDao; +} diff --git a/evently/lib/services/third_party_services/database.g.dart b/evently/lib/services/third_party_services/database.g.dart new file mode 100644 index 0000000000..e00269f83d --- /dev/null +++ b/evently/lib/services/third_party_services/database.g.dart @@ -0,0 +1,205 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'database.dart'; + +// ************************************************************************** +// FloorGenerator +// ************************************************************************** + +abstract class $AppDatabaseBuilderContract { + /// Adds migrations to the builder. + $AppDatabaseBuilderContract addMigrations(List migrations); + + /// Adds a database [Callback] to the builder. + $AppDatabaseBuilderContract addCallback(Callback callback); + + /// Creates the database and initializes it. + Future build(); +} + +// ignore: avoid_classes_with_only_static_members +class $FloorAppDatabase { + /// Creates a database builder for a persistent database. + /// Once a database is built, you should keep a reference to it and re-use it. + static $AppDatabaseBuilderContract databaseBuilder(String name) => + _$AppDatabaseBuilder(name); + + /// Creates a database builder for an in memory database. + /// Information stored in an in memory database disappears when the process is killed. + /// Once a database is built, you should keep a reference to it and re-use it. + static $AppDatabaseBuilderContract inMemoryDatabaseBuilder() => + _$AppDatabaseBuilder(null); +} + +class _$AppDatabaseBuilder implements $AppDatabaseBuilderContract { + _$AppDatabaseBuilder(this.name); + + final String? name; + + final List _migrations = []; + + Callback? _callback; + + @override + $AppDatabaseBuilderContract addMigrations(List migrations) { + _migrations.addAll(migrations); + return this; + } + + @override + $AppDatabaseBuilderContract addCallback(Callback callback) { + _callback = callback; + return this; + } + + @override + Future build() async { + final path = name != null + ? await sqfliteDatabaseFactory.getDatabasePath(name!) + : ':memory:'; + final database = _$AppDatabase(); + database.database = await database.open( + path, + _migrations, + _callback, + ); + return database; + } +} + +class _$AppDatabase extends AppDatabase { + _$AppDatabase([StreamController? listener]) { + changeListener = listener ?? StreamController.broadcast(); + } + + EventsDao? _eventsDaoInstance; + + Future open( + String path, + List migrations, [ + Callback? callback, + ]) async { + final databaseOptions = sqflite.OpenDatabaseOptions( + version: 6, + onConfigure: (database) async { + await database.execute('PRAGMA foreign_keys = ON'); + await callback?.onConfigure?.call(database); + }, + onOpen: (database) async { + await callback?.onOpen?.call(database); + }, + onUpgrade: (database, startVersion, endVersion) async { + await MigrationAdapter.runMigrations( + database, startVersion, endVersion, migrations); + + await callback?.onUpgrade?.call(database, startVersion, endVersion); + }, + onCreate: (database, version) async { + await database.execute( + 'CREATE TABLE IF NOT EXISTS `Events` (`id` INTEGER, `eventName` TEXT NOT NULL, `hostName` TEXT NOT NULL, `thumbnail` TEXT NOT NULL, `startDate` TEXT NOT NULL, `endDate` TEXT NOT NULL, `startTime` TEXT NOT NULL, `endTime` TEXT NOT NULL, `location` TEXT NOT NULL, `description` TEXT NOT NULL, `numberOfTickets` TEXT NOT NULL, `price` TEXT NOT NULL, `listOfPerks` TEXT NOT NULL, `isFreeDrops` TEXT NOT NULL, `cookbookID` TEXT NOT NULL, `recipeID` TEXT NOT NULL, PRIMARY KEY (`id`))'); + + await callback?.onCreate?.call(database, version); + }, + ); + return sqfliteDatabaseFactory.openDatabase(path, options: databaseOptions); + } + + @override + EventsDao get eventsDao { + return _eventsDaoInstance ??= _$EventsDao(database, changeListener); + } +} + +class _$EventsDao extends EventsDao { + _$EventsDao( + this.database, + this.changeListener, + ) : _queryAdapter = QueryAdapter(database), + _eventsInsertionAdapter = InsertionAdapter( + database, + 'Events', + (Events item) => { + 'id': item.id, + 'eventName': item.eventName, + 'hostName': item.hostName, + 'thumbnail': item.thumbnail, + 'startDate': item.startDate, + 'endDate': item.endDate, + 'startTime': item.startTime, + 'endTime': item.endTime, + 'location': item.location, + 'description': item.description, + 'numberOfTickets': item.numberOfTickets, + 'price': item.price, + 'listOfPerks': item.listOfPerks, + 'isFreeDrops': item.isFreeDrops, + 'cookbookID': item.cookbookID, + 'recipeID': item.recipeID + }); + + final sqflite.DatabaseExecutor database; + + final StreamController changeListener; + + final QueryAdapter _queryAdapter; + + final InsertionAdapter _eventsInsertionAdapter; + + @override + Future> findAllEvents() async { + return _queryAdapter.queryList( + 'SELECT * FROM events ORDER BY dateTime DESC', + mapper: (Map row) => Events( + eventName: row['eventName'] as String, + hostName: row['hostName'] as String, + thumbnail: row['thumbnail'] as String, + startDate: row['startDate'] as String, + endDate: row['endDate'] as String, + startTime: row['startTime'] as String, + endTime: row['endTime'] as String, + location: row['location'] as String, + description: row['description'] as String, + listOfPerks: row['listOfPerks'] as String, + numberOfTickets: row['numberOfTickets'] as String, + price: row['price'] as String, + isFreeDrops: row['isFreeDrops'] as String, + cookbookID: row['cookbookID'] as String, + recipeID: row['recipeID'] as String, + id: row['id'] as int?)); + } + + @override + Future findEventsById(int id) async { + return _queryAdapter.query('SELECT * FROM events WHERE id = ?1', + mapper: (Map row) => Events( + eventName: row['eventName'] as String, + hostName: row['hostName'] as String, + thumbnail: row['thumbnail'] as String, + startDate: row['startDate'] as String, + endDate: row['endDate'] as String, + startTime: row['startTime'] as String, + endTime: row['endTime'] as String, + location: row['location'] as String, + description: row['description'] as String, + listOfPerks: row['listOfPerks'] as String, + numberOfTickets: row['numberOfTickets'] as String, + price: row['price'] as String, + isFreeDrops: row['isFreeDrops'] as String, + cookbookID: row['cookbookID'] as String, + recipeID: row['recipeID'] as String, + id: row['id'] as int?), + arguments: [id]); + } + + @override + Future delete(int id) async { + await _queryAdapter + .queryNoReturn('DELETE FROM events WHERE id = ?1', arguments: [id]); + } + + @override + Future insertEvents(Events events) { + return _eventsInsertionAdapter.insertAndReturnId( + events, OnConflictStrategy.abort); + } +} diff --git a/evently/lib/services/third_party_services/event_dao.dart b/evently/lib/services/third_party_services/event_dao.dart new file mode 100644 index 0000000000..93e6f60b68 --- /dev/null +++ b/evently/lib/services/third_party_services/event_dao.dart @@ -0,0 +1,17 @@ +import 'package:evently/models/events.dart'; +import 'package:floor/floor.dart'; + +@dao +abstract class EventsDao { + @Query('SELECT * FROM events ORDER BY dateTime DESC') + Future> findAllEvents(); + + @Query('SELECT * FROM events WHERE id = :id') + Future findEventsById(int id); + + @insert + Future insertEvents(Events events); + + @Query('DELETE FROM events WHERE id = :id') + Future delete(int id); +} diff --git a/evently/lib/utils/di/di.dart b/evently/lib/utils/di/di.dart index 62d8189d3a..7e4d6d57fa 100644 --- a/evently/lib/utils/di/di.dart +++ b/evently/lib/utils/di/di.dart @@ -1,6 +1,7 @@ // coverage: false // coverage:ignore-file +import 'package:evently/services/third_party_services/database.dart'; import 'package:evently/utils/di/di.config.dart'; import 'package:get_it/get_it.dart'; import 'package:injectable/injectable.dart'; @@ -13,5 +14,6 @@ final sl = GetIt.I; @InjectableInit() void configureDependencies() { sl.registerSingletonAsync(() => SharedPreferences.getInstance()); + sl.registerSingletonAsync(() => $FloorAppDatabase.databaseBuilder('app_database.db').build()); sl.init(); } diff --git a/evently/pubspec.lock b/evently/pubspec.lock index 7dd01b7323..3e54b6d1c0 100644 --- a/evently/pubspec.lock +++ b/evently/pubspec.lock @@ -74,7 +74,7 @@ packages: source: hosted version: "2.4.2" build_runner: - dependency: "direct main" + dependency: "direct dev" description: name: build_runner sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" @@ -345,6 +345,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" + floor_generator: + dependency: "direct dev" + description: + name: floor_generator + sha256: "1499b3ab878a807e6fbe6f140dc014124845cd1df3090a113aae5fa7577a1e77" + url: "https://pub.dev" + source: hosted + version: "1.5.0" flutter: dependency: "direct main" description: flutter @@ -581,6 +589,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + lists: + dependency: transitive + description: + name: lists + sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" + url: "https://pub.dev" + source: hosted + version: "1.0.1" logging: dependency: transitive description: @@ -1041,6 +1057,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + strings: + dependency: transitive + description: + name: strings + sha256: b33f40c4dd3e597bf6d9e7f4f4dc282dad0f19b07d9f320cb5c2183859cbccf5 + url: "https://pub.dev" + source: hosted + version: "3.1.1" synchronized: dependency: transitive description: @@ -1105,6 +1129,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.0" + unicode: + dependency: transitive + description: + name: unicode + sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" + url: "https://pub.dev" + source: hosted + version: "0.3.1" url_launcher: dependency: transitive description: diff --git a/evently/pubspec.yaml b/evently/pubspec.yaml index a5f78805eb..763477446b 100644 --- a/evently/pubspec.yaml +++ b/evently/pubspec.yaml @@ -43,7 +43,6 @@ dependencies: flutter_svg_provider: ^1.0.3 get_it: ^7.7.0 injectable_generator: ^2.6.1 - build_runner: ^2.4.9 injectable: ^2.4.1 provider: ^6.1.2 steps_indicator: ^1.3.0 @@ -63,6 +62,8 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + floor_generator: ^1.4.2 + build_runner: ^2.4.9 # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is