mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-06 08:30:29 +00:00
feat: migrate shared_preferences to hive (#343)
This commit is contained in:
15 files changed
+247
-143
No files matched your search
@@ -63,4 +63,8 @@ windows/flutter/generated_plugin_registrant.cc
|
||||
windows/flutter/generated_plugin_registrant.h
|
||||
windows/flutter/generated_plugins.cmake
|
||||
|
||||
/extensions
|
||||
/extensions
|
||||
|
||||
# Hive database files
|
||||
database.hive
|
||||
database.lock
|
||||
@@ -1,8 +0,0 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ApiProvider extends GetConnect {
|
||||
@override
|
||||
void onInit() {
|
||||
httpClient.baseUrl = 'YOUR-API-URL';
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@ import 'package:app_links/app_links.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:gopeed/database/entity.dart';
|
||||
import 'package:lecle_downloads_path_provider/lecle_downloads_path_provider.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:tray_manager/tray_manager.dart';
|
||||
import 'package:uri_to_file/uri_to_file.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
@@ -17,18 +17,14 @@ import 'package:window_manager/window_manager.dart';
|
||||
import '../../../../api/api.dart';
|
||||
import '../../../../api/model/downloader_config.dart';
|
||||
import '../../../../core/common/start_config.dart';
|
||||
import '../../../../database/database.dart';
|
||||
import '../../../../i18n/message.dart';
|
||||
import '../../../../util/locale_manager.dart';
|
||||
import '../../../../util/log_util.dart';
|
||||
import '../../../../util/package_info.dart';
|
||||
import '../../../../util/util.dart';
|
||||
import '../../../../util/window_util.dart' as windows_util;
|
||||
import '../../../routes/app_pages.dart';
|
||||
|
||||
const _startConfigNetwork = "start.network";
|
||||
const _startConfigAddress = "start.address";
|
||||
const _startConfigApiToken = "start.apiToken";
|
||||
|
||||
const unixSocketPath = 'gopeed.sock';
|
||||
|
||||
const allTrackerSubscribeUrls = [
|
||||
@@ -127,17 +123,18 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
||||
|
||||
@override
|
||||
void onWindowMaximize() {
|
||||
windows_util.saveState(isMaximized: true);
|
||||
Database.instance.saveWindowState(WindowStateEntity(isMaximized: true));
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowUnmaximize() {
|
||||
windows_util.saveState(isMaximized: false);
|
||||
Database.instance.saveWindowState(WindowStateEntity(isMaximized: false));
|
||||
}
|
||||
|
||||
final _windowsResizeSave = Util.debounce(() async {
|
||||
final size = await windowManager.getSize();
|
||||
windows_util.saveState(width: size.width, height: size.height);
|
||||
Database.instance.saveWindowState(
|
||||
WindowStateEntity(width: size.width, height: size.height));
|
||||
}, 500);
|
||||
|
||||
@override
|
||||
@@ -307,13 +304,10 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
||||
|
||||
Future<void> loadStartConfig() async {
|
||||
final defaultCfg = await _initDefaultStartConfig();
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
startConfig.value.network =
|
||||
prefs.getString(_startConfigNetwork) ?? defaultCfg.network;
|
||||
startConfig.value.address =
|
||||
prefs.getString(_startConfigAddress) ?? defaultCfg.address;
|
||||
startConfig.value.apiToken =
|
||||
prefs.getString(_startConfigApiToken) ?? defaultCfg.apiToken;
|
||||
final saveCfg = Database.instance.getStartConfig();
|
||||
startConfig.value.network = saveCfg?.network ?? defaultCfg.network;
|
||||
startConfig.value.address = saveCfg?.address ?? defaultCfg.address;
|
||||
startConfig.value.apiToken = saveCfg?.apiToken ?? defaultCfg.apiToken;
|
||||
}
|
||||
|
||||
Future<void> loadDownloaderConfig() async {
|
||||
@@ -433,10 +427,10 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
||||
}
|
||||
|
||||
Future<void> saveConfig() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_startConfigNetwork, startConfig.value.network);
|
||||
await prefs.setString(_startConfigAddress, startConfig.value.address);
|
||||
await prefs.setString(_startConfigApiToken, startConfig.value.apiToken);
|
||||
Database.instance.saveStartConfig(StartConfigEntity(
|
||||
network: startConfig.value.network,
|
||||
address: startConfig.value.address,
|
||||
apiToken: startConfig.value.apiToken));
|
||||
await putConfig(downloaderConfig.value);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import '../../../../api/model/create_task.dart';
|
||||
import '../../../../api/model/options.dart';
|
||||
import '../../../../api/model/request.dart';
|
||||
import '../../../../api/model/resolve_result.dart';
|
||||
import '../../../../database/database.dart';
|
||||
import '../../../../util/input_formatter.dart';
|
||||
import '../../../../util/message.dart';
|
||||
import '../../../../util/util.dart';
|
||||
@@ -19,7 +20,6 @@ import '../../../routes/app_pages.dart';
|
||||
import '../../../views/directory_selector.dart';
|
||||
import '../../../views/file_list_view.dart';
|
||||
import '../../app/controllers/app_controller.dart';
|
||||
import '../../history/controller/history_controller.dart';
|
||||
import '../../history/views/history_view.dart';
|
||||
import '../controllers/create_controller.dart';
|
||||
|
||||
@@ -35,7 +35,6 @@ class CreateView extends GetView<CreateController> {
|
||||
final _httpCookieController = TextEditingController();
|
||||
final _httpRefererController = TextEditingController();
|
||||
final _btTrackerController = TextEditingController();
|
||||
final _historyController = HistoryController();
|
||||
|
||||
final _availableSchemes = ["http:", "https:", "magnet:"];
|
||||
|
||||
@@ -168,10 +167,7 @@ class CreateView extends GetView<CreateController> {
|
||||
icon: const Icon(Icons.history_rounded),
|
||||
onPressed: () async {
|
||||
List<String> resultOfHistories =
|
||||
await _historyController.getAllHistory();
|
||||
// reversing: display last entered history first
|
||||
List<String> reverseResultOfHistories =
|
||||
resultOfHistories.reversed.toList();
|
||||
Database.instance.getCreateHistory() ?? [];
|
||||
// show dialog box to list history
|
||||
if (context.mounted) {
|
||||
showGeneralDialog(
|
||||
@@ -183,16 +179,14 @@ class CreateView extends GetView<CreateController> {
|
||||
opacity: a1.value,
|
||||
child: HistoryView(
|
||||
isHistoryListEmpty:
|
||||
reverseResultOfHistories.isEmpty,
|
||||
resultOfHistories.isEmpty,
|
||||
historyList: ListView.builder(
|
||||
itemCount:
|
||||
reverseResultOfHistories.length,
|
||||
itemCount: resultOfHistories.length,
|
||||
itemBuilder: (context, index) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
_urlController.text =
|
||||
reverseResultOfHistories[
|
||||
index];
|
||||
resultOfHistories[index];
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: MouseRegion(
|
||||
@@ -217,9 +211,7 @@ class CreateView extends GetView<CreateController> {
|
||||
10.0),
|
||||
),
|
||||
child: Text(
|
||||
reverseResultOfHistories[
|
||||
index]
|
||||
.toString(),
|
||||
resultOfHistories[index],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -419,7 +411,7 @@ class CreateView extends GetView<CreateController> {
|
||||
// Add url to the history
|
||||
if (!isWebFileChosen) {
|
||||
for (final url in urls) {
|
||||
_historyController.addHistory(url);
|
||||
Database.instance.saveCreateHistory(url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class HistoryController {
|
||||
// Get History in List<String>
|
||||
Future<List<String>> getAllHistory() async {
|
||||
SharedPreferences preferences = await SharedPreferences.getInstance();
|
||||
List<String>? historyList = preferences.getStringList('history');
|
||||
if(historyList == null) {
|
||||
return [];
|
||||
}
|
||||
return historyList;
|
||||
}
|
||||
|
||||
// Get Existing History & Add New History
|
||||
void addHistory(String historyText) async {
|
||||
SharedPreferences preferences = await SharedPreferences.getInstance();
|
||||
List<String> existingHistoryData = await getAllHistory();
|
||||
existingHistoryData.add(historyText);
|
||||
preferences.setStringList('history', existingHistoryData);
|
||||
}
|
||||
|
||||
void clearHistory() async {
|
||||
SharedPreferences preferences = await SharedPreferences.getInstance();
|
||||
preferences.remove('history');
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:gopeed/app/modules/history/controller/history_controller.dart';
|
||||
import 'package:gopeed/database/database.dart';
|
||||
|
||||
class HistoryView extends StatefulWidget {
|
||||
const HistoryView({
|
||||
@@ -62,8 +62,7 @@ class _HistoryViewState extends State<HistoryView> {
|
||||
children: <Widget>[
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
HistoryController _controller = HistoryController();
|
||||
_controller.clearHistory();
|
||||
Database.instance.clearCreateHistory();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
tooltip: "clearHistory".tr,
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:gopeed/util/util.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
import 'entity.dart';
|
||||
|
||||
const String _startConfig = 'startConfig';
|
||||
const String _windowState = 'windowState';
|
||||
const String _bookmark = 'bookmark';
|
||||
const String _createHistory = 'createHistory';
|
||||
|
||||
class Database {
|
||||
static final Database _instance = Database._internal();
|
||||
|
||||
static Database get instance => _instance;
|
||||
|
||||
factory Database() {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
late Box box;
|
||||
|
||||
Database._internal();
|
||||
|
||||
Future<void> init() async {
|
||||
Hive.init(Util.getStorageDir());
|
||||
box = await Hive.openBox('database');
|
||||
}
|
||||
|
||||
void save<T>(String key, T entity) {
|
||||
box.put(key, jsonEncode(entity));
|
||||
}
|
||||
|
||||
T? get<T>(String key, T Function(dynamic json) fromJsonT) {
|
||||
final json = box.get(key);
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
return fromJsonT(jsonDecode(json));
|
||||
}
|
||||
|
||||
void clear(String key) {
|
||||
box.delete(key);
|
||||
}
|
||||
|
||||
void saveStartConfig(StartConfigEntity entity) {
|
||||
save<StartConfigEntity>(_startConfig, entity);
|
||||
}
|
||||
|
||||
StartConfigEntity? getStartConfig() {
|
||||
return get<StartConfigEntity>(
|
||||
_startConfig, (json) => StartConfigEntity.fromJson(json));
|
||||
}
|
||||
|
||||
/// Patch non-null fields with the original value
|
||||
void saveWindowState(WindowStateEntity entity) {
|
||||
final state = getWindowState();
|
||||
entity.isMaximized ??= state?.isMaximized;
|
||||
entity.width ??= state?.width;
|
||||
entity.height ??= state?.height;
|
||||
save<WindowStateEntity>(_windowState, entity);
|
||||
}
|
||||
|
||||
WindowStateEntity? getWindowState() {
|
||||
return get<WindowStateEntity>(
|
||||
_windowState, (json) => WindowStateEntity.fromJson(json));
|
||||
}
|
||||
|
||||
/// Use map to ensure that the same directory only saves the latest bookmark
|
||||
void saveBookmark(MapEntry<String, String> entry) {
|
||||
final map = getBookmark() ?? {};
|
||||
map[entry.key] = entry.value;
|
||||
save<Map<String, String>>(_bookmark, map);
|
||||
}
|
||||
|
||||
Map<String, String>? getBookmark() {
|
||||
return get<Map<String, String>>(_bookmark, (json) {
|
||||
return (json as Map<String, dynamic>)
|
||||
.map((key, value) => MapEntry(key, value.toString()));
|
||||
});
|
||||
}
|
||||
|
||||
void saveCreateHistory(String url) {
|
||||
var list = getCreateHistory() ?? [];
|
||||
list.remove(url);
|
||||
list.insert(0, url);
|
||||
if (list.length > 64) {
|
||||
list.removeLast();
|
||||
}
|
||||
save<List<String>>(_createHistory, list);
|
||||
}
|
||||
|
||||
List<String>? getCreateHistory() {
|
||||
return get<List<String>>(_createHistory, (json) {
|
||||
return (json as List<dynamic>).map((e) => e.toString()).toList();
|
||||
});
|
||||
}
|
||||
|
||||
void clearCreateHistory() {
|
||||
clear(_createHistory);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'entity.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class StartConfigEntity {
|
||||
String network;
|
||||
String address;
|
||||
String apiToken;
|
||||
|
||||
StartConfigEntity({
|
||||
required this.network,
|
||||
required this.address,
|
||||
required this.apiToken,
|
||||
});
|
||||
|
||||
factory StartConfigEntity.fromJson(Map<String, dynamic> json) =>
|
||||
_$StartConfigEntityFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$StartConfigEntityToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class WindowStateEntity {
|
||||
bool? isMaximized;
|
||||
double? width;
|
||||
double? height;
|
||||
|
||||
WindowStateEntity({
|
||||
this.isMaximized,
|
||||
this.width,
|
||||
this.height,
|
||||
});
|
||||
|
||||
factory WindowStateEntity.fromJson(Map<String, dynamic> json) =>
|
||||
_$WindowStateEntityFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$WindowStateEntityToJson(this);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'entity.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
StartConfigEntity _$StartConfigEntityFromJson(Map<String, dynamic> json) =>
|
||||
StartConfigEntity(
|
||||
network: json['network'] as String,
|
||||
address: json['address'] as String,
|
||||
apiToken: json['apiToken'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$StartConfigEntityToJson(StartConfigEntity instance) =>
|
||||
<String, dynamic>{
|
||||
'network': instance.network,
|
||||
'address': instance.address,
|
||||
'apiToken': instance.apiToken,
|
||||
};
|
||||
|
||||
WindowStateEntity _$WindowStateEntityFromJson(Map<String, dynamic> json) =>
|
||||
WindowStateEntity(
|
||||
isMaximized: json['isMaximized'] as bool?,
|
||||
width: (json['width'] as num?)?.toDouble(),
|
||||
height: (json['height'] as num?)?.toDouble(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$WindowStateEntityToJson(WindowStateEntity instance) {
|
||||
final val = <String, dynamic>{};
|
||||
|
||||
void writeNotNull(String key, dynamic value) {
|
||||
if (value != null) {
|
||||
val[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
writeNotNull('isMaximized', instance.isMaximized);
|
||||
writeNotNull('width', instance.width);
|
||||
writeNotNull('height', instance.height);
|
||||
return val;
|
||||
}
|
||||
@@ -7,13 +7,13 @@ import 'api/api.dart' as api;
|
||||
import 'app/modules/app/controllers/app_controller.dart';
|
||||
import 'app/modules/app/views/app_view.dart';
|
||||
import 'core/libgopeed_boot.dart';
|
||||
import 'database/database.dart';
|
||||
import 'i18n/message.dart';
|
||||
import 'util/locale_manager.dart';
|
||||
import 'util/log_util.dart';
|
||||
import 'util/mac_secure_util.dart';
|
||||
import 'util/package_info.dart';
|
||||
import 'util/util.dart';
|
||||
import 'util/window_util.dart' as windows_util;
|
||||
|
||||
void main() async {
|
||||
await init();
|
||||
@@ -24,11 +24,13 @@ void main() async {
|
||||
|
||||
Future<void> init() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Util.initStorageDir();
|
||||
await Database.instance.init();
|
||||
if (Util.isDesktop()) {
|
||||
await windowManager.ensureInitialized();
|
||||
final windowState = await windows_util.loadState();
|
||||
final windowState = Database.instance.getWindowState();
|
||||
final windowOptions = WindowOptions(
|
||||
size: Size(windowState.width, windowState.height),
|
||||
size: Size(windowState?.width ?? 800, windowState?.height ?? 600),
|
||||
center: true,
|
||||
skipTaskbar: false,
|
||||
);
|
||||
@@ -44,9 +46,6 @@ Future<void> init() async {
|
||||
});
|
||||
}
|
||||
|
||||
if (!Util.isWeb()) {
|
||||
await Util.initStorageDir();
|
||||
}
|
||||
initLogger();
|
||||
|
||||
final controller = Get.put(AppController());
|
||||
|
||||
@@ -1,33 +1,29 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:macos_secure_bookmarks/macos_secure_bookmarks.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../database/database.dart';
|
||||
import 'util.dart';
|
||||
|
||||
class MacSecureUtil {
|
||||
static const _bookmarkKey = "bookmark:";
|
||||
|
||||
static Future<void> saveBookmark(String dir) async {
|
||||
if (!Util.isMacos()) {
|
||||
return;
|
||||
}
|
||||
final secureBookmarks = SecureBookmarks();
|
||||
final bookmark = await secureBookmarks.bookmark(Directory(dir));
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_bookmarkKey + dir, bookmark);
|
||||
Database.instance.saveBookmark(MapEntry(dir, bookmark));
|
||||
}
|
||||
|
||||
static Future<void> loadBookmark() async {
|
||||
if (!Util.isMacos()) {
|
||||
return;
|
||||
}
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final keys = prefs.getKeys();
|
||||
final secureBookmarks = SecureBookmarks();
|
||||
keys.where((k) => k.startsWith(_bookmarkKey)).forEach((k) async {
|
||||
final resolvedFile = await secureBookmarks
|
||||
.resolveBookmark(prefs.getString(k)!, isDirectory: true);
|
||||
final bookmark = Database.instance.getBookmark() ?? {};
|
||||
bookmark.forEach((_, v) async {
|
||||
final resolvedFile =
|
||||
await secureBookmarks.resolveBookmark(v, isDirectory: true);
|
||||
await secureBookmarks.startAccessingSecurityScopedResource(resolvedFile);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -50,19 +50,21 @@ class Util {
|
||||
}
|
||||
|
||||
static Future<void> initStorageDir() async {
|
||||
var storageDir = "./";
|
||||
if (Platform.isAndroid) {
|
||||
storageDir = (await getExternalStorageDirectory())?.path ?? storageDir;
|
||||
} else if (Platform.isIOS) {
|
||||
storageDir = (await getLibraryDirectory()).path;
|
||||
} else if (Util.isLinux()) {
|
||||
storageDir = File(Platform.resolvedExecutable).parent.path;
|
||||
// check has write permission, if not, fallback to application support dir
|
||||
try {
|
||||
final testFile = File(path.join(storageDir, ".test"));
|
||||
await testFile.writeAsString("test");
|
||||
await testFile.delete();
|
||||
} catch (e) {
|
||||
var storageDir = "";
|
||||
if (Util.isWindows()) {
|
||||
storageDir = "./";
|
||||
} else if (!Util.isWeb()) {
|
||||
if (Util.isLinux()) {
|
||||
storageDir = File(Platform.resolvedExecutable).parent.path;
|
||||
// check has write permission, if not, fallback to application support dir
|
||||
try {
|
||||
final testFile = File(path.join(storageDir, ".test"));
|
||||
await testFile.writeAsString("test");
|
||||
await testFile.delete();
|
||||
} catch (e) {
|
||||
storageDir = (await getApplicationSupportDirectory()).path;
|
||||
}
|
||||
} else {
|
||||
storageDir = (await getApplicationSupportDirectory()).path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class WindowState {
|
||||
late bool isMaximized;
|
||||
late double width;
|
||||
late double height;
|
||||
|
||||
WindowState(this.isMaximized, this.width, this.height);
|
||||
}
|
||||
|
||||
const String _windowStateIsMaximized = "window.isMaximized";
|
||||
const String _windowStateWidth = "window.width";
|
||||
const String _windowStateHeight = "window.height";
|
||||
|
||||
/// Save window state to storage.
|
||||
void saveState({bool? isMaximized, double? width, double? height}) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
if (isMaximized != null) {
|
||||
await prefs.setBool(_windowStateIsMaximized, isMaximized);
|
||||
}
|
||||
if (width != null) {
|
||||
await prefs.setDouble(_windowStateWidth, width);
|
||||
}
|
||||
if (height != null) {
|
||||
await prefs.setDouble(_windowStateHeight, height);
|
||||
}
|
||||
}
|
||||
|
||||
/// Load window state from storage.
|
||||
Future<WindowState> loadState() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return WindowState(
|
||||
prefs.getBool(_windowStateIsMaximized) ?? false,
|
||||
prefs.getDouble(_windowStateWidth) ?? 800,
|
||||
prefs.getDouble(_windowStateHeight) ?? 600,
|
||||
);
|
||||
}
|
||||
@@ -405,6 +405,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
hive:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: hive
|
||||
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.2.3"
|
||||
http:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -798,7 +806,7 @@ packages:
|
||||
source: hosted
|
||||
version: "3.3.1"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
|
||||
|
||||
@@ -46,7 +46,6 @@ dependencies:
|
||||
macos_secure_bookmarks: ^0.2.1
|
||||
rounded_loading_button: ^2.1.0
|
||||
url_launcher: ^6.1.6
|
||||
shared_preferences: ^2.2.0
|
||||
logger: ^1.3.0
|
||||
desktop_drop: ^0.4.3
|
||||
package_info_plus: ^4.0.0
|
||||
@@ -64,6 +63,7 @@ dependencies:
|
||||
open_filex: ^4.3.4
|
||||
tray_manager: ^0.2.1
|
||||
lecle_downloads_path_provider: ^0.0.2+8
|
||||
hive: ^2.2.3
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
Reference in new issue
Block a user