Replace objectbox with sembast

adapt-navigator
Oystein Kristoffer Tveit 2021-12-04 05:13:13 +01:00
parent a0c608ccca
commit fe5c5a4cce
23 changed files with 754 additions and 782 deletions

2
.gitignore vendored
View File

@ -30,8 +30,6 @@
.pub/ .pub/
/build/ /build/
objectbox.g.dart
# Web related # Web related
lib/generated_plugin_registrant.dart lib/generated_plugin_registrant.dart

View File

@ -1,6 +1,5 @@
analyzer: analyzer:
exclude: exclude:
- "lib/objectbox.g.dart"
linter: linter:
rules: rules:

View File

@ -1,27 +0,0 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import './database_event.dart';
import './database_state.dart';
export 'package:flutter_bloc/flutter_bloc.dart';
export './database_event.dart';
export './database_not_connected_exception.dart';
export './database_state.dart';
class DatabaseBloc extends Bloc<DatabaseEvent, DatabaseState> {
DatabaseBloc() : super(const DatabaseDisconnected());
@override
Stream<DatabaseState> mapEventToState(DatabaseEvent event)
async* {
if (event is ConnectedToDatabase) {
yield DatabaseConnected(event.database);
} else {
yield const DatabaseDisconnected();
}
}
}

View File

@ -1,14 +0,0 @@
import 'package:objectbox/objectbox.dart';
abstract class DatabaseEvent {
const DatabaseEvent();
}
class ConnectedToDatabase extends DatabaseEvent {
final Store database;
const ConnectedToDatabase(this.database);
}
class DisconnectedFromDatabase extends DatabaseEvent {
const DisconnectedFromDatabase();
}

View File

@ -1 +0,0 @@
class DatabaseNotConnectedException implements Exception {}

View File

@ -1,14 +0,0 @@
import 'package:objectbox/objectbox.dart';
abstract class DatabaseState {
const DatabaseState();
}
class DatabaseConnected extends DatabaseState {
final Store database;
const DatabaseConnected(this.database);
}
class DatabaseDisconnected extends DatabaseState {
const DatabaseDisconnected();
}

View File

@ -1,12 +1,15 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:mdi/mdi.dart'; import 'package:mdi/mdi.dart';
import 'package:path/path.dart'; import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:sembast/sembast.dart';
import 'package:sembast/sembast_io.dart';
import 'bloc/database/database_bloc.dart';
import 'bloc/theme/theme_bloc.dart'; import 'bloc/theme/theme_bloc.dart';
import 'models/themes/theme.dart'; import 'models/themes/theme.dart';
import 'objectbox.g.dart';
import 'router.dart'; import 'router.dart';
import 'view/components/common/splash.dart'; import 'view/components/common/splash.dart';
import 'view/screens/history.dart'; import 'view/screens/history.dart';
@ -14,56 +17,35 @@ import 'view/screens/search/kanji_view.dart';
import 'view/screens/search/search_view.dart'; import 'view/screens/search/search_view.dart';
import 'view/screens/settings.dart'; import 'view/screens/settings.dart';
void main() => runApp(const MyApp()); Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final Directory appDocDir = await getApplicationDocumentsDirectory();
DatabaseBloc _databaseBloc = DatabaseBloc(); if (!appDocDir.existsSync())
appDocDir.createSync(recursive: true);
class MyApp extends StatefulWidget { final Database db = await databaseFactoryIo.openDatabase(join(appDocDir.path, 'sembast.db'));
const MyApp({Key? key}) : super(key: key);
@override GetIt.instance.registerSingleton<Database>(db);
_MyAppState createState() => _MyAppState();
runApp(const MyApp());
} }
class _MyAppState extends State<MyApp> { class MyApp extends StatelessWidget {
late final Store _store;
bool dbConnected = false;
@override const MyApp({
void initState() { Key? key,
super.initState(); }) : super(key: key);
getApplicationDocumentsDirectory().then((dir) {
_store = Store(
getObjectBoxModel(),
directory: join(dir.path, 'objectbox'),
);
_databaseBloc.add(ConnectedToDatabase(_store));
setState(() {
dbConnected = true;
});
});
}
@override
void dispose() {
_store.close();
_databaseBloc.add(const DisconnectedFromDatabase());
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
BlocProvider(create: (context) => _databaseBloc),
BlocProvider(create: (context) => ThemeBloc()), BlocProvider(create: (context) => ThemeBloc()),
], ],
child: BlocBuilder<ThemeBloc, ThemeState>( child: BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, themeState) { builder: (context, themeState) {
if (!(dbConnected && themeState.prefsAreLoaded)) if (!themeState.prefsAreLoaded) return const SplashScreen();
return const SplashScreen();
return MaterialApp( return MaterialApp(
title: 'Jisho Study Tool', title: 'Jisho Study Tool',
@ -77,6 +59,18 @@ class _MyAppState extends State<MyApp> {
} }
} }
class _Page {
final Widget content;
final Widget titleBar;
final BottomNavigationBarItem item;
const _Page({
required this.content,
required this.titleBar,
required this.item,
});
}
class Home extends StatefulWidget { class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key); const Home({Key? key}) : super(key: key);
@ -126,59 +120,47 @@ class _HomeState extends State<Home> {
}, },
); );
} }
List<_Page> get pages => [
const _Page(
content: SearchView(),
titleBar: Text('Search'),
item: BottomNavigationBarItem(
label: 'Search',
icon: Icon(Icons.search),
),
),
const _Page(
content: KanjiView(),
titleBar: Text('Kanji'),
item: BottomNavigationBarItem(
label: 'Kanji',
icon: Icon(Mdi.ideogramCjk, size: 30),
),
),
const _Page(
content: HistoryView(),
titleBar: Text('History'),
item: BottomNavigationBarItem(
label: 'History',
icon: Icon(Icons.history),
),
),
_Page(
content: Container(),
titleBar: const Text('Saved'),
item: const BottomNavigationBarItem(
label: 'Saved',
icon: Icon(Icons.bookmark),
),
),
const _Page(
content: SettingsView(),
titleBar: Text('Settings'),
item: BottomNavigationBarItem(
label: 'Settings',
icon: Icon(Icons.settings),
),
),
];
} }
class _Page {
final Widget content;
final Widget titleBar;
final BottomNavigationBarItem item;
const _Page({
required this.content,
required this.titleBar,
required this.item,
});
}
final List<_Page> pages = [
const _Page(
content: SearchView(),
titleBar: Text('Search'),
item: BottomNavigationBarItem(
label: 'Search',
icon: Icon(Icons.search),
),
),
const _Page(
content: KanjiView(),
titleBar: Text('Kanji'),
item: BottomNavigationBarItem(
label: 'Kanji',
icon: Icon(Mdi.ideogramCjk, size: 30),
),
),
const _Page(
content: HistoryView(),
titleBar: Text('History'),
item: BottomNavigationBarItem(
label: 'History',
icon: Icon(Icons.history),
),
),
_Page(
content: Container(),
titleBar: const Text('Saved'),
item: const BottomNavigationBarItem(
label: 'Saved',
icon: Icon(Icons.bookmark),
),
),
const _Page(
content: SettingsView(),
titleBar: Text('Settings'),
item: BottomNavigationBarItem(
label: 'Settings',
icon: Icon(Icons.settings),
),
),
];

