-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* #260 update servers: - use sqflite as cache database - store all item actions in cache - use virtual markers to distinct between saved and intermediate state - images are stored on device data instead of stream to reduce mem_usage - auto-discover when add + delete are done in cache (removes item from cache and never stores it) - apply door to use cache - apply flyer to use cache * 530: let refresh button rotate while flushing
- Loading branch information
Showing
60 changed files
with
2,011 additions
and
316 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import 'package:gruene_app/features/campaigns/helper/campaign_action.dart'; | ||
import 'package:path/path.dart'; | ||
import 'package:sqflite/sqflite.dart'; | ||
|
||
class CampaignActionDatabase { | ||
static final CampaignActionDatabase instance = CampaignActionDatabase._internal(); | ||
|
||
static Database? _database; | ||
|
||
CampaignActionDatabase._internal(); | ||
|
||
Future<Database> get database async { | ||
return _database ??= await _initDatabase(); | ||
} | ||
|
||
Future<Database> _initDatabase() async { | ||
final databasePath = await getDatabasesPath(); | ||
final path = join(databasePath, 'campaign_action_db.db'); | ||
return await openDatabase( | ||
path, | ||
version: 1, | ||
onCreate: _createDatabase, | ||
); | ||
} | ||
|
||
Future<void> _createDatabase(Database db, _) async { | ||
return await db.execute(''' | ||
CREATE TABLE ${CampaignActionFields.tableName} ( | ||
${CampaignActionFields.id} ${CampaignActionFields.idType}, | ||
${CampaignActionFields.poiId} ${CampaignActionFields.intTypeNullable}, | ||
${CampaignActionFields.poiTempId} ${CampaignActionFields.intType}, | ||
${CampaignActionFields.actionType} ${CampaignActionFields.intType}, | ||
${CampaignActionFields.serialized} ${CampaignActionFields.textTypeNullable} | ||
) | ||
'''); | ||
} | ||
|
||
Future<CampaignAction> create(CampaignAction campaignAction) async { | ||
final db = await instance.database; | ||
final id = await db.insert(CampaignActionFields.tableName, campaignAction.toMap()); | ||
return campaignAction.copyWith(id: id); | ||
} | ||
|
||
Future<List<CampaignAction>> readAll() async { | ||
final db = await instance.database; | ||
const orderBy = '${CampaignActionFields.poiTempId} ASC, ${CampaignActionFields.id} ASC'; | ||
final result = await db.query(CampaignActionFields.tableName, orderBy: orderBy); | ||
return result.map((json) => CampaignAction.fromMap(json)).toList(); | ||
} | ||
|
||
Future<List<CampaignAction>> readAllByActionType(List<int> posterActions) async { | ||
final db = await instance.database; | ||
const orderBy = '${CampaignActionFields.poiTempId} ASC, ${CampaignActionFields.id} ASC'; | ||
final result = await db.query( | ||
CampaignActionFields.tableName, | ||
orderBy: orderBy, | ||
where: '${CampaignActionFields.actionType} IN (${List.filled(posterActions.length, '?').join(',')})', | ||
whereArgs: posterActions, | ||
); | ||
return result.map((json) => CampaignAction.fromMap(json)).toList(); | ||
} | ||
|
||
Future<List<CampaignAction>> getActionsWithPoiId(String poiId) async { | ||
final db = await instance.database; | ||
const orderBy = '${CampaignActionFields.poiTempId} ASC, ${CampaignActionFields.id} ASC'; | ||
final result = await db.query( | ||
CampaignActionFields.tableName, | ||
orderBy: orderBy, | ||
where: '${CampaignActionFields.poiId} = ? OR ${CampaignActionFields.poiTempId} = ?', | ||
whereArgs: [poiId, poiId], | ||
); | ||
return result.map((json) => CampaignAction.fromMap(json)).toList(); | ||
} | ||
|
||
Future<void> update(CampaignAction campaignAction) async { | ||
final db = await instance.database; | ||
db.update( | ||
CampaignActionFields.tableName, | ||
campaignAction.toMap(), | ||
where: '${CampaignActionFields.id} = ?', | ||
whereArgs: [campaignAction.id], | ||
); | ||
} | ||
|
||
Future<void> updatePoiId(int oldId, int newId) async { | ||
final db = await instance.database; | ||
await db.update( | ||
CampaignActionFields.tableName, | ||
{CampaignActionFields.poiId: newId}, | ||
where: '${CampaignActionFields.poiId} = ?', | ||
whereArgs: [oldId], | ||
); | ||
} | ||
|
||
Future<int> delete(int id) async { | ||
final db = await instance.database; | ||
return await db.delete( | ||
CampaignActionFields.tableName, | ||
where: '${CampaignActionFields.id} = ?', | ||
whereArgs: [id], | ||
); | ||
} | ||
|
||
Future<void> close() async { | ||
final db = await instance.database; | ||
db.close(); | ||
} | ||
|
||
Future<int> getCount() async { | ||
final db = await instance.database; | ||
int count = Sqflite.firstIntValue(await db.rawQuery('SELECT COUNT(*) FROM ${CampaignActionFields.tableName}')) ?? 0; | ||
return count; | ||
} | ||
|
||
Future<bool> actionsWithPoiIdExists(String poiId) async { | ||
final db = await instance.database; | ||
final result = await db.query( | ||
CampaignActionFields.tableName, | ||
columns: ['COUNT(*)'], | ||
where: '${CampaignActionFields.poiId} = ? OR ${CampaignActionFields.poiTempId} = ?', | ||
whereArgs: [poiId, poiId], | ||
); | ||
return (Sqflite.firstIntValue(result) ?? 0) > 0; | ||
} | ||
} | ||
|
||
class CampaignActionFields { | ||
static const String tableName = 'campaign_action'; | ||
static const String idType = 'INTEGER PRIMARY KEY AUTOINCREMENT'; | ||
static const String textTypeNullable = 'TEXT'; | ||
static const String intType = 'INTEGER NOT NULL'; | ||
static const String intTypeNullable = 'INTEGER'; | ||
static const String id = '_id'; | ||
static const String poiId = 'poiId'; | ||
static const String poiTempId = 'poiTempId'; | ||
static const String actionType = 'actionType'; | ||
static const String serialized = 'serialized'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
part of '../converters.dart'; | ||
|
||
extension CampaignActionParsing on CampaignAction { | ||
PosterCreateModel getAsPosterCreate() { | ||
var data = jsonDecode(serialized!) as Map<String, dynamic>; | ||
var model = PosterCreateModel.fromJson(data.convertLatLongField()); | ||
return model; | ||
} | ||
|
||
PosterUpdateModel getAsPosterUpdate() { | ||
var data = jsonDecode(serialized!) as Map<String, dynamic>; | ||
var model = PosterUpdateModel.fromJson(data.updateIdField(poiId!).convertLatLongField()); | ||
|
||
return model; | ||
} | ||
|
||
DoorCreateModel getAsDoorCreate() { | ||
var data = jsonDecode(serialized!) as Map<String, dynamic>; | ||
var model = DoorCreateModel.fromJson(data.convertLatLongField()); | ||
|
||
return model; | ||
} | ||
|
||
DoorUpdateModel getAsDoorUpdate() { | ||
var data = jsonDecode(serialized!) as Map<String, dynamic>; | ||
var model = DoorUpdateModel.fromJson(data.updateIdField(poiId!).convertLatLongField()); | ||
|
||
return model; | ||
} | ||
|
||
FlyerCreateModel getAsFlyerCreate() { | ||
var data = jsonDecode(serialized!) as Map<String, dynamic>; | ||
var model = FlyerCreateModel.fromJson(data.convertLatLongField()); | ||
|
||
return model; | ||
} | ||
|
||
FlyerUpdateModel getAsFlyerUpdate() { | ||
var data = jsonDecode(serialized!) as Map<String, dynamic>; | ||
var model = FlyerUpdateModel.fromJson(data.updateIdField(poiId!).convertLatLongField()); | ||
|
||
return model; | ||
} | ||
|
||
PosterListItemModel getPosterUpdateAsPosterListItem(DateTime originalCreatedAt) { | ||
var updateModel = getAsPosterUpdate().transformToPosterDetailModel(); | ||
return PosterListItemModel( | ||
id: updateModel.id, | ||
thumbnailUrl: updateModel.thumbnailUrl, | ||
imageUrl: updateModel.imageUrl, | ||
address: updateModel.address, | ||
status: updateModel.status.translatePosterStatus(), | ||
lastChangeStatus: t.campaigns.poster.updated, | ||
lastChangeDateTime: '${DateTime.fromMillisecondsSinceEpoch(poiTempId).getAsLocalDateTimeString()}*', | ||
createdAt: originalCreatedAt, | ||
isCached: true, | ||
); | ||
} | ||
|
||
PosterListItemModel getPosterCreateAsPosterListItem() { | ||
var createModel = getAsPosterCreate().transformToPosterDetailModel(poiTempId.toString()); | ||
return PosterListItemModel( | ||
id: createModel.id, | ||
thumbnailUrl: createModel.thumbnailUrl, | ||
imageUrl: createModel.imageUrl, | ||
address: createModel.address, | ||
status: createModel.status.translatePosterStatus(), | ||
lastChangeStatus: t.campaigns.poster.updated, | ||
lastChangeDateTime: '${DateTime.fromMillisecondsSinceEpoch(poiTempId).getAsLocalDateTimeString()}*', | ||
createdAt: DateTime.fromMillisecondsSinceEpoch(poiTempId), | ||
isCached: true, | ||
); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
lib/app/services/converters/door_create_model_parsing.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
part of '../converters.dart'; | ||
|
||
extension DoorCreateModelParsing on DoorCreateModel { | ||
DoorDetailModel transformToDoorDetailModel(String temporaryId) { | ||
return DoorDetailModel( | ||
id: temporaryId, | ||
address: address, | ||
closedDoors: closedDoors, | ||
openedDoors: openedDoors, | ||
location: location, | ||
createdAt: '${DateTime.now().getAsLocalDateTimeString()}*', // should mark this as preliminary | ||
isCached: true, | ||
); | ||
} | ||
|
||
MarkerItemModel transformToVirtualMarkerItem(int temporaryId) { | ||
return MarkerItemModel.virtual( | ||
id: temporaryId, | ||
status: PoiServiceType.door.name, | ||
location: location, | ||
); | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
lib/app/services/converters/door_update_model_parsing.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
part of '../converters.dart'; | ||
|
||
extension DoorUpdateModelParsing on DoorUpdateModel { | ||
DoorDetailModel transformToDoorDetailModel() { | ||
var newDoorDetail = oldDoorDetail.copyWith( | ||
address: address, | ||
closedDoors: closedDoors, | ||
openedDoors: openedDoors, | ||
isCached: true, | ||
); | ||
return newDoorDetail; | ||
} | ||
|
||
MarkerItemModel transformToVirtualMarkerItem() { | ||
return MarkerItemModel.virtual( | ||
id: int.parse(id), | ||
status: PoiServiceType.door.name, | ||
location: location, | ||
); | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
lib/app/services/converters/flyer_create_model_parsing.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
part of '../converters.dart'; | ||
|
||
extension FlyerCreateModelParsing on FlyerCreateModel { | ||
FlyerDetailModel transformToFlyerDetailModel(String temporaryId) { | ||
return FlyerDetailModel( | ||
id: temporaryId, | ||
address: address, | ||
flyerCount: flyerCount, | ||
location: location, | ||
createdAt: '${DateTime.now().getAsLocalDateTimeString()}*', // should mark this as preliminary | ||
isCached: true, | ||
); | ||
} | ||
|
||
MarkerItemModel transformToVirtualMarkerItem(int temporaryId) { | ||
return MarkerItemModel.virtual( | ||
id: temporaryId, | ||
status: PoiServiceType.flyer.name, | ||
location: location, | ||
); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
lib/app/services/converters/flyer_update_model_parsing.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
part of '../converters.dart'; | ||
|
||
extension FlyerUpdateModelParsing on FlyerUpdateModel { | ||
FlyerDetailModel transformToFlyerDetailModel() { | ||
var newFlyerDetail = oldFlyerDetail.copyWith( | ||
address: address, | ||
flyerCount: flyerCount, | ||
isCached: true, | ||
); | ||
return newFlyerDetail; | ||
} | ||
|
||
MarkerItemModel transformToVirtualMarkerItem() { | ||
return MarkerItemModel.virtual( | ||
id: int.parse(id), | ||
status: PoiServiceType.flyer.name, | ||
location: location, | ||
); | ||
} | ||
} |
Oops, something went wrong.