-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add support for multiple profiles.
Also basically rewrote everything and moved to riverpod.
- Loading branch information
Showing
44 changed files
with
1,340 additions
and
493 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ on: | |
workflow_dispatch: | ||
|
||
env: | ||
FLUTTER_VERSION: "3.27.1" | ||
FLUTTER_VERSION: "3.27.3" | ||
|
||
jobs: | ||
deploy-pages: | ||
|
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 was deleted.
Oops, something went wrong.
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 |
---|---|---|
@@ -1,37 +1,57 @@ | ||
import 'package:btox/btox_state.dart'; | ||
import 'package:btox/contact_list_page.dart'; | ||
import 'package:btox/db/database.dart'; | ||
import 'package:btox/pages/contact_list_page.dart'; | ||
import 'package:btox/pages/create_profile_page.dart'; | ||
import 'package:btox/pages/select_profile_page.dart'; | ||
import 'package:btox/providers/database.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_redux/flutter_redux.dart'; | ||
import 'package:redux/redux.dart'; | ||
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||
import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||
|
||
final class BtoxApp extends StatelessWidget { | ||
final Database database; | ||
final Store<BtoxState> store; | ||
|
||
const BtoxApp({ | ||
super.key, | ||
required this.database, | ||
required this.store, | ||
}); | ||
final class BtoxApp extends ConsumerWidget { | ||
const BtoxApp({super.key}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return StoreProvider<BtoxState>( | ||
store: store, | ||
child: MaterialApp( | ||
title: 'bTox', | ||
localizationsDelegates: AppLocalizations.localizationsDelegates, | ||
supportedLocales: AppLocalizations.supportedLocales, | ||
theme: ThemeData( | ||
brightness: Brightness.dark, | ||
primarySwatch: Colors.blue, | ||
), | ||
home: ContactListPage( | ||
database: database, | ||
), | ||
Widget build(BuildContext context, WidgetRef ref) { | ||
return MaterialApp( | ||
title: 'bTox', | ||
localizationsDelegates: AppLocalizations.localizationsDelegates, | ||
supportedLocales: AppLocalizations.supportedLocales, | ||
theme: ThemeData( | ||
brightness: Brightness.dark, | ||
primarySwatch: Colors.blue, | ||
), | ||
home: ref.watch(databaseProvider).when( | ||
loading: () => const Scaffold( | ||
body: Center( | ||
child: CircularProgressIndicator(), | ||
), | ||
), | ||
error: (error, _) => Scaffold( | ||
body: Center( | ||
child: Text('Error: $error'), | ||
), | ||
), | ||
data: (db) => StreamBuilder<List<Profile>>( | ||
stream: db.watchProfiles(), | ||
builder: (context, snapshot) { | ||
final profiles = snapshot.data ?? const []; | ||
if (profiles.isEmpty) { | ||
return const CreateProfilePage(); | ||
} | ||
|
||
final activeProfiles = | ||
profiles.where((profile) => profile.active).toList(); | ||
if (activeProfiles.isEmpty) { | ||
return SelectProfilePage(profiles: profiles); | ||
} | ||
|
||
return ContactListPage( | ||
database: db, | ||
profile: activeProfiles.first, | ||
); | ||
}, | ||
), | ||
), | ||
); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
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 |
---|---|---|
@@ -1,39 +1,97 @@ | ||
import 'package:btox/models/id.dart'; | ||
import 'package:btox/models/persistence.dart'; | ||
import 'package:btox/models/profile_settings.dart'; | ||
import 'package:drift/drift.dart'; | ||
|
||
part 'database.g.dart'; | ||
|
||
class Contacts extends Table { | ||
IntColumn get id => integer().autoIncrement()(); | ||
TextColumn get publicKey => text()(); | ||
TextColumn get name => text().nullable()(); | ||
} | ||
export 'package:drift/drift.dart' show Value; | ||
|
||
class Messages extends Table { | ||
IntColumn get contactId => integer().references(Contacts, #id)(); | ||
TextColumn get content => text()(); | ||
DateTimeColumn get timestamp => dateTime()(); | ||
} | ||
part 'database.g.dart'; | ||
|
||
@DriftDatabase(tables: [Contacts, Messages]) | ||
@DriftDatabase(tables: [ | ||
Contacts, | ||
Messages, | ||
Profiles, | ||
]) | ||
final class Database extends _$Database { | ||
Database(super.e); | ||
|
||
@override | ||
int get schemaVersion => 2; | ||
|
||
// TODO(robinlinden): Remove before first real release. | ||
@override | ||
MigrationStrategy get migration => destructiveFallback; | ||
|
||
void addContact(ContactsCompanion entry) => into(contacts).insert(entry); | ||
@override | ||
int get schemaVersion => 1; | ||
|
||
Future<void> activateProfile(Id<Profiles> id) async { | ||
await deactivateProfiles(); | ||
|
||
await (update(profiles)..where((p) => p.id.equals(id.value))) | ||
.write(ProfilesCompanion( | ||
active: Value(true), | ||
)); | ||
} | ||
|
||
Future<void> deactivateProfiles() async { | ||
await update(profiles).write(ProfilesCompanion( | ||
active: Value(false), | ||
)); | ||
} | ||
|
||
Future<void> deleteProfile(Id<Profiles> id) async { | ||
transaction(() async { | ||
// Find all the contacts for the profile. | ||
final contactsForProfile = await (select(contacts) | ||
..where((c) => c.profileId.equals(id.value))) | ||
.get(); | ||
// Delete all their messages. | ||
batch((batch) { | ||
for (final contact in contactsForProfile) { | ||
batch.deleteWhere( | ||
messages, | ||
(m) => m.contactId.equals(contact.id.value), | ||
); | ||
} | ||
}); | ||
// Then delete the contacts. | ||
await (delete(contacts)..where((c) => c.profileId.equals(id.value))).go(); | ||
// Finally delete the profile. | ||
await (delete(profiles)..where((p) => p.id.equals(id.value))).go(); | ||
}); | ||
} | ||
|
||
Future<Id<Contacts>> addContact(ContactsCompanion entry) async => | ||
Id(await into(contacts).insert(entry)); | ||
|
||
Future<Id<Messages>> addMessage(MessagesCompanion entry) async => | ||
Id(await into(messages).insert(entry)); | ||
|
||
Future<Id<Profiles>> addProfile(ProfilesCompanion entry) async => | ||
Id(await into(profiles).insert(entry)); | ||
|
||
Future<void> updateProfileSettings( | ||
Id<Profiles> id, ProfileSettings settings) async { | ||
await (update(profiles)..where((p) => p.id.equals(id.value))).write( | ||
ProfilesCompanion( | ||
settings: Value(settings), | ||
), | ||
); | ||
} | ||
|
||
Stream<Contact> watchContact(Id<Contacts> id) => | ||
(select(contacts)..where((c) => c.id.equals(id.value))).watchSingle(); | ||
|
||
Stream<List<Contact>> watchContacts() => select(contacts).watch(); | ||
Stream<List<Contact>> watchContactsFor(Id<Profiles> id) => (select(contacts) | ||
..where((c) => c.profileId.equals(id.value)) | ||
..orderBy([ | ||
(c) => OrderingTerm(expression: c.name), | ||
])) | ||
.watch(); | ||
|
||
Stream<Contact> watchContact(int id) => | ||
(select(contacts)..where((c) => c.id.equals(id))).watchSingle(); | ||
Stream<List<Message>> watchMessagesFor(Id<Contacts> id) => | ||
(select(messages)..where((m) => m.contactId.equals(id.value))).watch(); | ||
|
||
void addMessage(MessagesCompanion entry) => into(messages).insert(entry); | ||
Stream<Profile> watchProfile(Id<Profiles> id) => | ||
(select(profiles)..where((p) => p.id.equals(id.value))).watchSingle(); | ||
|
||
Stream<List<Message>> watchMessagesFor(int id) => | ||
(select(messages)..where((m) => m.contactId.equals(id))).watch(); | ||
Stream<List<Profile>> watchProfiles() => select(profiles).watch(); | ||
} |
Oops, something went wrong.