View File

@ -1,13 +1,12 @@
import 'package:objectbox/objectbox.dart';
@Entity()
class KanjiQuery { class KanjiQuery {
int id; final String kanji;
String kanji;
KanjiQuery({ KanjiQuery({
this.id = 0,
required this.kanji, required this.kanji,
}); });
Map<String, Object?> toJson() => {'kanji': kanji};
factory KanjiQuery.fromJson(Map<String, dynamic> json) =>
KanjiQuery(kanji: json['kanji'] as String);
} }

View File

@ -1,30 +1,43 @@
import 'package:objectbox/objectbox.dart'; import 'package:sembast/sembast.dart';
import 'package:sembast/timestamp.dart';
import './kanji_query.dart'; import './kanji_query.dart';
import './word_query.dart'; import './word_query.dart';
@Entity()
class Search { class Search {
int id; final DateTime timestamp;
final WordQuery? wordQuery;
final KanjiQuery? kanjiQuery;
@Property(type: PropertyType.date) Search.fromKanjiQuery({
late final DateTime timestamp;
final wordQuery = ToOne<WordQuery>();
final kanjiQuery = ToOne<KanjiQuery>();
Search({
this.id = 0,
required this.timestamp, required this.timestamp,
}); required KanjiQuery this.kanjiQuery,
}) : wordQuery = null;
bool isKanji() { Search.fromWordQuery({
// // TODO: better error message required this.timestamp,
if (wordQuery.target == null && kanjiQuery.target == null) required WordQuery this.wordQuery,
throw Exception(); }) : kanjiQuery = null;
return wordQuery.target == null;
}
bool get isKanji => wordQuery == null;
Map<String, Object?> toJson() => {
'timestamp': timestamp.millisecondsSinceEpoch,
'wordQuery': wordQuery?.toJson(),
'kanjiQuery': kanjiQuery?.toJson(),
};
factory Search.fromJson(Map<String, dynamic> json) =>
json['wordQuery'] != null
? Search.fromWordQuery(
timestamp:
DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int),
wordQuery: WordQuery.fromJson(json['wordQuery']),
)
: Search.fromKanjiQuery(
timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int),
kanjiQuery: KanjiQuery.fromJson(json['kanjiQuery']),
);
static StoreRef<int, Object?> get store => intMapStoreFactory.store('search');
} }

View File

@ -1,19 +1,17 @@
import 'package:objectbox/objectbox.dart';
import './word_result.dart'; import './word_result.dart';
@Entity()
class WordQuery { class WordQuery {
int id; final String query;
String query;
// TODO: Link query with results that the user clicks onto. // TODO: Link query with results that the user clicks onto.
@Backlink() // final List<WordResult> chosenResults;
final chosenResults = ToMany<WordResult>();
WordQuery({ WordQuery({
this.id = 0,
required this.query, required this.query,
}); });
Map<String, Object?> toJson() => {'query': query};
factory WordQuery.fromJson(Map<String, dynamic> json) =>
WordQuery(query: json['query'] as String);
} }

View File

@ -1,21 +1,13 @@
import 'package:objectbox/objectbox.dart';
import 'word_query.dart'; import 'word_query.dart';
@Entity()
class WordResult { class WordResult {
int id; final DateTime timestamp;
final String word;
@Property(type: PropertyType.date) final WordQuery searchString;
DateTime timestamp;
String word;
final searchString = ToOne<WordQuery>();
WordResult({ WordResult({
this.id = 0,
required this.timestamp, required this.timestamp,
required this.word, required this.word,
required this.searchString,
}); });
} }

View File

@ -1,13 +1,22 @@
import 'package:objectbox/objectbox.dart'; // import 'package:objectbox/objectbox.dart';
import 'package:unofficial_jisho_api/api.dart' as jisho; // import 'package:unofficial_jisho_api/api.dart' as jisho;
@Entity() // TODO: Rewrite for sembast
class ExampleSentencePiece {
int id = 0;
String? lifted;
String unlifted;
ExampleSentencePiece.fromJishoObject(jisho.ExampleSentencePiece object) : // @Entity()
lifted = object.lifted, // class ExampleSentencePiece {
unlifted = object.unlifted; // int id;
} // String? lifted;
// String unlifted;
// ExampleSentencePiece({
// this.id = 0,
// required this.lifted,
// required this.unlifted,
// });
// ExampleSentencePiece.fromJishoObject(jisho.ExampleSentencePiece object)
// : id = 0,
// lifted = object.lifted,
// unlifted = object.unlifted;
// }

View File

