Add import export functionality
This commit is contained in:
parent
7ad6540962
commit
edd3d7c9a9
|
@ -86,3 +86,35 @@ Future<void> addSearchToDatabase({
|
||||||
.toJson(),
|
.toJson(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Search> mergeSearches(List<Search> a, List<Search> b) {
|
||||||
|
final List<Search> result = [...a];
|
||||||
|
|
||||||
|
for (final Search search in b) {
|
||||||
|
late final Iterable<Search> matchingEntry;
|
||||||
|
if (search.isKanji) {
|
||||||
|
matchingEntry =
|
||||||
|
result.where((e) => e.kanjiQuery?.kanji == search.kanjiQuery!.kanji);
|
||||||
|
} else {
|
||||||
|
matchingEntry =
|
||||||
|
result.where((e) => e.wordQuery?.query == search.wordQuery!.query);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchingEntry.isEmpty) {
|
||||||
|
result.add(search);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final timestamps = [...matchingEntry.first.timestamps];
|
||||||
|
matchingEntry.first.timestamps.clear();
|
||||||
|
matchingEntry.first.timestamps.addAll(
|
||||||
|
(timestamps
|
||||||
|
..addAll(search.timestamps)
|
||||||
|
..sort())
|
||||||
|
.toSet()
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:confirm_dialog/confirm_dialog.dart';
|
import 'package:confirm_dialog/confirm_dialog.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_settings_ui/flutter_settings_ui.dart';
|
import 'package:flutter_settings_ui/flutter_settings_ui.dart';
|
||||||
import 'package:mdi/mdi.dart';
|
import 'package:mdi/mdi.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:sembast/sembast_io.dart';
|
||||||
|
import 'package:sembast/utils/sembast_import_export.dart';
|
||||||
|
|
||||||
import '../bloc/theme/theme_bloc.dart';
|
import '../bloc/theme/theme_bloc.dart';
|
||||||
import '../components/common/denshi_jisho_background.dart';
|
import '../components/common/denshi_jisho_background.dart';
|
||||||
import '../models/history/search.dart';
|
import '../models/history/search.dart';
|
||||||
import '../routing/routes.dart';
|
import '../routing/routes.dart';
|
||||||
|
import '../services/database.dart';
|
||||||
import '../services/open_webpage.dart';
|
import '../services/open_webpage.dart';
|
||||||
|
import '../services/snackbar.dart';
|
||||||
import '../settings.dart';
|
import '../settings.dart';
|
||||||
|
|
||||||
class SettingsView extends StatefulWidget {
|
class SettingsView extends StatefulWidget {
|
||||||
|
@ -19,6 +28,8 @@ class SettingsView extends StatefulWidget {
|
||||||
|
|
||||||
class _SettingsViewState extends State<SettingsView> {
|
class _SettingsViewState extends State<SettingsView> {
|
||||||
final Database db = GetIt.instance.get<Database>();
|
final Database db = GetIt.instance.get<Database>();
|
||||||
|
bool dataExportIsLoading = false;
|
||||||
|
bool dataImportIsLoading = false;
|
||||||
|
|
||||||
Future<void> clearHistory(context) async {
|
Future<void> clearHistory(context) async {
|
||||||
final bool userIsSure = await confirm(context);
|
final bool userIsSure = await confirm(context);
|
||||||
|
@ -40,6 +51,92 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
setState(() => autoThemeEnabled = b);
|
setState(() => autoThemeEnabled = b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> changeFont(context) async {
|
||||||
|
final int? i = await _chooseFromList(
|
||||||
|
list: [for (final font in JapaneseFont.values) font.name],
|
||||||
|
chosen: japaneseFont.index,
|
||||||
|
)(context);
|
||||||
|
if (i != null)
|
||||||
|
setState(() {
|
||||||
|
japaneseFont = JapaneseFont.values[i];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Can assume Android for time being
|
||||||
|
Future<void> exportData(context) async {
|
||||||
|
setState(() => dataExportIsLoading = true);
|
||||||
|
|
||||||
|
final path = (await getExternalStorageDirectory())!;
|
||||||
|
final dbData = await exportDatabase(db);
|
||||||
|
final file = File('${path.path}/jisho_data.json');
|
||||||
|
file.createSync(recursive: true);
|
||||||
|
await file.writeAsString(jsonEncode(dbData));
|
||||||
|
|
||||||
|
setState(() => dataExportIsLoading = false);
|
||||||
|
ScaffoldMessenger.of(context)
|
||||||
|
.showSnackBar(SnackBar(content: Text('Data exported to ${file.path}')));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Can assume Android for time being
|
||||||
|
Future<void> importData(context) async {
|
||||||
|
setState(() => dataImportIsLoading = true);
|
||||||
|
|
||||||
|
final path = await FilePicker.platform.pickFiles(
|
||||||
|
type: FileType.custom,
|
||||||
|
allowedExtensions: ['json'],
|
||||||
|
);
|
||||||
|
final file = File(path!.files[0].path!);
|
||||||
|
|
||||||
|
final List<Search> prevSearches = (await Search.store.find(db))
|
||||||
|
.map((e) => Search.fromJson(e.value! as Map<String, Object?>))
|
||||||
|
.toList();
|
||||||
|
late final List<Search> importedSearches;
|
||||||
|
try {
|
||||||
|
importedSearches = ((((jsonDecode(await file.readAsString())
|
||||||
|
as Map<String, Object?>)['stores']! as List)
|
||||||
|
.map((e) => e as Map)
|
||||||
|
.where((e) => e['name'] == 'search')
|
||||||
|
.first)['values'] as List)
|
||||||
|
.map((item) => Search.fromJson(item))
|
||||||
|
.toList();
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint(e.toString());
|
||||||
|
showSnackbar(
|
||||||
|
context,
|
||||||
|
"Couldn't read file. Did you choose the right one?",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Search> mergedSearches =
|
||||||
|
mergeSearches(prevSearches, importedSearches);
|
||||||
|
|
||||||
|
// print(mergedSearches);
|
||||||
|
|
||||||
|
await GetIt.instance.get<Database>().close();
|
||||||
|
GetIt.instance.unregister<Database>();
|
||||||
|
|
||||||
|
final importedDb = await importDatabase(
|
||||||
|
{
|
||||||
|
'sembast_export': 1,
|
||||||
|
'version': 1,
|
||||||
|
'stores': [
|
||||||
|
{
|
||||||
|
'name': 'search',
|
||||||
|
'keys': [for (var i = 1; i <= mergedSearches.length; i++) i],
|
||||||
|
'values': mergedSearches.map((e) => e.toJson()).toList(),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
databaseFactoryIo,
|
||||||
|
await databasePath(),
|
||||||
|
);
|
||||||
|
GetIt.instance.registerSingleton<Database>(importedDb);
|
||||||
|
|
||||||
|
setState(() => dataImportIsLoading = false);
|
||||||
|
showSnackbar(context, 'Data imported successfully');
|
||||||
|
}
|
||||||
|
|
||||||
Future<int?> Function(BuildContext) _chooseFromList({
|
Future<int?> Function(BuildContext) _chooseFromList({
|
||||||
required List<String> list,
|
required List<String> list,
|
||||||
int? chosen,
|
int? chosen,
|
||||||
|
@ -89,9 +186,7 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
SettingsTile.switchTile(
|
SettingsTile.switchTile(
|
||||||
title: 'Use romaji',
|
title: 'Use romaji',
|
||||||
leading: const Icon(Mdi.alphabetical),
|
leading: const Icon(Mdi.alphabetical),
|
||||||
onToggle: (b) {
|
onToggle: (b) => setState(() => romajiEnabled = b),
|
||||||
setState(() => romajiEnabled = b);
|
|
||||||
},
|
|
||||||
switchValue: romajiEnabled,
|
switchValue: romajiEnabled,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
switchActiveColor: AppTheme.jishoGreen.background,
|
switchActiveColor: AppTheme.jishoGreen.background,
|
||||||
|
@ -99,9 +194,7 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
SettingsTile.switchTile(
|
SettingsTile.switchTile(
|
||||||
title: 'Extensive search',
|
title: 'Extensive search',
|
||||||
leading: const Icon(Icons.downloading),
|
leading: const Icon(Icons.downloading),
|
||||||
onToggle: (b) {
|
onToggle: (b) => setState(() => extensiveSearchEnabled = b),
|
||||||
setState(() => extensiveSearchEnabled = b);
|
|
||||||
},
|
|
||||||
switchValue: extensiveSearchEnabled,
|
switchValue: extensiveSearchEnabled,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
switchActiveColor: AppTheme.jishoGreen.background,
|
switchActiveColor: AppTheme.jishoGreen.background,
|
||||||
|
@ -114,18 +207,7 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
SettingsTile(
|
SettingsTile(
|
||||||
title: 'Japanese font',
|
title: 'Japanese font',
|
||||||
leading: const Icon(Icons.format_size),
|
leading: const Icon(Icons.format_size),
|
||||||
onPressed: (context) async {
|
onPressed: changeFont,
|
||||||
final int? i = await _chooseFromList(
|
|
||||||
list: [
|
|
||||||
for (final font in JapaneseFont.values) font.name
|
|
||||||
],
|
|
||||||
chosen: japaneseFont.index,
|
|
||||||
)(context);
|
|
||||||
if (i != null)
|
|
||||||
setState(() {
|
|
||||||
japaneseFont = JapaneseFont.values[i];
|
|
||||||
});
|
|
||||||
},
|
|
||||||
theme: theme,
|
theme: theme,
|
||||||
trailing: Text(japaneseFont.name),
|
trailing: Text(japaneseFont.name),
|
||||||
// subtitle:
|
// subtitle:
|
||||||
|
@ -134,6 +216,7 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
title: 'Theme',
|
title: 'Theme',
|
||||||
titleTextStyle: _titleTextStyle,
|
titleTextStyle: _titleTextStyle,
|
||||||
|
@ -161,6 +244,7 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
// TODO: This will be left commented until caching is implemented
|
// TODO: This will be left commented until caching is implemented
|
||||||
// SettingsSection(
|
// SettingsSection(
|
||||||
// title: 'Cache',
|
// title: 'Cache',
|
||||||
|
@ -196,14 +280,31 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
// ),
|
// ),
|
||||||
// ],
|
// ],
|
||||||
// ),
|
// ),
|
||||||
|
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
title: 'Data',
|
title: 'Data',
|
||||||
titleTextStyle: _titleTextStyle,
|
titleTextStyle: _titleTextStyle,
|
||||||
tiles: <SettingsTile>[
|
tiles: <SettingsTile>[
|
||||||
|
SettingsTile(
|
||||||
|
leading: const Icon(Icons.file_upload),
|
||||||
|
title: 'Import Data',
|
||||||
|
onPressed: importData,
|
||||||
|
enabled: Platform.isAndroid,
|
||||||
|
subtitle:
|
||||||
|
Platform.isAndroid ? null : 'Not available on iOS yet',
|
||||||
|
subtitleWidget: dataImportIsLoading
|
||||||
|
? const LinearProgressIndicator()
|
||||||
|
: null,
|
||||||
|
),
|
||||||
SettingsTile(
|
SettingsTile(
|
||||||
leading: const Icon(Icons.file_download),
|
leading: const Icon(Icons.file_download),
|
||||||
title: 'Export Data',
|
title: 'Export Data',
|
||||||
enabled: false,
|
enabled: Platform.isAndroid,
|
||||||
|
subtitle:
|
||||||
|
Platform.isAndroid ? null : 'Not available on iOS yet',
|
||||||
|
subtitleWidget: dataExportIsLoading
|
||||||
|
? const LinearProgressIndicator()
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
SettingsTile(
|
SettingsTile(
|
||||||
leading: const Icon(Icons.delete),
|
leading: const Icon(Icons.delete),
|
||||||
|
@ -220,6 +321,7 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
title: 'Info',
|
title: 'Info',
|
||||||
titleTextStyle: _titleTextStyle,
|
titleTextStyle: _titleTextStyle,
|
||||||
|
|
|
@ -6,10 +6,14 @@ import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:sembast/sembast.dart';
|
import 'package:sembast/sembast.dart';
|
||||||
import 'package:sembast/sembast_io.dart';
|
import 'package:sembast/sembast_io.dart';
|
||||||
|
|
||||||
Future<void> setupDatabase() async {
|
Future<String> databasePath() async {
|
||||||
final Directory appDocDir = await getApplicationDocumentsDirectory();
|
final Directory appDocDir = await getApplicationDocumentsDirectory();
|
||||||
if (!appDocDir.existsSync()) appDocDir.createSync(recursive: true);
|
if (!appDocDir.existsSync()) appDocDir.createSync(recursive: true);
|
||||||
|
return join(appDocDir.path, 'sembast.db');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setupDatabase() async {
|
||||||
final Database database =
|
final Database database =
|
||||||
await databaseFactoryIo.openDatabase(join(appDocDir.path, 'sembast.db'));
|
await databaseFactoryIo.openDatabase(await databasePath());
|
||||||
GetIt.instance.registerSingleton<Database>(database);
|
GetIt.instance.registerSingleton<Database>(database);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
void showSnackbar(BuildContext context, String text) =>
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(text)));
|
230
pubspec.lock
230
pubspec.lock
|
@ -7,14 +7,14 @@ packages:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "33.0.0"
|
version: "31.0.0"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "2.8.0"
|
||||||
animated_size_and_fade:
|
animated_size_and_fade:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -28,7 +28,7 @@ packages:
|
||||||
name: archive
|
name: archive
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.8"
|
version: "3.3.0"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -56,7 +56,7 @@ packages:
|
||||||
name: bloc
|
name: bloc
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.0.2"
|
version: "8.0.3"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -70,7 +70,7 @@ packages:
|
||||||
name: build
|
name: build
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.1"
|
version: "2.3.0"
|
||||||
build_config:
|
build_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -84,7 +84,7 @@ packages:
|
||||||
name: build_daemon
|
name: build_daemon
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.1.0"
|
||||||
build_resolvers:
|
build_resolvers:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -98,7 +98,7 @@ packages:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.7"
|
version: "2.1.10"
|
||||||
build_runner_core:
|
build_runner_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -119,7 +119,7 @@ packages:
|
||||||
name: built_value
|
name: built_value
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.1.3"
|
version: "8.2.3"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -175,7 +175,7 @@ packages:
|
||||||
name: confirm_dialog
|
name: confirm_dialog
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.1"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -183,13 +183,20 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.0.1"
|
||||||
|
coverage:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: coverage
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: crypto
|
name: crypto
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.0.2"
|
||||||
csslib:
|
csslib:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -232,6 +239,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.2"
|
version: "6.1.2"
|
||||||
|
file_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_picker
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.5.1"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -264,7 +278,14 @@ packages:
|
||||||
name: flutter_native_splash
|
name: flutter_native_splash
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.3"
|
version: "2.1.6"
|
||||||
|
flutter_plugin_android_lifecycle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_plugin_android_lifecycle
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.5"
|
||||||
flutter_settings_ui:
|
flutter_settings_ui:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -351,7 +372,7 @@ packages:
|
||||||
name: http_multi_server
|
name: http_multi_server
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.2.0"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -365,7 +386,7 @@ packages:
|
||||||
name: image
|
name: image
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.3"
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -386,28 +407,35 @@ packages:
|
||||||
name: json_annotation
|
name: json_annotation
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.0"
|
version: "4.5.0"
|
||||||
just_audio:
|
just_audio:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: just_audio
|
name: just_audio
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.9.18"
|
version: "0.9.21"
|
||||||
just_audio_platform_interface:
|
just_audio_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: just_audio_platform_interface
|
name: just_audio_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "4.1.0"
|
||||||
just_audio_web:
|
just_audio_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: just_audio_web
|
name: just_audio_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.3"
|
version: "0.4.7"
|
||||||
|
lint:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: lint
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.8.2"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -422,6 +450,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.11"
|
version: "0.12.11"
|
||||||
|
material_color_utilities:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: material_color_utilities
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.3"
|
||||||
mdi:
|
mdi:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -442,7 +477,7 @@ packages:
|
||||||
name: mime
|
name: mime
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.2"
|
||||||
nested:
|
nested:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -450,6 +485,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
node_preamble:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: node_preamble
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -484,21 +526,21 @@ packages:
|
||||||
name: path_provider
|
name: path_provider
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.8"
|
version: "2.0.9"
|
||||||
path_provider_android:
|
path_provider_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.11"
|
version: "2.0.13"
|
||||||
path_provider_ios:
|
path_provider_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_ios
|
name: path_provider_ios
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.7"
|
version: "2.0.8"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -575,7 +617,7 @@ packages:
|
||||||
name: pub_semver
|
name: pub_semver
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.1"
|
||||||
pubspec_parse:
|
pubspec_parse:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -596,42 +638,84 @@ packages:
|
||||||
name: sembast
|
name: sembast
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.1+1"
|
version: "3.2.0"
|
||||||
|
share_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: share_plus
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.4"
|
||||||
|
share_plus_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: share_plus_linux
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
|
share_plus_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: share_plus_macos
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
|
share_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: share_plus_platform_interface
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
|
share_plus_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: share_plus_web
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
|
share_plus_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: share_plus_windows
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.12"
|
version: "2.0.13"
|
||||||
shared_preferences_android:
|
shared_preferences_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_android
|
name: shared_preferences_android
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.10"
|
version: "2.0.11"
|
||||||
shared_preferences_ios:
|
shared_preferences_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_ios
|
name: shared_preferences_ios
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.9"
|
version: "2.1.0"
|
||||||
shared_preferences_linux:
|
shared_preferences_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_linux
|
name: shared_preferences_linux
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.4"
|
version: "2.1.0"
|
||||||
shared_preferences_macos:
|
shared_preferences_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_macos
|
name: shared_preferences_macos
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.0.3"
|
||||||
shared_preferences_platform_interface:
|
shared_preferences_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -652,14 +736,28 @@ packages:
|
||||||
name: shared_preferences_windows
|
name: shared_preferences_windows
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.4"
|
version: "2.1.0"
|
||||||
shelf:
|
shelf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shelf
|
name: shelf
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.3.0"
|
||||||
|
shelf_packages_handler:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_packages_handler
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
|
shelf_static:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_static
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
shelf_web_socket:
|
shelf_web_socket:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -679,6 +777,20 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.99"
|
version: "0.0.99"
|
||||||
|
source_map_stack_trace:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_map_stack_trace
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
source_maps:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_maps
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.10.10"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -720,7 +832,7 @@ packages:
|
||||||
name: synchronized
|
name: synchronized
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0+2"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -728,13 +840,27 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
|
test:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: test
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.19.5"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
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.8"
|
||||||
|
test_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: test_core
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.9"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -769,35 +895,35 @@ packages:
|
||||||
name: url_launcher
|
name: url_launcher
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.18"
|
version: "6.1.0"
|
||||||
url_launcher_android:
|
url_launcher_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_android
|
name: url_launcher_android
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.14"
|
version: "6.0.16"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_ios
|
name: url_launcher_ios
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.14"
|
version: "6.0.15"
|
||||||
url_launcher_linux:
|
url_launcher_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_linux
|
name: url_launcher_linux
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "3.0.0"
|
||||||
url_launcher_macos:
|
url_launcher_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_macos
|
name: url_launcher_macos
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "3.0.0"
|
||||||
url_launcher_platform_interface:
|
url_launcher_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -811,21 +937,21 @@ packages:
|
||||||
name: url_launcher_web
|
name: url_launcher_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.6"
|
version: "2.0.9"
|
||||||
url_launcher_windows:
|
url_launcher_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_windows
|
name: url_launcher_windows
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "3.0.0"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.5"
|
version: "3.0.6"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -833,6 +959,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
|
vm_service:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "7.5.0"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -846,21 +979,28 @@ packages:
|
||||||
name: web_socket_channel
|
name: web_socket_channel
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.2.0"
|
||||||
|
webkit_inspection_protocol:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webkit_inspection_protocol
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.3"
|
version: "2.5.2"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xdg_directories
|
name: xdg_directories
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.2.0+1"
|
||||||
xml:
|
xml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -876,5 +1016,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.15.1 <3.0.0"
|
dart: ">=2.16.0 <3.0.0"
|
||||||
flutter: ">=2.5.0"
|
flutter: ">=2.10.0"
|
||||||
|
|
|
@ -10,9 +10,11 @@ dependencies:
|
||||||
collection: ^1.15.0
|
collection: ^1.15.0
|
||||||
confirm_dialog: ^1.0.0
|
confirm_dialog: ^1.0.0
|
||||||
division: ^0.9.0
|
division: ^0.9.0
|
||||||
|
file_picker: ^4.5.1
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_bloc: ^8.0.0
|
flutter_bloc: ^8.0.0
|
||||||
|
flutter_settings_ui: ^2.0.1
|
||||||
flutter_slidable: ^1.1.0
|
flutter_slidable: ^1.1.0
|
||||||
flutter_svg: ^1.0.2
|
flutter_svg: ^1.0.2
|
||||||
get_it: ^7.2.0
|
get_it: ^7.2.0
|
||||||
|
@ -22,7 +24,8 @@ dependencies:
|
||||||
path: ^1.8.0
|
path: ^1.8.0
|
||||||
path_provider: ^2.0.2
|
path_provider: ^2.0.2
|
||||||
sembast: ^3.1.1
|
sembast: ^3.1.1
|
||||||
flutter_settings_ui: ^2.0.1
|
share_plus: ^4.0.4
|
||||||
|
test: ^1.19.5
|
||||||
shared_preferences: ^2.0.6
|
shared_preferences: ^2.0.6
|
||||||
signature: ^5.0.0
|
signature: ^5.0.0
|
||||||
unofficial_jisho_api: ^2.0.4
|
unofficial_jisho_api: ^2.0.4
|
||||||
|
@ -32,8 +35,8 @@ dev_dependencies:
|
||||||
build_runner: ^2.0.6
|
build_runner: ^2.0.6
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_native_splash: ^1.2.0
|
flutter_native_splash: ^2.1.6
|
||||||
flutter_launcher_icons: "^0.9.1"
|
flutter_launcher_icons: "^0.9.2"
|
||||||
|
|
||||||
flutter_icons:
|
flutter_icons:
|
||||||
android: "launcher_icon"
|
android: "launcher_icon"
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import 'package:jisho_study_tool/models/history/kanji_query.dart';
|
||||||
|
import 'package:jisho_study_tool/models/history/search.dart';
|
||||||
|
import 'package:jisho_study_tool/models/history/word_query.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('Search', () {
|
||||||
|
final List<Search> searches = [
|
||||||
|
Search.fromKanjiQuery(kanjiQuery: KanjiQuery(kanji: '何')),
|
||||||
|
Search.fromWordQuery(wordQuery: WordQuery(query: 'テスト')),
|
||||||
|
Search.fromJson({'timestamps':[1648658269960],'lastTimestamp':1648658269960,'wordQuery':null,'kanjiQuery':{'kanji':'日'}}),
|
||||||
|
Search.fromJson({'timestamps':[1648674967535],'lastTimestamp':1648674967535,'wordQuery':{'query':'黙る'},'kanjiQuery':null}),
|
||||||
|
Search.fromJson({'timestamps':[1649079907766],'lastTimestamp':1649079907766,'wordQuery':{'query':'seal'},'kanjiQuery':null}),
|
||||||
|
Search.fromJson({'timestamps':[1649082072981],'lastTimestamp':1649082072981,'wordQuery':{'query':'感涙屋'},'kanjiQuery':null}),
|
||||||
|
Search.fromJson({'timestamps':[1644951726777,1644951732749],'lastTimestamp':1644951732749,'wordQuery':{'query':'呑める'},'kanjiQuery':null}),
|
||||||
|
];
|
||||||
|
test("mergeSearches with empty lists doesn't add data", () {
|
||||||
|
final List<Search> merged1 = mergeSearches(searches, []);
|
||||||
|
final List<Search> merged2 = mergeSearches([], searches);
|
||||||
|
for (int i = 0; i < searches.length; i++) {
|
||||||
|
expect(merged1[i], searches[i]);
|
||||||
|
expect(merged2[i], searches[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("mergeSearches with the same list doesn't add data", () {
|
||||||
|
final List<Search> merged = mergeSearches(searches, searches);
|
||||||
|
for (int i = 0; i < searches.length; i++) {
|
||||||
|
expect(merged[i], searches[i]);
|
||||||
|
}
|
||||||
|
expect(mergeSearches(searches, searches), searches);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue