Persist theme
Persist theme in sqlite database. A new table was created for this. Add migration to add table for persisted theme
This commit is contained in:
parent
66d7d27a81
commit
a52a50d4d1
@ -8,17 +8,23 @@ import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart';
|
|||||||
|
|
||||||
part 'database.g.dart';
|
part 'database.g.dart';
|
||||||
|
|
||||||
class NoteTable extends Table {
|
var database = AppDatabase(); //global, since we should only use one instance
|
||||||
|
|
||||||
|
class PersistentNote extends Table {
|
||||||
TextColumn get id => text()();
|
TextColumn get id => text()();
|
||||||
TextColumn get content => text()();
|
TextColumn get content => text()();
|
||||||
}
|
}
|
||||||
|
|
||||||
@DriftDatabase(tables: [NoteTable])
|
class PersistentTheme extends Table {
|
||||||
|
TextColumn get brightness => text().withDefault(const Constant("dark"))();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DriftDatabase(tables: [PersistentNote, PersistentTheme])
|
||||||
class AppDatabase extends _$AppDatabase {
|
class AppDatabase extends _$AppDatabase {
|
||||||
AppDatabase() : super(_openConnection());
|
AppDatabase() : super(_openConnection());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 1;
|
int get schemaVersion => 2;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MigrationStrategy get migration {
|
MigrationStrategy get migration {
|
||||||
@ -27,30 +33,26 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
await m.createAll();
|
await m.createAll();
|
||||||
},
|
},
|
||||||
onUpgrade: (Migrator m, int from, int to) async {
|
onUpgrade: (Migrator m, int from, int to) async {
|
||||||
if (from < 2) {}
|
if (from < 2) {
|
||||||
|
await m.renameTable(persistentNote, "note_table");
|
||||||
|
await m.createTable(persistentTheme);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyDatabase _openConnection() {
|
LazyDatabase _openConnection() {
|
||||||
// the LazyDatabase util lets us find the right location for the file async.
|
|
||||||
return LazyDatabase(() async {
|
return LazyDatabase(() async {
|
||||||
// put the database file, called db.sqlite here, into the documents folder
|
|
||||||
// for your app.
|
|
||||||
final dbFolder = await getApplicationDocumentsDirectory();
|
final dbFolder = await getApplicationDocumentsDirectory();
|
||||||
final file = File(p.join(dbFolder.path, 'db.sqlite'));
|
final file = File(p.join(dbFolder.path, 'db.sqlite'));
|
||||||
|
|
||||||
// Also work around limitations on old Android versions
|
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
await applyWorkaroundToOpenSqlite3OnOldAndroidVersions();
|
await applyWorkaroundToOpenSqlite3OnOldAndroidVersions();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sqlite3 pick a more suitable location for temporary files - the
|
|
||||||
// one from the system may be inaccessible due to sandboxing.
|
|
||||||
final cachebase = (await getTemporaryDirectory()).path;
|
final cachebase = (await getTemporaryDirectory()).path;
|
||||||
// We can't access /tmp on Android, which sqlite3 would try by default.
|
|
||||||
// Explicitly tell it about the correct temporary directory.
|
|
||||||
sqlite3.tempDirectory = cachebase;
|
sqlite3.tempDirectory = cachebase;
|
||||||
|
|
||||||
return NativeDatabase.createInBackground(file);
|
return NativeDatabase.createInBackground(file);
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
part of 'database.dart';
|
part of 'database.dart';
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
class $NoteTableTable extends NoteTable
|
class $PersistentNoteTable extends PersistentNote
|
||||||
with TableInfo<$NoteTableTable, NoteTableData> {
|
with TableInfo<$PersistentNoteTable, PersistentNoteData> {
|
||||||
@override
|
@override
|
||||||
final GeneratedDatabase attachedDatabase;
|
final GeneratedDatabase attachedDatabase;
|
||||||
final String? _alias;
|
final String? _alias;
|
||||||
$NoteTableTable(this.attachedDatabase, [this._alias]);
|
$PersistentNoteTable(this.attachedDatabase, [this._alias]);
|
||||||
static const VerificationMeta _idMeta = const VerificationMeta('id');
|
static const VerificationMeta _idMeta = const VerificationMeta('id');
|
||||||
@override
|
@override
|
||||||
late final GeneratedColumn<String> id = GeneratedColumn<String>(
|
late final GeneratedColumn<String> id = GeneratedColumn<String>(
|
||||||
@ -26,9 +26,9 @@ class $NoteTableTable extends NoteTable
|
|||||||
String get aliasedName => _alias ?? actualTableName;
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
@override
|
@override
|
||||||
String get actualTableName => $name;
|
String get actualTableName => $name;
|
||||||
static const String $name = 'note_table';
|
static const String $name = 'persistent_note';
|
||||||
@override
|
@override
|
||||||
VerificationContext validateIntegrity(Insertable<NoteTableData> instance,
|
VerificationContext validateIntegrity(Insertable<PersistentNoteData> instance,
|
||||||
{bool isInserting = false}) {
|
{bool isInserting = false}) {
|
||||||
final context = VerificationContext();
|
final context = VerificationContext();
|
||||||
final data = instance.toColumns(true);
|
final data = instance.toColumns(true);
|
||||||
@ -49,9 +49,9 @@ class $NoteTableTable extends NoteTable
|
|||||||
@override
|
@override
|
||||||
Set<GeneratedColumn> get $primaryKey => const {};
|
Set<GeneratedColumn> get $primaryKey => const {};
|
||||||
@override
|
@override
|
||||||
NoteTableData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
PersistentNoteData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||||
return NoteTableData(
|
return PersistentNoteData(
|
||||||
id: attachedDatabase.typeMapping
|
id: attachedDatabase.typeMapping
|
||||||
.read(DriftSqlType.string, data['${effectivePrefix}id'])!,
|
.read(DriftSqlType.string, data['${effectivePrefix}id'])!,
|
||||||
content: attachedDatabase.typeMapping
|
content: attachedDatabase.typeMapping
|
||||||
@ -60,15 +60,16 @@ class $NoteTableTable extends NoteTable
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
$NoteTableTable createAlias(String alias) {
|
$PersistentNoteTable createAlias(String alias) {
|
||||||
return $NoteTableTable(attachedDatabase, alias);
|
return $PersistentNoteTable(attachedDatabase, alias);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NoteTableData extends DataClass implements Insertable<NoteTableData> {
|
class PersistentNoteData extends DataClass
|
||||||
|
implements Insertable<PersistentNoteData> {
|
||||||
final String id;
|
final String id;
|
||||||
final String content;
|
final String content;
|
||||||
const NoteTableData({required this.id, required this.content});
|
const PersistentNoteData({required this.id, required this.content});
|
||||||
@override
|
@override
|
||||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||||
final map = <String, Expression>{};
|
final map = <String, Expression>{};
|
||||||
@ -77,17 +78,17 @@ class NoteTableData extends DataClass implements Insertable<NoteTableData> {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteTableCompanion toCompanion(bool nullToAbsent) {
|
PersistentNoteCompanion toCompanion(bool nullToAbsent) {
|
||||||
return NoteTableCompanion(
|
return PersistentNoteCompanion(
|
||||||
id: Value(id),
|
id: Value(id),
|
||||||
content: Value(content),
|
content: Value(content),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
factory NoteTableData.fromJson(Map<String, dynamic> json,
|
factory PersistentNoteData.fromJson(Map<String, dynamic> json,
|
||||||
{ValueSerializer? serializer}) {
|
{ValueSerializer? serializer}) {
|
||||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||||
return NoteTableData(
|
return PersistentNoteData(
|
||||||
id: serializer.fromJson<String>(json['id']),
|
id: serializer.fromJson<String>(json['id']),
|
||||||
content: serializer.fromJson<String>(json['content']),
|
content: serializer.fromJson<String>(json['content']),
|
||||||
);
|
);
|
||||||
@ -101,13 +102,14 @@ class NoteTableData extends DataClass implements Insertable<NoteTableData> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteTableData copyWith({String? id, String? content}) => NoteTableData(
|
PersistentNoteData copyWith({String? id, String? content}) =>
|
||||||
|
PersistentNoteData(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
content: content ?? this.content,
|
content: content ?? this.content,
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return (StringBuffer('NoteTableData(')
|
return (StringBuffer('PersistentNoteData(')
|
||||||
..write('id: $id, ')
|
..write('id: $id, ')
|
||||||
..write('content: $content')
|
..write('content: $content')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
@ -119,27 +121,27 @@ class NoteTableData extends DataClass implements Insertable<NoteTableData> {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
(other is NoteTableData &&
|
(other is PersistentNoteData &&
|
||||||
other.id == this.id &&
|
other.id == this.id &&
|
||||||
other.content == this.content);
|
other.content == this.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
class NoteTableCompanion extends UpdateCompanion<NoteTableData> {
|
class PersistentNoteCompanion extends UpdateCompanion<PersistentNoteData> {
|
||||||
final Value<String> id;
|
final Value<String> id;
|
||||||
final Value<String> content;
|
final Value<String> content;
|
||||||
final Value<int> rowid;
|
final Value<int> rowid;
|
||||||
const NoteTableCompanion({
|
const PersistentNoteCompanion({
|
||||||
this.id = const Value.absent(),
|
this.id = const Value.absent(),
|
||||||
this.content = const Value.absent(),
|
this.content = const Value.absent(),
|
||||||
this.rowid = const Value.absent(),
|
this.rowid = const Value.absent(),
|
||||||
});
|
});
|
||||||
NoteTableCompanion.insert({
|
PersistentNoteCompanion.insert({
|
||||||
required String id,
|
required String id,
|
||||||
required String content,
|
required String content,
|
||||||
this.rowid = const Value.absent(),
|
this.rowid = const Value.absent(),
|
||||||
}) : id = Value(id),
|
}) : id = Value(id),
|
||||||
content = Value(content);
|
content = Value(content);
|
||||||
static Insertable<NoteTableData> custom({
|
static Insertable<PersistentNoteData> custom({
|
||||||
Expression<String>? id,
|
Expression<String>? id,
|
||||||
Expression<String>? content,
|
Expression<String>? content,
|
||||||
Expression<int>? rowid,
|
Expression<int>? rowid,
|
||||||
@ -151,9 +153,9 @@ class NoteTableCompanion extends UpdateCompanion<NoteTableData> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteTableCompanion copyWith(
|
PersistentNoteCompanion copyWith(
|
||||||
{Value<String>? id, Value<String>? content, Value<int>? rowid}) {
|
{Value<String>? id, Value<String>? content, Value<int>? rowid}) {
|
||||||
return NoteTableCompanion(
|
return PersistentNoteCompanion(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
content: content ?? this.content,
|
content: content ?? this.content,
|
||||||
rowid: rowid ?? this.rowid,
|
rowid: rowid ?? this.rowid,
|
||||||
@ -177,7 +179,7 @@ class NoteTableCompanion extends UpdateCompanion<NoteTableData> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return (StringBuffer('NoteTableCompanion(')
|
return (StringBuffer('PersistentNoteCompanion(')
|
||||||
..write('id: $id, ')
|
..write('id: $id, ')
|
||||||
..write('content: $content, ')
|
..write('content: $content, ')
|
||||||
..write('rowid: $rowid')
|
..write('rowid: $rowid')
|
||||||
@ -186,12 +188,170 @@ class NoteTableCompanion extends UpdateCompanion<NoteTableData> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class $PersistentThemeTable extends PersistentTheme
|
||||||
|
with TableInfo<$PersistentThemeTable, PersistentThemeData> {
|
||||||
|
@override
|
||||||
|
final GeneratedDatabase attachedDatabase;
|
||||||
|
final String? _alias;
|
||||||
|
$PersistentThemeTable(this.attachedDatabase, [this._alias]);
|
||||||
|
static const VerificationMeta _brightnessMeta =
|
||||||
|
const VerificationMeta('brightness');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<String> brightness = GeneratedColumn<String>(
|
||||||
|
'brightness', aliasedName, false,
|
||||||
|
type: DriftSqlType.string,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultValue: const Constant("dark"));
|
||||||
|
@override
|
||||||
|
List<GeneratedColumn> get $columns => [brightness];
|
||||||
|
@override
|
||||||
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
|
@override
|
||||||
|
String get actualTableName => $name;
|
||||||
|
static const String $name = 'persistent_theme';
|
||||||
|
@override
|
||||||
|
VerificationContext validateIntegrity(
|
||||||
|
Insertable<PersistentThemeData> instance,
|
||||||
|
{bool isInserting = false}) {
|
||||||
|
final context = VerificationContext();
|
||||||
|
final data = instance.toColumns(true);
|
||||||
|
if (data.containsKey('brightness')) {
|
||||||
|
context.handle(
|
||||||
|
_brightnessMeta,
|
||||||
|
brightness.isAcceptableOrUnknown(
|
||||||
|
data['brightness']!, _brightnessMeta));
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<GeneratedColumn> get $primaryKey => const {};
|
||||||
|
@override
|
||||||
|
PersistentThemeData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||||
|
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||||
|
return PersistentThemeData(
|
||||||
|
brightness: attachedDatabase.typeMapping
|
||||||
|
.read(DriftSqlType.string, data['${effectivePrefix}brightness'])!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
$PersistentThemeTable createAlias(String alias) {
|
||||||
|
return $PersistentThemeTable(attachedDatabase, alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PersistentThemeData extends DataClass
|
||||||
|
implements Insertable<PersistentThemeData> {
|
||||||
|
final String brightness;
|
||||||
|
const PersistentThemeData({required this.brightness});
|
||||||
|
@override
|
||||||
|
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, Expression>{};
|
||||||
|
map['brightness'] = Variable<String>(brightness);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistentThemeCompanion toCompanion(bool nullToAbsent) {
|
||||||
|
return PersistentThemeCompanion(
|
||||||
|
brightness: Value(brightness),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
factory PersistentThemeData.fromJson(Map<String, dynamic> json,
|
||||||
|
{ValueSerializer? serializer}) {
|
||||||
|
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||||
|
return PersistentThemeData(
|
||||||
|
brightness: serializer.fromJson<String>(json['brightness']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||||
|
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||||
|
return <String, dynamic>{
|
||||||
|
'brightness': serializer.toJson<String>(brightness),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistentThemeData copyWith({String? brightness}) => PersistentThemeData(
|
||||||
|
brightness: brightness ?? this.brightness,
|
||||||
|
);
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('PersistentThemeData(')
|
||||||
|
..write('brightness: $brightness')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => brightness.hashCode;
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
(other is PersistentThemeData && other.brightness == this.brightness);
|
||||||
|
}
|
||||||
|
|
||||||
|
class PersistentThemeCompanion extends UpdateCompanion<PersistentThemeData> {
|
||||||
|
final Value<String> brightness;
|
||||||
|
final Value<int> rowid;
|
||||||
|
const PersistentThemeCompanion({
|
||||||
|
this.brightness = const Value.absent(),
|
||||||
|
this.rowid = const Value.absent(),
|
||||||
|
});
|
||||||
|
PersistentThemeCompanion.insert({
|
||||||
|
this.brightness = const Value.absent(),
|
||||||
|
this.rowid = const Value.absent(),
|
||||||
|
});
|
||||||
|
static Insertable<PersistentThemeData> custom({
|
||||||
|
Expression<String>? brightness,
|
||||||
|
Expression<int>? rowid,
|
||||||
|
}) {
|
||||||
|
return RawValuesInsertable({
|
||||||
|
if (brightness != null) 'brightness': brightness,
|
||||||
|
if (rowid != null) 'rowid': rowid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistentThemeCompanion copyWith(
|
||||||
|
{Value<String>? brightness, Value<int>? rowid}) {
|
||||||
|
return PersistentThemeCompanion(
|
||||||
|
brightness: brightness ?? this.brightness,
|
||||||
|
rowid: rowid ?? this.rowid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, Expression>{};
|
||||||
|
if (brightness.present) {
|
||||||
|
map['brightness'] = Variable<String>(brightness.value);
|
||||||
|
}
|
||||||
|
if (rowid.present) {
|
||||||
|
map['rowid'] = Variable<int>(rowid.value);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('PersistentThemeCompanion(')
|
||||||
|
..write('brightness: $brightness, ')
|
||||||
|
..write('rowid: $rowid')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class _$AppDatabase extends GeneratedDatabase {
|
abstract class _$AppDatabase extends GeneratedDatabase {
|
||||||
_$AppDatabase(QueryExecutor e) : super(e);
|
_$AppDatabase(QueryExecutor e) : super(e);
|
||||||
late final $NoteTableTable noteTable = $NoteTableTable(this);
|
late final $PersistentNoteTable persistentNote = $PersistentNoteTable(this);
|
||||||
|
late final $PersistentThemeTable persistentTheme =
|
||||||
|
$PersistentThemeTable(this);
|
||||||
@override
|
@override
|
||||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||||
@override
|
@override
|
||||||
List<DatabaseSchemaEntity> get allSchemaEntities => [noteTable];
|
List<DatabaseSchemaEntity> get allSchemaEntities =>
|
||||||
|
[persistentNote, persistentTheme];
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,31 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:fnotes/notes_app.dart';
|
import 'package:fnotes/notes_app.dart';
|
||||||
import 'package:fnotes/persistence_bloc.dart';
|
import 'package:fnotes/persisted_brightness.dart';
|
||||||
|
import 'package:fnotes/persistent_notes_bloc.dart';
|
||||||
import 'package:fnotes/theme_bloc.dart';
|
import 'package:fnotes/theme_bloc.dart';
|
||||||
|
|
||||||
void main() {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized(); //for drift
|
WidgetsFlutterBinding.ensureInitialized(); //for drift
|
||||||
runApp(const MainApp());
|
|
||||||
|
PersistedBrightness persistedBrightness =
|
||||||
|
await PersistedThemeBloc.getPersistedBrightness();
|
||||||
|
|
||||||
|
runApp(MainApp(brightness: persistedBrightness.toFlutterBrightness()));
|
||||||
}
|
}
|
||||||
|
|
||||||
class MainApp extends StatelessWidget {
|
class MainApp extends StatelessWidget {
|
||||||
const MainApp({super.key});
|
final Brightness brightness;
|
||||||
|
const MainApp({super.key, required this.brightness});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
BlocProvider(create: (context) => ThemeBloc()),
|
BlocProvider(create: (context) => PersistedThemeBloc(brightness)),
|
||||||
BlocProvider(create: (context) => PersistenceBloc())
|
BlocProvider(create: (context) => PersistentNotesBloc()),
|
||||||
],
|
],
|
||||||
child: BlocBuilder<ThemeBloc, ThemeState>(
|
child: BlocBuilder<PersistedThemeBloc, ThemeState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
theme: state.theme,
|
theme: state.theme,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:fnotes/note.dart';
|
import 'package:fnotes/note.dart';
|
||||||
import 'package:fnotes/persistence_bloc.dart';
|
import 'package:fnotes/persistent_notes_bloc.dart';
|
||||||
import 'package:fnotes/theme_bloc.dart';
|
import 'package:fnotes/theme_bloc.dart';
|
||||||
|
|
||||||
class NotesApp extends StatefulWidget {
|
class NotesApp extends StatefulWidget {
|
||||||
@ -18,7 +18,7 @@ class _NotesAppState extends State<NotesApp> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
context.read<PersistenceBloc>().add(LoadNotesEvent());
|
context.read<PersistentNotesBloc>().add(LoadNotesEvent());
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,29 +31,29 @@ class _NotesAppState extends State<NotesApp> {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.light_mode),
|
icon: const Icon(Icons.light_mode),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<ThemeBloc>().add(ThemeEvent());
|
context.read<PersistedThemeBloc>().add(ThemeChangedEvent());
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: BlocBuilder<ThemeBloc, ThemeState>(
|
body: BlocBuilder<PersistedThemeBloc, ThemeState>(
|
||||||
builder: (context, state) {
|
builder: (context, themeState) {
|
||||||
return BlocBuilder<PersistenceBloc, PersistenceState>(
|
return BlocBuilder<PersistentNotesBloc, PersistentNotesState>(
|
||||||
builder: (context, blocState) {
|
builder: (context, notesState) {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemCount: blocState.notes.length,
|
itemCount: notesState.notes.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return Dismissible(
|
return Dismissible(
|
||||||
onDismissed: (direction) {
|
onDismissed: (direction) {
|
||||||
context.read<PersistenceBloc>().add(NoteDismissed(
|
context.read<PersistentNotesBloc>().add(NoteDismissed(
|
||||||
Note.withId(
|
Note.withId(
|
||||||
id: blocState.notes[index].id,
|
id: notesState.notes[index].id,
|
||||||
content: blocState.notes[index].content)));
|
content: notesState.notes[index].content)));
|
||||||
},
|
},
|
||||||
key: ValueKey(blocState.notes[index]),
|
key: ValueKey(notesState.notes[index]),
|
||||||
child: Card(
|
child: Card(
|
||||||
elevation: 5,
|
elevation: 5,
|
||||||
color: state.theme.colorScheme.primaryContainer,
|
color: themeState.theme.colorScheme.primaryContainer,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 50,
|
height: 50,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@ -61,10 +61,10 @@ class _NotesAppState extends State<NotesApp> {
|
|||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Text(
|
child: Text(
|
||||||
blocState.notes[index].content,
|
notesState.notes[index].content,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color:
|
color: themeState
|
||||||
state.theme.colorScheme.onPrimaryContainer),
|
.theme.colorScheme.onPrimaryContainer),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -83,7 +83,7 @@ class _NotesAppState extends State<NotesApp> {
|
|||||||
(value) {
|
(value) {
|
||||||
if (value != null && value.isNotEmpty) {
|
if (value != null && value.isNotEmpty) {
|
||||||
context
|
context
|
||||||
.read<PersistenceBloc>()
|
.read<PersistentNotesBloc>()
|
||||||
.add(NoteEntered(Note(content: value)));
|
.add(NoteEntered(Note(content: value)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
40
lib/persisted_brightness.dart
Normal file
40
lib/persisted_brightness.dart
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class PersistedBrightness {
|
||||||
|
final String brightness;
|
||||||
|
|
||||||
|
PersistedBrightness(this.brightness);
|
||||||
|
|
||||||
|
factory PersistedBrightness.fromFlutterBrightness(Brightness brightness) {
|
||||||
|
var persistedBrightness = "light";
|
||||||
|
|
||||||
|
if (brightness == Brightness.dark) {
|
||||||
|
persistedBrightness = "dark";
|
||||||
|
}
|
||||||
|
|
||||||
|
return PersistedBrightness(persistedBrightness);
|
||||||
|
}
|
||||||
|
|
||||||
|
Brightness toFlutterBrightness() {
|
||||||
|
Brightness flutterBrightness = Brightness.light;
|
||||||
|
|
||||||
|
if (brightness == "dark") {
|
||||||
|
flutterBrightness = Brightness.dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flutterBrightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => brightness;
|
||||||
|
|
||||||
|
PersistedBrightness toOpposite() {
|
||||||
|
var newBrightness = "light";
|
||||||
|
|
||||||
|
if (brightness == "light") {
|
||||||
|
newBrightness = "dark";
|
||||||
|
}
|
||||||
|
|
||||||
|
return PersistedBrightness(newBrightness);
|
||||||
|
}
|
||||||
|
}
|
@ -1,79 +0,0 @@
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:fnotes/database.dart';
|
|
||||||
import 'package:fnotes/note.dart';
|
|
||||||
|
|
||||||
class PersistenceBloc extends Bloc<PersistenceEvent, PersistenceState> {
|
|
||||||
static final database = AppDatabase();
|
|
||||||
|
|
||||||
PersistenceBloc() : super(PersistenceState.init()) {
|
|
||||||
on<StoreNotesEvent>(storeAllNotes);
|
|
||||||
on<LoadNotesEvent>(loadAllNotes);
|
|
||||||
on<NoteEntered>(storeNote);
|
|
||||||
on<NoteDismissed>(deleteNote);
|
|
||||||
}
|
|
||||||
|
|
||||||
void storeAllNotes(PersistenceEvent event, Emitter<PersistenceState> emit) {}
|
|
||||||
|
|
||||||
void loadAllNotes(
|
|
||||||
PersistenceEvent event, Emitter<PersistenceState> emit) async {
|
|
||||||
List<Note> list = [];
|
|
||||||
|
|
||||||
await database.select(database.noteTable).get().then(
|
|
||||||
(value) {
|
|
||||||
list = value.map((row) {
|
|
||||||
return Note.withId(id: row.id, content: row.content);
|
|
||||||
}).toList();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
emit(PersistenceState(notes: list));
|
|
||||||
}
|
|
||||||
|
|
||||||
void storeNote(NoteEntered event, Emitter<PersistenceState> emit) async {
|
|
||||||
await database.into(database.noteTable).insert(NoteTableCompanion.insert(
|
|
||||||
id: event.note.id,
|
|
||||||
content: event.note.content,
|
|
||||||
));
|
|
||||||
|
|
||||||
var newNotes = state.notes;
|
|
||||||
newNotes.add(Note.withId(id: event.note.id, content: event.note.content));
|
|
||||||
emit(PersistenceState(notes: newNotes));
|
|
||||||
}
|
|
||||||
|
|
||||||
void deleteNote(NoteDismissed event, Emitter<PersistenceState> emit) {
|
|
||||||
(database.delete(database.noteTable)
|
|
||||||
..where((tbl) => tbl.id.equals(event.note.id)))
|
|
||||||
.go();
|
|
||||||
|
|
||||||
var newNotes =
|
|
||||||
state.notes.where((note) => note.id != event.note.id).toList();
|
|
||||||
|
|
||||||
emit(PersistenceState(notes: newNotes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PersistenceEvent {}
|
|
||||||
|
|
||||||
class LoadNotesEvent extends PersistenceEvent {}
|
|
||||||
|
|
||||||
class StoreNotesEvent extends PersistenceEvent {}
|
|
||||||
|
|
||||||
class NoteEntered extends PersistenceEvent {
|
|
||||||
final Note note;
|
|
||||||
NoteEntered(this.note);
|
|
||||||
}
|
|
||||||
|
|
||||||
class NoteDismissed extends PersistenceEvent {
|
|
||||||
final Note note;
|
|
||||||
NoteDismissed(this.note);
|
|
||||||
}
|
|
||||||
|
|
||||||
class PersistenceState {
|
|
||||||
List<Note> notes = List.empty(growable: true);
|
|
||||||
|
|
||||||
PersistenceState({required this.notes});
|
|
||||||
|
|
||||||
factory PersistenceState.init() {
|
|
||||||
return PersistenceState(notes: []);
|
|
||||||
}
|
|
||||||
}
|
|
78
lib/persistent_notes_bloc.dart
Normal file
78
lib/persistent_notes_bloc.dart
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:fnotes/database.dart';
|
||||||
|
import 'package:fnotes/note.dart';
|
||||||
|
|
||||||
|
class PersistentNotesBloc
|
||||||
|
extends Bloc<PersistentNotesEvent, PersistentNotesState> {
|
||||||
|
PersistentNotesBloc() : super(PersistentNotesState.init()) {
|
||||||
|
on<LoadNotesEvent>(loadAllNotes);
|
||||||
|
on<NoteEntered>(storeNote);
|
||||||
|
on<NoteDismissed>(deleteNote);
|
||||||
|
}
|
||||||
|
|
||||||
|
void storeAllNotes(
|
||||||
|
PersistentNotesEvent event, Emitter<PersistentNotesState> emit) {}
|
||||||
|
|
||||||
|
void loadAllNotes(
|
||||||
|
PersistentNotesEvent event, Emitter<PersistentNotesState> emit) async {
|
||||||
|
List<Note> list = [];
|
||||||
|
|
||||||
|
await database.select(database.persistentNote).get().then(
|
||||||
|
(value) {
|
||||||
|
list = value.map((row) {
|
||||||
|
return Note.withId(id: row.id, content: row.content);
|
||||||
|
}).toList();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
emit(PersistentNotesState(notes: list));
|
||||||
|
}
|
||||||
|
|
||||||
|
void storeNote(NoteEntered event, Emitter<PersistentNotesState> emit) async {
|
||||||
|
await database
|
||||||
|
.into(database.persistentNote)
|
||||||
|
.insert(PersistentNoteCompanion.insert(
|
||||||
|
id: event.note.id,
|
||||||
|
content: event.note.content,
|
||||||
|
));
|
||||||
|
|
||||||
|
var newNotes = state.notes;
|
||||||
|
newNotes.add(Note.withId(id: event.note.id, content: event.note.content));
|
||||||
|
emit(PersistentNotesState(notes: newNotes));
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteNote(NoteDismissed event, Emitter<PersistentNotesState> emit) {
|
||||||
|
(database.delete(database.persistentNote)
|
||||||
|
..where((tbl) => tbl.id.equals(event.note.id)))
|
||||||
|
.go();
|
||||||
|
|
||||||
|
var newNotes =
|
||||||
|
state.notes.where((note) => note.id != event.note.id).toList();
|
||||||
|
|
||||||
|
emit(PersistentNotesState(notes: newNotes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PersistentNotesEvent {}
|
||||||
|
|
||||||
|
class LoadNotesEvent extends PersistentNotesEvent {}
|
||||||
|
|
||||||
|
class NoteEntered extends PersistentNotesEvent {
|
||||||
|
final Note note;
|
||||||
|
NoteEntered(this.note);
|
||||||
|
}
|
||||||
|
|
||||||
|
class NoteDismissed extends PersistentNotesEvent {
|
||||||
|
final Note note;
|
||||||
|
NoteDismissed(this.note);
|
||||||
|
}
|
||||||
|
|
||||||
|
class PersistentNotesState {
|
||||||
|
List<Note> notes = List.empty(growable: true);
|
||||||
|
|
||||||
|
PersistentNotesState({required this.notes});
|
||||||
|
|
||||||
|
factory PersistentNotesState.init() {
|
||||||
|
return PersistentNotesState(notes: []);
|
||||||
|
}
|
||||||
|
}
|
@ -1,33 +1,78 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:fnotes/database.dart';
|
||||||
|
import 'package:fnotes/persisted_brightness.dart';
|
||||||
|
|
||||||
class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
|
class PersistedThemeBloc extends Bloc<ThemeEvent, ThemeState> {
|
||||||
ThemeBloc() : super(ThemeState.init()) {
|
PersistedThemeBloc(Brightness brightness)
|
||||||
on<ThemeEvent>(switchTheme);
|
: super(ThemeState.withBrightness(brightness)) {
|
||||||
|
on<ThemeChangedEvent>(switchTheme);
|
||||||
|
on<LoadThemeEvent>(loadTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
void switchTheme(ThemeEvent event, Emitter<ThemeState> emit) {
|
void switchTheme(ThemeChangedEvent event, Emitter<ThemeState> emit) async {
|
||||||
if (state.theme.brightness == Brightness.light) {
|
await database.delete(database.persistentTheme).go();
|
||||||
emit(ThemeState.withBrightness(Brightness.dark));
|
|
||||||
} else {
|
var newBrightness =
|
||||||
emit(ThemeState.withBrightness(Brightness.light));
|
PersistedBrightness.fromFlutterBrightness(state.theme.brightness)
|
||||||
|
.toOpposite();
|
||||||
|
|
||||||
|
await database
|
||||||
|
.into(database.persistentTheme)
|
||||||
|
.insert(PersistentThemeCompanion.insert(
|
||||||
|
brightness: Value(newBrightness.toString()),
|
||||||
|
));
|
||||||
|
|
||||||
|
emit(ThemeState.withBrightness(newBrightness.toFlutterBrightness()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loadTheme(LoadThemeEvent event, Emitter<ThemeState> emit) async {
|
||||||
|
PersistedBrightness persistedBrightness = await getPersistedBrightness();
|
||||||
|
emit(ThemeState.withBrightness(persistedBrightness.toFlutterBrightness()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<PersistedBrightness> getPersistedBrightness() async {
|
||||||
|
PersistedBrightness persistedBrightness = PersistedBrightness("light");
|
||||||
|
|
||||||
|
await database.select(database.persistentTheme).get().then(
|
||||||
|
(value) {
|
||||||
|
var brightnessIter = value.map((row) {
|
||||||
|
return row.brightness;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (brightnessIter.isNotEmpty) {
|
||||||
|
persistedBrightness = PersistedBrightness(brightnessIter.first);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return persistedBrightness;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThemeEvent {}
|
class ThemeEvent {}
|
||||||
|
|
||||||
|
class LoadThemeEvent extends ThemeEvent {}
|
||||||
|
|
||||||
|
class ThemeChangedEvent extends ThemeEvent {}
|
||||||
|
|
||||||
class ThemeState {
|
class ThemeState {
|
||||||
final ThemeData theme;
|
final ThemeData theme;
|
||||||
static final ThemeData initTheme = ThemeData(
|
|
||||||
colorScheme: ColorScheme.fromSeed(
|
|
||||||
seedColor: Colors.lightBlue, brightness: Brightness.light),
|
|
||||||
);
|
|
||||||
|
|
||||||
ThemeState({required this.theme});
|
ThemeState({required this.theme});
|
||||||
|
|
||||||
factory ThemeState.init() {
|
static Future<ThemeState> fetchAndConstructInitState() async {
|
||||||
return ThemeState(theme: initTheme);
|
PersistedBrightness persistedBrightness = PersistedBrightness('light');
|
||||||
|
await database.select(database.persistentTheme).get().then(
|
||||||
|
(value) {
|
||||||
|
var brightnessIter = value.map((row) {
|
||||||
|
return row.brightness;
|
||||||
|
});
|
||||||
|
persistedBrightness = PersistedBrightness(brightnessIter.first);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return ThemeState.withBrightness(persistedBrightness.toFlutterBrightness());
|
||||||
}
|
}
|
||||||
|
|
||||||
factory ThemeState.withBrightness(Brightness brightness) {
|
factory ThemeState.withBrightness(Brightness brightness) {
|
||||||
|
@ -513,7 +513,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.1"
|
version: "1.5.1"
|
||||||
provider:
|
provider:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: provider
|
name: provider
|
||||||
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||||
|
@ -17,6 +17,7 @@ dependencies:
|
|||||||
sqlite3_flutter_libs: ^0.5.20
|
sqlite3_flutter_libs: ^0.5.20
|
||||||
uuid: ^4.3.3
|
uuid: ^4.3.3
|
||||||
sqlite3: ^2.4.0
|
sqlite3: ^2.4.0
|
||||||
|
provider: ^6.1.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user