@ -1,36 +1,58 @@
import 'package:objectbox/objectbox.dart'; // import 'package:objectbox/objectbox.dart';
import 'package:unofficial_jisho_api/api.dart' as jisho; // import 'package:unofficial_jisho_api/api.dart' as jisho;
import 'common.dart'; // import 'common.dart';
@Entity() // TODO: Rewrite for sembast
class ExampleResultData {
String kanji;
String kana;
String english;
List<ExampleSentencePiece> pieces;
ExampleResultData.fromJishoObject(jisho.ExampleResultData object) // @Entity()
: kanji = object.kanji, // class ExampleResultData {
kana = object.kana, // int id;
english = object.english, // String kanji;
pieces = object.pieces // String kana;
.map((p) => ExampleSentencePiece.fromJishoObject(p)) // String english;
.toList(); // List<ExampleSentencePiece> pieces;
}
@Entity() // ExampleResultData({
class ExampleResults { // this.id = 0,
String query; // required this.kanji,
bool found; // required this.kana,
String uri; // required this.english,
List<ExampleResultData> results; // required this.pieces,
// });
ExampleResults.fromJishoObject(jisho.ExampleResults object) // ExampleResultData.fromJishoObject(jisho.ExampleResultData object)
: query = object.query, // : id = 0,
found = object.found, // kanji = object.kanji,
uri = object.uri, // kana = object.kana,
results = object.results // english = object.english,
.map((r) => ExampleResultData.fromJishoObject(r)) // pieces = object.pieces
.toList(); // .map((p) => ExampleSentencePiece.fromJishoObject(p))
} // .toList();
// }
// @Entity()
// class ExampleResults {
// int id;
// String query;
// bool found;
// String uri;
// List<ExampleResultData> results;
// ExampleResults({
// this.id = 0,
// required this.query,
// required this.found,
// required this.uri,
// required this.results,
// });
// ExampleResults.fromJishoObject(jisho.ExampleResults object)
// : id = 0,
// query = object.query,
// found = object.found,
// uri = object.uri,
// results = object.results
// .map((r) => ExampleResultData.fromJishoObject(r))
// .toList();
// }

View File

@ -1,86 +1,129 @@
import 'package:objectbox/objectbox.dart'; // import 'package:objectbox/objectbox.dart';
import 'package:unofficial_jisho_api/api.dart' as jisho; // import 'package:unofficial_jisho_api/api.dart' as jisho;
@Entity() // TODO: Rewrite for sembast
class YomiExample {
int id = 0;
String example;
String reading;
String meaning;
YomiExample.fromJishoObject(jisho.YomiExample object) // @Entity()
: example = object.example, // class YomiExample {
reading = object.reading, // int id;
meaning = object.meaning; // String example;
} // String reading;
// String meaning;
@Entity() // YomiExample({
class Radical { // this.id = 0,
int id = 0; // required this.example,
String symbol; // required this.reading,
List<String> forms; // required this.meaning,
String meaning; // });
Radical.fromJishoObject(jisho.Radical object) // YomiExample.fromJishoObject(jisho.YomiExample object)
: symbol = object.symbol, // : id = 0,
forms = object.forms, // example = object.example,
meaning = object.meaning; // reading = object.reading,
} // meaning = object.meaning;
// }
@Entity() // @Entity()
class KanjiResult { // class Radical {
int id = 0; // int id = 0;
String query; // String symbol;
bool found; // List<String> forms;
KanjiResultData? data; // String meaning;
KanjiResult.fromJishoObject(jisho.KanjiResult object) // Radical({
: query = object.query, // this.id = 0,
found = object.found, // required this.symbol,
data = (object.data == null) // required this.forms,
? null // required this.meaning,
: KanjiResultData.fromJishoObject(object.data!); // });
}
@Entity() // Radical.fromJishoObject(jisho.Radical object)
class KanjiResultData { // : symbol = object.symbol,
int id = 0; // forms = object.forms,
String? taughtIn; // meaning = object.meaning;
String? jlptLevel; // }
int? newspaperFrequencyRank;
int strokeCount;
String meaning;
List<String> kunyomi;
List<String> onyomi;
List<YomiExample> kunyomiExamples;
List<YomiExample> onyomiExamples;
Radical? radical;
List<String> parts;
String strokeOrderDiagramUri;
String strokeOrderSvgUri;
String strokeOrderGifUri;
String uri;
KanjiResultData.fromJishoObject(jisho.KanjiResultData object) // @Entity()
: taughtIn = object.taughtIn, // class KanjiResult {
jlptLevel = object.jlptLevel, // int id = 0;
newspaperFrequencyRank = object.newspaperFrequencyRank, // String query;
strokeCount = object.strokeCount, // bool found;
meaning = object.meaning, // KanjiResultData? data;
kunyomi = object.kunyomi,
onyomi = object.onyomi, // KanjiResult({
kunyomiExamples = object.kunyomiExamples // this.id = 0,
.map((k) => YomiExample.fromJishoObject(k)) // required this.query,
.toList(), // required this.found,
onyomiExamples = object.onyomiExamples // required this.data,
.map((o) => YomiExample.fromJishoObject(o)) // });
.toList(),
radical = (object.radical == null) // KanjiResult.fromJishoObject(jisho.KanjiResult object)
? null // : query = object.query,
: Radical.fromJishoObject(object.radical!), // found = object.found,
parts = object.parts, // data = (object.data == null)
strokeOrderDiagramUri = object.strokeOrderDiagramUri, // ? null
strokeOrderSvgUri = object.strokeOrderSvgUri, // : KanjiResultData.fromJishoObject(object.data!);
strokeOrderGifUri = object.strokeOrderGifUri, // }
uri = object.uri;
} // @Entity()
// class KanjiResultData {
// int id = 0;
// String? taughtIn;
// String? jlptLevel;
// int? newspaperFrequencyRank;
// int strokeCount;
// String meaning;
// List<String> kunyomi;
// List<String> onyomi;
// List<YomiExample> kunyomiExamples;
// List<YomiExample> onyomiExamples;
// Radical? radical;
// List<String> parts;
// String strokeOrderDiagramUri;
// String strokeOrderSvgUri;
// String strokeOrderGifUri;
// String uri;
// KanjiResultData({
// this.id = 0,
// required this.taughtIn,
// required this.jlptLevel,
// required this.newspaperFrequencyRank,
// required this.strokeCount,
// required this.meaning,
// required this.kunyomi,
// required this.onyomi,
// required this.kunyomiExamples,
// required this.onyomiExamples,
// required this.radical,
// required this.parts,
// required this.strokeOrderDiagramUri,
// required this.strokeOrderSvgUri,
// required this.strokeOrderGifUri,
// required this.uri,
// });
// KanjiResultData.fromJishoObject(jisho.KanjiResultData object)
// : taughtIn = object.taughtIn,
// jlptLevel = object.jlptLevel,
// newspaperFrequencyRank = object.newspaperFrequencyRank,
// strokeCount = object.strokeCount,
// meaning = object.meaning,
// kunyomi = object.kunyomi,
// onyomi = object.onyomi,
// kunyomiExamples = object.kunyomiExamples
// .map((k) => YomiExample.fromJishoObject(k))
// .toList(),
// onyomiExamples = object.onyomiExamples
// .map((o) => YomiExample.fromJishoObject(o))
// .toList(),
// radical = (object.radical == null)
// ? null
// : Radical.fromJishoObject(object.radical!),
// parts = object.parts,
// strokeOrderDiagramUri = object.strokeOrderDiagramUri,
// strokeOrderSvgUri = object.strokeOrderSvgUri,
// strokeOrderGifUri = object.strokeOrderGifUri,
// uri = object.uri;
// }

