diff --git a/lib/data/local/item.dart b/lib/data/local/item.dart index 2c4058f..13bd1ee 100644 --- a/lib/data/local/item.dart +++ b/lib/data/local/item.dart @@ -13,7 +13,7 @@ class LocalItemFields { static const values = [ localId, remoteId, - project, + projectId, title, emitter, amount, @@ -24,7 +24,7 @@ class LocalItemFields { static const String localId = 'local_id'; static const String remoteId = 'remote_id'; - static const String project = 'project'; + static const String projectId = 'project'; static const String title = 'title'; static const String emitter = 'emitter'; static const String amount = 'amount'; @@ -70,7 +70,7 @@ class LocalItem extends LocalGeneric { Map toJson() => { LocalItemFields.localId: item.localId, LocalItemFields.remoteId: item.remoteId, - LocalItemFields.project: item.project.localId, + LocalItemFields.projectId: item.project.localId, LocalItemFields.title: item.title, LocalItemFields.emitter: item.emitter.localId, LocalItemFields.amount: item.amount, @@ -84,7 +84,7 @@ class LocalItem extends LocalGeneric { if (project != null) { p = project; } else { - p = Project.fromId(json[LocalItemFields.project] as int)!; + p = Project.fromId(json[LocalItemFields.projectId] as int)!; } return Item( diff --git a/lib/data/local/project.dart b/lib/data/local/project.dart index fd5b403..efc5859 100644 --- a/lib/data/local/project.dart +++ b/lib/data/local/project.dart @@ -14,7 +14,7 @@ import 'participant.dart'; const String tableProjects = 'projects'; -class ProjectFields { +class LocalProjectFields { static const values = [ localId, remoteId, @@ -46,7 +46,7 @@ class LocalProject extends LocalGeneric { static Future> getAllProjects() async { final res = await AppData.db.query( tableProjects, - columns: ProjectFields.values, + columns: LocalProjectFields.values, ); return res.map((e) => fromJson(e)).toSet(); } @@ -76,7 +76,7 @@ class LocalProject extends LocalGeneric { final rawItems = await AppData.db.query( tableItems, where: - '${LocalItemFields.project} = ? AND (${LocalItemFields.deleted} == 0 OR ${LocalItemFields.lastUpdate} > ?)', + '${LocalItemFields.projectId} = ? AND (${LocalItemFields.deleted} == 0 OR ${LocalItemFields.lastUpdate} > ?)', whereArgs: [project.localId, project.lastSync.millisecondsSinceEpoch], orderBy: '${LocalItemFields.date} DESC', ); @@ -127,33 +127,53 @@ class LocalProject extends LocalGeneric { Map toJson() { return { - ProjectFields.localId: project.localId, - ProjectFields.remoteId: project.remoteId, - ProjectFields.name: project.name, - ProjectFields.code: project.code ?? getRandom(5), - ProjectFields.currentParticipant: project.currentParticipant?.localId, - ProjectFields.instance: project.provider.instance.localId, - ProjectFields.lastSync: project.lastSync.millisecondsSinceEpoch, - ProjectFields.lastUpdate: project.lastUpdate.millisecondsSinceEpoch, - ProjectFields.deleted: project.deleted ? 1 : 0, + LocalProjectFields.localId: project.localId, + LocalProjectFields.remoteId: project.remoteId, + LocalProjectFields.name: project.name, + LocalProjectFields.code: project.code ?? getRandom(5), + LocalProjectFields.currentParticipant: + project.currentParticipant?.localId, + LocalProjectFields.instance: project.provider.instance.localId, + LocalProjectFields.lastSync: project.lastSync.millisecondsSinceEpoch, + LocalProjectFields.lastUpdate: project.lastUpdate.millisecondsSinceEpoch, + LocalProjectFields.deleted: project.deleted ? 1 : 0, }; } static Project fromJson(Map json) { return Project( - localId: json[ProjectFields.localId] as int?, - remoteId: json[ProjectFields.remoteId] as String?, - name: json[ProjectFields.name] as String, - code: json[ProjectFields.code] as String?, - currentParticipantId: json[ProjectFields.currentParticipant] as int?, - instance: Instance.fromId(json[ProjectFields.instance] as int)!, + localId: json[LocalProjectFields.localId] as int?, + remoteId: json[LocalProjectFields.remoteId] as String?, + name: json[LocalProjectFields.name] as String, + code: json[LocalProjectFields.code] as String?, + currentParticipantId: json[LocalProjectFields.currentParticipant] as int?, + instance: Instance.fromId(json[LocalProjectFields.instance] as int) ?? + Instance.fromName('local')!, lastSync: DateTime.fromMillisecondsSinceEpoch( - json[ProjectFields.lastSync] as int), + json[LocalProjectFields.lastSync] as int), lastUpdate: DateTime.fromMillisecondsSinceEpoch( - json[ProjectFields.lastUpdate] + json[LocalProjectFields.lastUpdate] as int //? ?? DateTime.now().millisecondsSinceEpoch ), - deleted: (json[ProjectFields.deleted] as int) == 1, + deleted: (json[LocalProjectFields.deleted] as int) == 1, ); } + + Future delete() async { + int a = await AppData.db.delete(tableProjects, + where: '${LocalProjectFields.localId} = ?', + whereArgs: [project.localId]); + a += await AppData.db.delete(tableParticipants, + where: '${LocalParticipantFields.projectId} = ?', + whereArgs: [project.localId]); + a += await AppData.db.delete(tableItems, + where: '${LocalItemFields.projectId} = ?', + whereArgs: [project.localId]); + // await AppData.db.query(tableItemParts, where: '${LocalItemPartFields.itemId} = ?', whereArgs: [project.localId]); + a += await AppData.db.delete(tableGroup, + where: '${LocalGroupFields.projectId} = ?', + whereArgs: [project.localId]); + // await AppData.db.query(tableGroupMembership, where: '${LocalGroupMembershipFields.groupId} = ?', whereArgs: [project.localId]); + return a > 0; + } } diff --git a/lib/models/instance.dart b/lib/models/instance.dart index f6bbcd5..1ccb5fa 100644 --- a/lib/models/instance.dart +++ b/lib/models/instance.dart @@ -18,8 +18,12 @@ class Instance { late LocalInstance conn; static Instance? fromId(int localId) { - return AppData.instances - .firstWhere((element) => element.localId == localId); + try { + return AppData.instances + .firstWhere((element) => element.localId == localId); + } catch (e) { + return null; + } } static Instance? fromName(String s) { diff --git a/lib/models/project.dart b/lib/models/project.dart index 1bad342..d90834d 100644 --- a/lib/models/project.dart +++ b/lib/models/project.dart @@ -170,4 +170,14 @@ class Project extends Data { return null; } } + + void clear() { + currentParticipant = null; + participants.clear(); + items.clear(); + name = ''; + groups.clear(); + lastSync = DateTime(1970); + notSyncCount = 0; + } } diff --git a/lib/screens/new_project/new_project.dart b/lib/screens/new_project/new_project.dart index d74b288..3ca9d29 100644 --- a/lib/screens/new_project/new_project.dart +++ b/lib/screens/new_project/new_project.dart @@ -69,7 +69,13 @@ class NewProjectScreen extends StatelessWidget { } if (first) { AppData.firstRun = false; - runApp(const MainScreen()); + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute( + builder: (context) => const MainScreen(), + ), + (Route route) => false, + ); } else { if (context.mounted) { if (isNew) { diff --git a/lib/screens/project/project_page.dart b/lib/screens/project/project_page.dart index f46ff8d..84d2fa0 100644 --- a/lib/screens/project/project_page.dart +++ b/lib/screens/project/project_page.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:splitr/data/local/project.dart'; import 'package:splitr/utils/ext/list.dart'; +import 'package:splitr/utils/helper/confirm_box.dart'; import '../../models/project.dart'; import '../new_project/new_project.dart'; @@ -28,28 +30,37 @@ class _ProjectPageState extends State { appBar: AppBar( centerTitle: true, elevation: 4, - title: Column( - children: [ - Text( - widget.project.name, - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, + title: Padding( + padding: const EdgeInsets.only(left: 40), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(left: 10, right: 10), + child: FittedBox( + fit: BoxFit.scaleDown, + child: Text( + widget.project.name, + style: const TextStyle( + fontSize: 26, + fontWeight: FontWeight.bold, + ), + ), + ), ), - ), - Text( - widget.project.participants.enabled().length <= 4 - ? widget.project.participants - .enabled() - .map((e) => e.pseudo) - .join(', ') - : '${widget.project.participants.enabled().length} participants', - style: const TextStyle( - fontSize: 14, - fontStyle: FontStyle.italic, + Text( + widget.project.participants.enabled().length <= 4 + ? widget.project.participants + .enabled() + .map((e) => e.pseudo) + .join(', ') + : '${widget.project.participants.enabled().length} participants', + style: const TextStyle( + fontSize: 14, + fontStyle: FontStyle.italic, + ), ), - ), - ], + ], + ), ), actions: [ actionMenu(), @@ -130,6 +141,18 @@ class _ProjectPageState extends State { ); setState(() {}); break; + case 4: + await confirmBox( + context: context, + title: 'Are you sure you want to recreate this project ?', + content: 'You will NOT be able to undi this action!', + onValidate: () async { + await (widget.project.conn as LocalProject).delete(); + widget.project.clear(); + await widget.project.provider.sync(); + if (mounted) setState(() {}); + }); + break; case 3: if (Navigator.canPop(context)) { Navigator.pop(context); diff --git a/lib/services/database.dart b/lib/services/database.dart index 9725f73..72642ae 100644 --- a/lib/services/database.dart +++ b/lib/services/database.dart @@ -41,15 +41,15 @@ class SplitrDatabase { Future _createDB(Database db, int version) async { await db.execute(''' CREATE TABLE $tableProjects ( - ${ProjectFields.localId} INTEGER PRIMARY KEY AUTOINCREMENT, - ${ProjectFields.remoteId} TEXT, - ${ProjectFields.name} TEXT NOT NULL, - ${ProjectFields.code} TEXT NOT NULL, - ${ProjectFields.currentParticipant} INTEGER, - ${ProjectFields.instance} INTEGER NOT NULL, - ${ProjectFields.lastSync} INTEGER, - ${ProjectFields.lastUpdate} INTEGER, - ${ProjectFields.deleted} INTEGER NOT NULL + ${LocalProjectFields.localId} INTEGER PRIMARY KEY AUTOINCREMENT, + ${LocalProjectFields.remoteId} TEXT, + ${LocalProjectFields.name} TEXT NOT NULL, + ${LocalProjectFields.code} TEXT NOT NULL, + ${LocalProjectFields.currentParticipant} INTEGER, + ${LocalProjectFields.instance} INTEGER NOT NULL, + ${LocalProjectFields.lastSync} INTEGER, + ${LocalProjectFields.lastUpdate} INTEGER, + ${LocalProjectFields.deleted} INTEGER NOT NULL ) '''); @@ -70,7 +70,7 @@ CREATE TABLE $tableParticipants ( CREATE TABLE $tableItems ( ${LocalItemFields.localId} INTEGER PRIMARY KEY AUTOINCREMENT, ${LocalItemFields.remoteId} TEXT, - ${LocalItemFields.project} INTEGER NOT NULL, + ${LocalItemFields.projectId} INTEGER NOT NULL, ${LocalItemFields.title} TEXT NOT NULL, ${LocalItemFields.emitter} INTEGER NOT NULL, ${LocalItemFields.amount} REAL NOT NULL, diff --git a/lib/widgets/new_screen.dart b/lib/widgets/new_screen.dart index 30f53dd..7c79181 100644 --- a/lib/widgets/new_screen.dart +++ b/lib/widgets/new_screen.dart @@ -48,7 +48,12 @@ class NewScreen extends StatelessWidget { width: double.infinity, child: ElevatedButton( onPressed: onValidate == null - ? null + ? () async => + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Please check your entries'), + ), + ) : () async => await onValidate!(context, formKey), child: Padding( padding: const EdgeInsets.all(15.0), diff --git a/pubspec.yaml b/pubspec.yaml index c6c77f6..806744b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: splitr is a free and open-source app that lets you create multiple publish_to: 'none' -version: 0.4.3 +version: 0.4.4 environment: sdk: '>=2.18.6 <3.0.0'