Add import export functionality
This commit is contained in:
parent
7ad6540962
commit
edd3d7c9a9
|
@ -86,3 +86,35 @@ Future<void> addSearchToDatabase({
|
|||
.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:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_settings_ui/flutter_settings_ui.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 '../components/common/denshi_jisho_background.dart';
|
||||
import '../models/history/search.dart';
|
||||
import '../routing/routes.dart';
|
||||
import '../services/database.dart';
|
||||
import '../services/open_webpage.dart';
|
||||
import '../services/snackbar.dart';
|
||||
import '../settings.dart';
|
||||
|
||||
class SettingsView extends StatefulWidget {
|
||||
|
@ -19,6 +28,8 @@ class SettingsView extends StatefulWidget {
|
|||
|
||||
class _SettingsViewState extends State<SettingsView> {
|
||||
final Database db = GetIt.instance.get<Database>();
|
||||
bool dataExportIsLoading = false;
|
||||
bool dataImportIsLoading = false;
|
||||
|
||||
Future<void> clearHistory(context) async {
|
||||
final bool userIsSure = await confirm(context);
|
||||
|
@ -40,6 +51,92 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
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({
|
||||
required List<String> list,
|
||||
int? chosen,
|
||||
|
@ -89,9 +186,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
SettingsTile.switchTile(
|
||||
title: 'Use romaji',
|
||||
leading: const Icon(Mdi.alphabetical),
|
||||
onToggle: (b) {
|
||||
setState(() => romajiEnabled = b);
|
||||
},
|
||||
onToggle: (b) => setState(() => romajiEnabled = b),
|
||||
switchValue: romajiEnabled,
|
||||
theme: theme,
|
||||
switchActiveColor: AppTheme.jishoGreen.background,
|
||||
|
@ -99,9 +194,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
SettingsTile.switchTile(
|
||||
title: 'Extensive search',
|
||||
leading: const Icon(Icons.downloading),
|
||||
onToggle: (b) {
|
||||
setState(() => extensiveSearchEnabled = b);
|
||||
},
|
||||
onToggle: (b) => setState(() => extensiveSearchEnabled = b),
|
||||
switchValue: extensiveSearchEnabled,
|
||||
theme: theme,
|
||||
switchActiveColor: AppTheme.jishoGreen.background,
|
||||
|
@ -114,18 +207,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
SettingsTile(
|
||||
title: 'Japanese font',
|
||||
leading: const Icon(Icons.format_size),
|
||||
onPressed: (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];
|
||||
});
|
||||
},
|
||||
onPressed: changeFont,
|
||||
theme: theme,
|
||||
trailing: Text(japaneseFont.name),
|
||||
// subtitle:
|
||||
|
@ -134,6 +216,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
),
|
||||
],
|
||||
),
|
||||
|
||||
SettingsSection(
|
||||
title: 'Theme',
|
||||
titleTextStyle: _titleTextStyle,
|
||||
|
@ -161,6 +244,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
),
|
||||
],
|
||||
),
|
||||
|
||||
// TODO: This will be left commented until caching is implemented
|
||||
// SettingsSection(
|
||||
// title: 'Cache',
|
||||
|
@ -196,14 +280,31 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
// ),
|
||||
// ],
|
||||
// ),
|
||||
|
||||
SettingsSection(
|
||||
title: 'Data',
|
||||
titleTextStyle: _titleTextStyle,
|
||||
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(
|
||||
leading: const Icon(Icons.file_download),
|
||||
title: 'Export Data',
|
||||
enabled: false,
|
||||
enabled: Platform.isAndroid,
|
||||
subtitle:
|
||||
Platform.isAndroid ? null : 'Not available on iOS yet',
|
||||
subtitleWidget: dataExportIsLoading
|
||||
? const LinearProgressIndicator()
|
||||
: null,
|
||||
),
|
||||
SettingsTile(
|
||||
leading: const Icon(Icons.delete),
|
||||
|
@ -220,6 +321,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
)
|
||||
],
|
||||
),
|
||||
|
||||
SettingsSection(
|
||||
title: 'Info',
|
||||
titleTextStyle: _titleTextStyle,
|
||||
|
|
|
@ -6,10 +6,14 @@ import 'package:path_provider/path_provider.dart';
|
|||
import 'package:sembast/sembast.dart';
|
||||
import 'package:sembast/sembast_io.dart';
|
||||
|
||||
Future<void> setupDatabase() async {
|
||||
Future<String> databasePath() async {
|
||||
final Directory appDocDir = await getApplicationDocumentsDirectory();
|
||||
if (!appDocDir.existsSync()) appDocDir.createSync(recursive: true);
|
||||
return join(appDocDir.path, 'sembast.db');
|
||||
}
|
||||
|
||||
Future<void> setupDatabase() async {
|
||||
final Database database =
|
||||
await databaseFactoryIo.openDatabase(join(appDocDir.path, 'sembast.db'));
|
||||
await databaseFactoryIo.openDatabase(await databasePath());
|
||||
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
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "33.0.0"
|
||||
version: "31.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "2.8.0"
|
||||
animated_size_and_fade:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -28,7 +28,7 @@ packages:
|
|||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.8"
|
||||
version: "3.3.0"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -56,7 +56,7 @@ packages:
|
|||
name: bloc
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "8.0.2"
|
||||
version: "8.0.3"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -70,7 +70,7 @@ packages:
|
|||
name: build
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
version: "2.3.0"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -84,7 +84,7 @@ packages:
|
|||
name: build_daemon
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "3.1.0"
|
||||
build_resolvers:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -98,7 +98,7 @@ packages:
|
|||
name: build_runner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.1.10"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -119,7 +119,7 @@ packages:
|
|||
name: built_value
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "8.1.3"
|
||||
version: "8.2.3"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -175,7 +175,7 @@ packages:
|
|||
name: confirm_dialog
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.0.1"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -183,13 +183,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
coverage:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: coverage
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "3.0.2"
|
||||
csslib:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -232,6 +239,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -264,7 +278,14 @@ packages:
|
|||
name: flutter_native_splash
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -351,7 +372,7 @@ packages:
|
|||
name: http_multi_server
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "3.2.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -365,7 +386,7 @@ packages:
|
|||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.1.3"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -386,28 +407,35 @@ packages:
|
|||
name: json_annotation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.4.0"
|
||||
version: "4.5.0"
|
||||
just_audio:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: just_audio
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.9.18"
|
||||
version: "0.9.21"
|
||||
just_audio_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: just_audio_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
version: "4.1.0"
|
||||
just_audio_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: just_audio_web
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -422,6 +450,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -442,7 +477,7 @@ packages:
|
|||
name: mime
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
version: "1.0.2"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -450,6 +485,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -484,21 +526,21 @@ packages:
|
|||
name: path_provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.8"
|
||||
version: "2.0.9"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.11"
|
||||
version: "2.0.13"
|
||||
path_provider_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_ios
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.7"
|
||||
version: "2.0.8"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -575,7 +617,7 @@ packages:
|
|||
name: pub_semver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.1"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -596,42 +638,84 @@ packages:
|
|||
name: sembast
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.12"
|
||||
version: "2.0.13"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.10"
|
||||
version: "2.0.11"
|
||||
shared_preferences_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_ios
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.9"
|
||||
version: "2.1.0"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
version: "2.1.0"
|
||||
shared_preferences_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
version: "2.0.3"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -652,14 +736,28 @@ packages:
|
|||
name: shared_preferences_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
version: "2.1.0"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -679,6 +777,20 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -720,7 +832,7 @@ packages:
|
|||
name: synchronized
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.0.0+2"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -728,13 +840,27 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
test:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: test
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.19.5"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -769,35 +895,35 @@ packages:
|
|||
name: url_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.18"
|
||||
version: "6.1.0"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.14"
|
||||
version: "6.0.16"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.14"
|
||||
version: "6.0.15"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
version: "3.0.0"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
version: "3.0.0"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -811,21 +937,21 @@ packages:
|
|||
name: url_launcher_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.6"
|
||||
version: "2.0.9"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
version: "3.0.0"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
version: "3.0.6"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -833,6 +959,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "7.5.0"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -846,21 +979,28 @@ packages:
|
|||
name: web_socket_channel
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
version: "2.5.2"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
version: "0.2.0+1"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -876,5 +1016,5 @@ packages:
|
|||
source: hosted
|
||||
version: "3.1.0"
|
||||
sdks:
|
||||
dart: ">=2.15.1 <3.0.0"
|
||||
flutter: ">=2.5.0"
|
||||
dart: ">=2.16.0 <3.0.0"
|
||||
flutter: ">=2.10.0"
|
||||
|
|
|
@ -10,9 +10,11 @@ dependencies:
|
|||
collection: ^1.15.0
|
||||
confirm_dialog: ^1.0.0
|
||||
division: ^0.9.0
|
||||
file_picker: ^4.5.1
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_bloc: ^8.0.0
|
||||
flutter_settings_ui: ^2.0.1
|
||||
flutter_slidable: ^1.1.0
|
||||
flutter_svg: ^1.0.2
|
||||
get_it: ^7.2.0
|
||||
|
@ -22,7 +24,8 @@ dependencies:
|
|||
path: ^1.8.0
|
||||
path_provider: ^2.0.2
|
||||
sembast: ^3.1.1
|
||||
flutter_settings_ui: ^2.0.1
|
||||
share_plus: ^4.0.4
|
||||
test: ^1.19.5
|
||||
shared_preferences: ^2.0.6
|
||||
signature: ^5.0.0
|
||||
unofficial_jisho_api: ^2.0.4
|
||||
|
@ -32,8 +35,8 @@ dev_dependencies:
|
|||
build_runner: ^2.0.6
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_native_splash: ^1.2.0
|
||||
flutter_launcher_icons: "^0.9.1"
|
||||
flutter_native_splash: ^2.1.6
|
||||
flutter_launcher_icons: "^0.9.2"
|
||||
|
||||
flutter_icons:
|
||||
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