View File

@ -1,101 +1,155 @@
import 'package:objectbox/objectbox.dart'; // import 'package:objectbox/objectbox.dart';
import 'package:unofficial_jisho_api/api.dart' as jisho; // import 'package:unofficial_jisho_api/api.dart' as jisho;
import 'common.dart'; // import 'common.dart';
@Entity() // TODO: Rewrite for sembast
class PhraseScrapeSentence {
int id = 0;
String english;
String japanese;
List<ExampleSentencePiece> pieces;
PhraseScrapeSentence.fromJishoObject(jisho.PhraseScrapeSentence object) // @Entity()
: english = object.english, // class PhraseScrapeSentence {
japanese = object.japanese, // int id;
pieces = object.pieces // String english;
.map((p) => ExampleSentencePiece.fromJishoObject(p)) // String japanese;
.toList(); // List<ExampleSentencePiece> pieces;
}
@Entity() // PhraseScrapeSentence({
class PhraseScrapeMeaning { // this.id = 0,
int id = 0; // required this.english,
List<String> seeAlsoTerms; // required this.japanese,
List<PhraseScrapeSentence> sentences; // required this.pieces,
String definition; // });
List<String> supplemental;
String? definitionAbstract;
List<String> tags;
PhraseScrapeMeaning.fromJishoObject(jisho.PhraseScrapeMeaning object) // PhraseScrapeSentence.fromJishoObject(jisho.PhraseScrapeSentence object)
: seeAlsoTerms = object.seeAlsoTerms, // : id = 0,
sentences = object.sentences // english = object.english,
.map((s) => PhraseScrapeSentence.fromJishoObject(s)) // japanese = object.japanese,
.toList(), // pieces = object.pieces
definition = object.definition, // .map((p) => ExampleSentencePiece.fromJishoObject(p))
supplemental = object.supplemental, // .toList();
definitionAbstract = object.definitionAbstract, // }
tags = object.tags;
}
@Entity() // @Entity()
class KanjiKanaPair { // class PhraseScrapeMeaning {
int id = 0; // int id;
String kanji; // List<String> seeAlsoTerms;
String? kana; // List<PhraseScrapeSentence> sentences;
// String definition;
// List<String> supplemental;
// String? definitionAbstract;
// List<String> tags;
KanjiKanaPair.fromJishoObject(jisho.KanjiKanaPair object) // PhraseScrapeMeaning({
: kanji = object.kanji, // this.id = 0,
kana = object.kana; // required this.seeAlsoTerms,
} // required this.sentences,
// required this.definition,
// required this.supplemental,
// required this.definitionAbstract,
// required this.tags,
// });
@Entity() // PhraseScrapeMeaning.fromJishoObject(jisho.PhraseScrapeMeaning object)
class PhrasePageScrapeResult { // : id = 0,
int id = 0; // seeAlsoTerms = object.seeAlsoTerms,
bool found; // sentences = object.sentences
String query; // .map((s) => PhraseScrapeSentence.fromJishoObject(s))
PhrasePageScrapeResultData? data; // .toList(),
// definition = object.definition,
// supplemental = object.supplemental,
// definitionAbstract = object.definitionAbstract,
// tags = object.tags;
// }
PhrasePageScrapeResult.fromJishoObject(jisho.PhrasePageScrapeResult object) // @Entity()
: found = object.found, // class KanjiKanaPair {
query = object.query, // int id;
data = (object.data == null) // String kanji;
? null // String? kana;
: PhrasePageScrapeResultData.fromJishoObject(object.data!);
}
@Entity() // KanjiKanaPair({
class AudioFile { // this.id = 0,
int id = 0; // required this.kanji,
String uri; // required this.kana,
String mimetype; // });
AudioFile.fromJishoObject(jisho.AudioFile object) // KanjiKanaPair.fromJishoObject(jisho.KanjiKanaPair object)
: uri = object.uri, // : id = 0,
mimetype = object.mimetype; // kanji = object.kanji,
} // kana = object.kana;
// }
@Entity() // @Entity()
class PhrasePageScrapeResultData { // class PhrasePageScrapeResult {
int id = 0; // int id;
String uri; // bool found;
List<String> tags; // String query;
List<PhraseScrapeMeaning> meanings; // PhrasePageScrapeResultData? data;
List<KanjiKanaPair> otherForms;
List<AudioFile> audio;
List<String> notes;
PhrasePageScrapeResultData.fromJishoObject( // PhrasePageScrapeResult({
jisho.PhrasePageScrapeResultData object, // this.id = 0,
) : uri = object.uri, // required this.found,
tags = object.tags, // required this.query,
meanings = object.meanings // required this.data,
.map((m) => PhraseScrapeMeaning.fromJishoObject(m)) // });
.toList(),
otherForms = object.otherForms // PhrasePageScrapeResult.fromJishoObject(jisho.PhrasePageScrapeResult object)
.map((f) => KanjiKanaPair.fromJishoObject(f)) // : id = 0,
.toList(), // found = object.found,
audio = object.audio.map((a) => AudioFile.fromJishoObject(a)).toList(), // query = object.query,
notes = object.notes; // data = (object.data == null)
} // ? null
// : PhrasePageScrapeResultData.fromJishoObject(object.data!);
// }
// @Entity()
// class AudioFile {
// int id;
// String uri;
// String mimetype;
// AudioFile({
// this.id = 0,
// required this.uri,
// required this.mimetype,
// });
// AudioFile.fromJishoObject(jisho.AudioFile object)
// : id = 0,
// uri = object.uri,
// mimetype = object.mimetype;
// }
// @Entity()
// class PhrasePageScrapeResultData {
// int id;
// String uri;
// List<String> tags;
// List<PhraseScrapeMeaning> meanings;
// List<KanjiKanaPair> otherForms;
// List<AudioFile> audio;
// List<String> notes;
// PhrasePageScrapeResultData({
// this.id = 0,
// required this.uri,
// required this.tags,
// required this.meanings,
// required this.otherForms,
// required this.audio,
// required this.notes,
// });
// PhrasePageScrapeResultData.fromJishoObject(
// jisho.PhrasePageScrapeResultData object,
// ) : id = 0,
// uri = object.uri,
// tags = object.tags,
// meanings = object.meanings
// .map((m) => PhraseScrapeMeaning.fromJishoObject(m))
// .toList(),
// otherForms = object.otherForms
// .map((f) => KanjiKanaPair.fromJishoObject(f))
// .toList(),
// audio = object.audio.map((a) => AudioFile.fromJishoObject(a)).toList(),
// notes = object.notes;
// }

View File

@ -1,126 +1,195 @@
import 'package:objectbox/objectbox.dart'; // import 'package:objectbox/objectbox.dart';
import 'package:unofficial_jisho_api/api.dart' as jisho; // import 'package:unofficial_jisho_api/api.dart' as jisho;
@Entity() // TODO: Rewrite for sembast
class SearchResult {
int id = 0;
final JishoResultMeta meta;
final ToMany<JishoResult> data = ToMany<JishoResult>();
SearchResult.fromJishoObject(final jisho.JishoAPIResult object) // @Entity()
: meta = JishoResultMeta.fromJishoObject(object.meta) { // class SearchResult {
data.addAll( // int id;
object.data // final JishoResultMeta meta;
?.map((r) => JishoResult.fromJishoObject(r)) ?? // final ToMany<JishoResult> data;
<JishoResult>[],
);
}
}
@Entity() // SearchResult({
class JishoResultMeta { // this.id = 0,
int id = 0; // required this.meta,
int status; // required this.data,
// });
JishoResultMeta.fromJishoObject(final jisho.JishoResultMeta object) // SearchResult.fromJishoObject(final jisho.JishoAPIResult object)
: status = object.status; // : id = 0,
} // meta = JishoResultMeta.fromJishoObject(object.meta),
// data = ToMany<JishoResult>()
// ..addAll(
// object.data?.map((r) => JishoResult.fromJishoObject(r)) ??
// <JishoResult>[],
// );
// }
@Entity() // @Entity()
class JishoResult { // class JishoResultMeta {
int id = 0; // int id;
JishoAttribution attribution; // int status;
bool? is_common;
List<JishoJapaneseWord> japanese;
List<String> jlpt;
List<JishoWordSense> senses;
String slug;
List<String> tags;
JishoResult.fromJishoObject(final jisho.JishoResult object) // JishoResultMeta({
: attribution = JishoAttribution.fromJishoObject(object.attribution), // this.id = 0,
is_common = object.isCommon, // required this.status,
japanese = object.japanese // });
.map((j) => JishoJapaneseWord.fromJishoObject(j))
.toList(),
jlpt = object.jlpt,
senses = object.senses
.map((s) => JishoWordSense.fromJishoObject(s))
.toList(),
slug = object.slug,
tags = object.tags;
}
@Entity() // JishoResultMeta.fromJishoObject(final jisho.JishoResultMeta object)
class JishoAttribution { // : id = 0,
int id = 0; // status = object.status;
String? dbpedia; // }
bool jmdict;
bool jmnedict;
JishoAttribution.fromJishoObject(final jisho.JishoAttribution object) // @Entity()
: dbpedia = object.dbpedia, // class JishoResult {
jmdict = object.jmdict, // int id;
jmnedict = object.jmnedict; // JishoAttribution attribution;
} // bool? is_common;
// List<JishoJapaneseWord> japanese;
// List<String> jlpt;
// List<JishoWordSense> senses;
// String slug;
// List<String> tags;
@Entity() // JishoResult({
class JishoJapaneseWord { // this.id = 0,
int id = 0; // required this.attribution,
String? reading; // required this.is_common,
String? word; // required this.japanese,
// required this.jlpt,
// required this.senses,
// required this.slug,
// required this.tags,
// });
JishoJapaneseWord.fromJishoObject(final jisho.JishoJapaneseWord object) // JishoResult.fromJishoObject(final jisho.JishoResult object)
: reading = object.reading, // : id = 0,
word = object.word; // attribution = JishoAttribution.fromJishoObject(object.attribution),
} // is_common = object.isCommon,
// japanese = object.japanese
// .map((j) => JishoJapaneseWord.fromJishoObject(j))
// .toList(),
// jlpt = object.jlpt,
// senses = object.senses
// .map((s) => JishoWordSense.fromJishoObject(s))
// .toList(),
// slug = object.slug,
// tags = object.tags;
// }
@Entity() // @Entity()
class JishoWordSense { // class JishoAttribution {
int id = 0; // int id;
List<String> antonyms; // String? dbpedia;
List<String> english_definitions; // bool jmdict;
List<String> info; // bool jmnedict;
List<JishoSenseLink> links;
List<String> parts_of_speech;
List<String> restrictions;
List<String> see_also;
List<JishoWordSource> source;
List<String> tags;
JishoWordSense.fromJishoObject(final jisho.JishoWordSense object) // JishoAttribution({
: antonyms = object.antonyms, // this.id = 0,
english_definitions = object.englishDefinitions, // required this.dbpedia,
info = object.info, // required this.jmdict,
links = // required this.jmnedict,
object.links.map((l) => JishoSenseLink.fromJishoObject(l)).toList(), // });
parts_of_speech = object.partsOfSpeech,
restrictions = object.restrictions,
see_also = object.seeAlso,
source = object.source
.map((s) => JishoWordSource.fromJishoObject(s))
.toList(),
tags = object.tags;
}
@Entity() // JishoAttribution.fromJishoObject(final jisho.JishoAttribution object)
class JishoWordSource { // : id = 0,
int id = 0; // dbpedia = object.dbpedia,
String language; // jmdict = object.jmdict,
String? word; // jmnedict = object.jmnedict;
// }
JishoWordSource.fromJishoObject(final jisho.JishoWordSource object) // @Entity()
: language = object.language, // class JishoJapaneseWord {
word = object.word; // int id;
} // String? reading;
// String? word;
@Entity() // JishoJapaneseWord({
class JishoSenseLink { // this.id = 0,
int id = 0; // required this.reading,
String text; // required this.word,
String url; // });
JishoSenseLink.fromJishoObject(final jisho.JishoSenseLink object) // JishoJapaneseWord.fromJishoObject(final jisho.JishoJapaneseWord object)
: text = object.text, // : id = 0,
url = object.url; // reading = object.reading,
} // word = object.word;
// }
// @Entity()
// class JishoWordSense {
// int id;
// List<String> antonyms;
// List<String> english_definitions;
// List<String> info;
// List<JishoSenseLink> links;
// List<String> parts_of_speech;
// List<String> restrictions;
// List<String> see_also;
// List<JishoWordSource> source;
// List<String> tags;
// JishoWordSense({
// this.id = 0,
// required this.antonyms,
// required this.english_definitions,
// required this.info,
// required this.links,
// required this.parts_of_speech,
// required this.restrictions,
// required this.see_also,
// required this.source,
// required this.tags,
// });
// JishoWordSense.fromJishoObject(final jisho.JishoWordSense object)
// : id = 0,
// antonyms = object.antonyms,
// english_definitions = object.englishDefinitions,
// info = object.info,
// links =
// object.links.map((l) => JishoSenseLink.fromJishoObject(l)).toList(),
// parts_of_speech = object.partsOfSpeech,
// restrictions = object.restrictions,
// see_also = object.seeAlso,
// source = object.source
// .map((s) => JishoWordSource.fromJishoObject(s))
// .toList(),
// tags = object.tags;
// }
// @Entity()
// class JishoWordSource {
// int id;
// String language;
// String? word;
// JishoWordSource({
// this.id = 0,
// required this.language,
// required this.word,
// });
// JishoWordSource.fromJishoObject(final jisho.JishoWordSource object)
// : id = 0,
// language = object.language,
// word = object.word;
// }
// @Entity()
// class JishoSenseLink {
// int id;
// String text;
// String url;
// JishoSenseLink({
// this.id = 0,
// required this.text,
// required this.url,
// });
// JishoSenseLink.fromJishoObject(final jisho.JishoSenseLink object)
// : id = 0,
// text = object.text,
// url = object.url;
// }

View File

@ -1,141 +0,0 @@
{
"_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.",
"_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.",
"_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.",
"entities": [
{
"id": "3:8314315977756262774",
"lastPropertyId": "4:7972948456299367594",
"name": "WordResult",
"properties": [
{
"id": "1:8286440150679521496",
"name": "id",
"type": 6,
"flags": 1
},
{
"id": "2:2698026687178480112",
"name": "timestamp",
"type": 10
},
{
"id": "3:8750782874894963158",
"name": "word",
"type": 9
},
{
"id": "4:7972948456299367594",
"name": "searchStringId",
"type": 11,
"flags": 520,
"indexId": "1:6146948198859733323",
"relationTarget": "WordQuery"
}
],
"relations": []
},
{
"id": "4:4256390943850643278",
"lastPropertyId": "3:1496429060084558178",
"name": "KanjiQuery",
"properties": [
{
"id": "1:2966275213904862677",
"name": "id",
"type": 6,
"flags": 1
},
{
"id": "2:3733952844232949036",
"name": "kanji",
"type": 9
}
],
"relations": []
},
{
"id": "5:3499538826755540666",
"lastPropertyId": "3:1154921921492752045",
"name": "WordQuery",
"properties": [
{
"id": "1:2582448470002735577",
"name": "id",
"type": 6,
"flags": 1
},
{
"id": "2:6622038022626247037",
"name": "query",
"type": 9
}
],
"relations": []
},
{
"id": "6:8118874861016646859",
"lastPropertyId": "5:818915488505962903",
"name": "Search",
"properties": [
{
"id": "1:3233720904924970047",
"name": "id",
"type": 6,
"flags": 1
},
{
"id": "2:7793044338609887616",
"name": "timestamp",
"type": 10
},
{
"id": "4:5737790291742758071",
"name": "wordQueryId",
"type": 11,
"flags": 520,
"indexId": "4:4174896839978600983",
"relationTarget": "WordQuery"
},
{
"id": "5:818915488505962903",
"name": "kanjiQueryId",
"type": 11,
"flags": 520,
"indexId": "5:5394995618034342416",
"relationTarget": "KanjiQuery"
}
],
"relations": []
}
],
"lastEntityId": "6:8118874861016646859",
"lastIndexId": "5:5394995618034342416",
"lastRelationId": "1:2624712325077938293",
"lastSequenceId": "0:0",
"modelVersion": 5,
"modelVersionParserMinimum": 5,
"retiredEntityUids": [
8135239166970424087,
461492167249325765
],
"retiredIndexUids": [
2344626140411525437,
1957456749938325194
],
"retiredPropertyUids": [
2681934095975267680,
4514526257378540330,
1930470268740402049,
4297905889790758495,
4157902147911002923,
7573103520245228403,
1496429060084558178,
1154921921492752045,
2254834401134912797
],
"retiredRelationUids": [
2624712325077938293
],
"version": 1
}

View File

@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:sembast/sembast.dart';
import '../../bloc/database/database_bloc.dart';
import '../../models/history/search.dart'; import '../../models/history/search.dart';
import '../../objectbox.g.dart';
import '../components/history/date_divider.dart'; import '../components/history/date_divider.dart';
import '../components/history/kanji_search_item.dart'; import '../components/history/kanji_search_item.dart';
import '../components/history/phrase_search_item.dart'; import '../components/history/phrase_search_item.dart';
@ -11,60 +11,63 @@ import '../components/opaque_box.dart';
class HistoryView extends StatelessWidget { class HistoryView extends StatelessWidget {
const HistoryView({Key? key}) : super(key: key); const HistoryView({Key? key}) : super(key: key);
Database get _db => GetIt.instance.get<Database>();
Stream<List<Search>> get searchStream => Search.store
.query(
finder: Finder(
sortOrders: [SortOrder('timestamp', false)],
),
)
.onSnapshots(_db)
.map((snapshot) {
return snapshot
.map<Search?>(
(snap) => (snap.value != null)
? Search.fromJson(snap.value! as Map<String, Object?>)
: null,
)
.where((s) => s != null)
.map<Search>((s) => s!)
.toList();
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<DatabaseBloc, DatabaseState>( return StreamBuilder<List<Search>>(
builder: (context, state) { stream: searchStream,
if (state is DatabaseDisconnected) { builder: (context, snapshot) {
throw DatabaseNotConnectedException(); if (!snapshot.hasData)
} return const Center(
child: Text('The history is empty.\nTry searching for something!'),
return StreamBuilder<List<Search>>( );
stream: getAsyncStream(state), final List<Search> data = snapshot.data!;
builder: (context, snapshot) { return OpaqueBox(
if (!snapshot.hasData) { child: ListView.separated(
return Container(); itemCount: data.length + 1,
} itemBuilder: historyEntryWithData(data),
separatorBuilder: historyEntrySeparatorWithData(data),
final List<Search> data = snapshot.data!; ),
return OpaqueBox(
child: ListView.separated(
itemCount: data.length + 1,
itemBuilder: historyEntryWithData(data),
separatorBuilder: historyEntrySeparatorWithData(data),
),
);
},
); );
}, },
); );
} }
Stream<List<Search>> getAsyncStream(DatabaseState state) =>
((state as DatabaseConnected).database.box<Search>().query()
..order(Search_.timestamp, flags: Order.descending))
.watch(triggerImmediately: true)
.map((query) => query.find());
Widget Function(BuildContext, int) historyEntryWithData(List<Search> data) => Widget Function(BuildContext, int) historyEntryWithData(List<Search> data) =>
(context, index) { (context, index) {
if (index == 0) { if (index == 0) return Container();
return Container();
}
final Search search = data[index - 1]; final Search search = data[index - 1];
if (search.isKanji()) { return (search.isKanji)
return KanjiSearchItem( ? KanjiSearchItem(
result: search.kanjiQuery.target!, result: search.kanjiQuery!,
timestamp: search.timestamp, timestamp: search.timestamp,
); )
} else { : PhraseSearchItem(
return PhraseSearchItem( search: search.wordQuery!,
search: search.wordQuery.target!, timestamp: search.timestamp,
timestamp: search.timestamp, );
);
}
}; };
DateTime roundToDay(DateTime date) => DateTime roundToDay(DateTime date) =>

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:sembast/sembast.dart';
import '../../../bloc/database/database_bloc.dart';
import '../../../models/history/kanji_query.dart'; import '../../../models/history/kanji_query.dart';
import '../../../models/history/search.dart'; import '../../../models/history/search.dart';
import '../../../services/jisho_api/kanji_search.dart'; import '../../../services/jisho_api/kanji_search.dart';
@ -19,18 +20,18 @@ class KanjiResultPage extends StatelessWidget {
appBar: AppBar(), appBar: AppBar(),
body: FutureBuilder<KanjiResult>( body: FutureBuilder<KanjiResult>(
future: fetchKanji(kanjiSearchTerm), future: fetchKanji(kanjiSearchTerm),
builder: ( context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData) return LoadingScreen(); if (!snapshot.hasData) return const LoadingScreen();
if (snapshot.hasError) return ErrorWidget(snapshot.error!); if (snapshot.hasError) return ErrorWidget(snapshot.error!);
if (!addedToDatabase) { if (!addedToDatabase) {
(BlocProvider.of<DatabaseBloc>(context).state as DatabaseConnected) Search.store.add(
.database GetIt.instance.get<Database>(),
.box<Search>() Search.fromKanjiQuery(
.put(Search(timestamp: DateTime.now()) timestamp: DateTime.now(),
..kanjiQuery.target = KanjiQuery( kanjiQuery: KanjiQuery(kanji: kanjiSearchTerm),
kanji: kanjiSearchTerm, ).toJson(),
),); );
addedToDatabase = true; addedToDatabase = true;
} }

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:sembast/sembast.dart';
import '../../../bloc/database/database_bloc.dart';
import '../../../models/history/search.dart'; import '../../../models/history/search.dart';
import '../../../models/history/word_query.dart'; import '../../../models/history/word_query.dart';
import '../../../services/jisho_api/jisho_search.dart'; import '../../../services/jisho_api/jisho_search.dart';
@ -23,20 +24,18 @@ class SearchResultsPage extends StatelessWidget {
body: FutureBuilder<JishoAPIResult>( body: FutureBuilder<JishoAPIResult>(
future: results, future: results,
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData) return LoadingScreen(); if (!snapshot.hasData) return const LoadingScreen();
if (snapshot.hasError || snapshot.data!.data == null) if (snapshot.hasError || snapshot.data!.data == null)
return ErrorWidget(snapshot.error!); return ErrorWidget(snapshot.error!);
if (!addedToDatabase) { if (!addedToDatabase) {
(BlocProvider.of<DatabaseBloc>(context).state as DatabaseConnected) Search.store.add(
.database GetIt.instance.get<Database>(),
.box<Search>() Search.fromWordQuery(
.put( timestamp: DateTime.now(),
Search(timestamp: DateTime.now()) wordQuery: WordQuery(query: searchTerm),
..wordQuery.target = WordQuery( ).toJson(),
query: searchTerm, );
),
);
addedToDatabase = true; addedToDatabase = true;
} }

View File

@ -1,13 +1,13 @@
import 'package:confirm_dialog/confirm_dialog.dart'; import 'package:confirm_dialog/confirm_dialog.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:sembast/sembast.dart';
import 'package:settings_ui/settings_ui.dart'; import 'package:settings_ui/settings_ui.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import '../../bloc/database/database_bloc.dart';
import '../../bloc/theme/theme_bloc.dart'; import '../../bloc/theme/theme_bloc.dart';
import '../../models/history/search.dart'; import '../../models/history/search.dart';
import '../../models/themes/theme.dart'; import '../../models/themes/theme.dart';
import '../../objectbox.g.dart';
class SettingsView extends StatefulWidget { class SettingsView extends StatefulWidget {
const SettingsView({Key? key}) : super(key: key); const SettingsView({Key? key}) : super(key: key);
@ -41,11 +41,20 @@ class _SettingsViewState extends State<SettingsView> {
} }
/// Update stored preferences with values from setting page state /// Update stored preferences with values from setting page state
void _updatePrefs() { Future<void> _updatePrefs() async {
prefs.setBool('darkThemeEnabled', darkThemeEnabled); prefs.setBool('darkThemeEnabled', darkThemeEnabled);
prefs.setBool('autoThemeEnabled', autoThemeEnabled); prefs.setBool('autoThemeEnabled', autoThemeEnabled);
} }
Future<void> clearHistory(context) async {
final bool userIsSure = await confirm(context);
if (userIsSure) {
final Database db = GetIt.instance.get<Database>();
await Search.store.delete(db);
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final TextStyle _titleTextStyle = TextStyle( final TextStyle _titleTextStyle = TextStyle(
@ -133,12 +142,11 @@ class _SettingsViewState extends State<SettingsView> {
title: 'Export Data', title: 'Export Data',
enabled: false, enabled: false,
), ),
const SettingsTile( SettingsTile(
leading: Icon(Icons.delete), leading: const Icon(Icons.delete),
title: 'Clear History', title: 'Clear History',
onPressed: _clearHistory, onPressed: clearHistory,
titleTextStyle: TextStyle(color: Colors.red), titleTextStyle: const TextStyle(color: Colors.red),
enabled: false,
), ),
SettingsTile( SettingsTile(
leading: const Icon(Icons.delete), leading: const Icon(Icons.delete),
@ -153,15 +161,3 @@ class _SettingsViewState extends State<SettingsView> {
); );
} }
} }
void _clearHistory(context) {
confirm(context).then((userIsSure) {
if (userIsSure) {
final Store db =
(BlocProvider.of<DatabaseBloc>(context).state as DatabaseConnected)
.database;
// db.box<Search>().query().build().find()
db.box<Search>().removeAll();
}
});
}

View File

@ -42,7 +42,7 @@ packages:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.8.2" version: "2.8.1"
bloc: bloc:
dependency: transitive dependency: transitive
description: description:
@ -119,7 +119,7 @@ packages:
name: characters name: characters
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.1.0"
charcode: charcode:
dependency: transitive dependency: transitive
description: description:
@ -282,6 +282,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.2" version: "2.1.2"
get_it:
dependency: "direct main"
description:
name: get_it
url: "https://pub.dartlang.org"
source: hosted
version: "7.2.0"
glob: glob:
dependency: transitive dependency: transitive
description: description:
@ -372,7 +379,7 @@ packages:
name: matcher name: matcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.11" version: "0.12.10"
mdi: mdi:
dependency: "direct main" dependency: "direct main"
description: description:
@ -401,27 +408,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.0"
objectbox:
dependency: "direct main"
description:
name: objectbox
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
objectbox_flutter_libs:
dependency: "direct main"
description:
name: objectbox_flutter_libs
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
objectbox_generator:
dependency: "direct dev"
description:
name: objectbox_generator
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
@ -430,7 +416,7 @@ packages:
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
path: path:
dependency: transitive dependency: "direct main"
description: description:
name: path name: path
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
@ -534,6 +520,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.0"
sembast:
dependency: "direct main"
description:
name: sembast
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.1"
settings_ui: settings_ui:
dependency: "direct main" dependency: "direct main"
description: description:
@ -602,13 +595,6 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.99" version: "0.0.99"
source_gen:
dependency: transitive
description:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
@ -644,6 +630,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
synchronized:
dependency: transitive
description:
name: synchronized
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
@ -657,7 +650,7 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.3" version: "0.4.2"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -778,5 +771,5 @@ packages:
source: hosted source: hosted
version: "3.1.0" version: "3.1.0"
sdks: sdks:
dart: ">=2.13.0 <3.0.0" dart: ">=2.14.0 <3.0.0"
flutter: ">=2.0.0" flutter: ">=2.0.0"

View File

@ -13,21 +13,20 @@ dependencies:
sdk: flutter sdk: flutter
flutter_bloc: ^7.0.1 flutter_bloc: ^7.0.1
flutter_slidable: ^0.6.0 flutter_slidable: ^0.6.0
get_it: ^7.2.0
mdi: ^5.0.0-nullsafety.0 mdi: ^5.0.0-nullsafety.0
objectbox: ^1.1.1 path: ^1.8.0
objectbox_flutter_libs: ^1.1.1
path_provider: ^2.0.2 path_provider: ^2.0.2
sembast: ^3.1.1
settings_ui: ^1.0.0
shared_preferences: ^2.0.6 shared_preferences: ^2.0.6
unofficial_jisho_api: ^2.0.2 unofficial_jisho_api: ^2.0.2
url_launcher: ^6.0.9 url_launcher: ^6.0.9
settings_ui: ^1.0.0
dev_dependencies: dev_dependencies:
build_runner: ^2.0.6 build_runner: ^2.0.6
flutter_test: flutter_test:
sdk: flutter sdk: flutter
objectbox_generator: ^1.1.1
flutter_native_splash: ^1.2.0 flutter_native_splash: ^1.2.0
flutter_launcher_icons: "^0.9.1" flutter_launcher_icons: "^0.9.1"