added persistence using shared preferences
This commit is contained in:
2
android/app/proguard-rules.pro
vendored
Normal file
2
android/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
-keep class io.flutter.plugins.sharedpreferences.** { *; }
|
||||
-keep class io.flutter.plugins.sharedpreferences.LegacySharedPreferencesPlugin { *; }
|
||||
@@ -5,6 +5,7 @@ import android.os.Bundle
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin
|
||||
|
||||
class MainActivity: FlutterActivity() {
|
||||
private var sharedText: String? = null
|
||||
@@ -31,6 +32,8 @@ class MainActivity: FlutterActivity() {
|
||||
}
|
||||
|
||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||
super.configureFlutterEngine(flutterEngine)
|
||||
flutterEngine.plugins.add(SharedPreferencesPlugin())
|
||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
|
||||
.setMethodCallHandler { call, result ->
|
||||
if (call.method == "getSharedText") {
|
||||
|
||||
3
devtools_options.yaml
Normal file
3
devtools_options.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
||||
@@ -1,7 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'pages/collections_page.dart';
|
||||
import 'service/storage.dart';
|
||||
|
||||
void main() {
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Storage.initialize();
|
||||
runApp(const MapsBookmarks());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,35 @@
|
||||
class Bookmark {
|
||||
Bookmark({required this.name, required this.link});
|
||||
Bookmark({
|
||||
required this.collectionId,
|
||||
required this.name,
|
||||
required this.link,
|
||||
required this.description,
|
||||
int? createdAt,
|
||||
}) : createdAt = createdAt ?? DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
factory Bookmark.fromJson(Map<String, dynamic> json) =>
|
||||
Bookmark(name: json['name'] as String, link: json['link'] as String);
|
||||
factory Bookmark.fromJson(Map<String, dynamic> json) => Bookmark(
|
||||
collectionId: json['collectionId'] as int,
|
||||
name: json['name'] as String,
|
||||
link: json['link'] as String,
|
||||
description: json['description'] as String,
|
||||
createdAt: json['createdAt'] as int,
|
||||
);
|
||||
|
||||
int collectionId;
|
||||
String link;
|
||||
String name;
|
||||
String description;
|
||||
int createdAt;
|
||||
|
||||
Map<String, dynamic> toJson() => {'name': name, 'link': link};
|
||||
int get id => createdAt;
|
||||
|
||||
DateTime get createdDate => DateTime.fromMillisecondsSinceEpoch(createdAt);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'collectionId': collectionId,
|
||||
'name': name,
|
||||
'link': link,
|
||||
'description': description,
|
||||
'createdAt': createdAt,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
class Collection {
|
||||
Collection({required this.name});
|
||||
Collection({required this.name, int? createdAt})
|
||||
: createdAt = createdAt ?? DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
factory Collection.fromJson(Map<String, dynamic> json) =>
|
||||
Collection(name: json['name'] as String);
|
||||
factory Collection.fromJson(Map<String, dynamic> json) => Collection(
|
||||
name: json['name'] as String,
|
||||
createdAt: json['createdAt'] as int,
|
||||
);
|
||||
|
||||
String name;
|
||||
int createdAt; // used as Id with millisecondsSinceEpoch
|
||||
|
||||
Map<String, dynamic> toJson() => {'name': name};
|
||||
int get id => createdAt;
|
||||
|
||||
DateTime get createdDate => DateTime.fromMillisecondsSinceEpoch(createdAt);
|
||||
|
||||
Map<String, dynamic> toJson() => {'name': name, 'createdAt': createdAt};
|
||||
}
|
||||
|
||||
117
lib/service/storage.dart
Normal file
117
lib/service/storage.dart
Normal file
@@ -0,0 +1,117 @@
|
||||
import 'dart:convert' show jsonDecode, jsonEncode;
|
||||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../model/bookmark.dart';
|
||||
import '../model/collection.dart';
|
||||
|
||||
class Storage {
|
||||
static const String _collectionsKey = 'collections';
|
||||
static const String _bookmarksKey = 'bookmarks';
|
||||
static const String _statsKey = 'stats';
|
||||
static SharedPreferencesWithCache? _prefsWithCache;
|
||||
|
||||
static Future<void> initialize() async {
|
||||
_prefsWithCache = await SharedPreferencesWithCache.create(
|
||||
cacheOptions: const SharedPreferencesWithCacheOptions(
|
||||
allowList: <String>{_collectionsKey, _bookmarksKey, _statsKey},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static SharedPreferencesWithCache get _prefs {
|
||||
if (_prefsWithCache == null) {
|
||||
throw StateError(
|
||||
'BookmarkStorage not initialized. Call initialize() first.',
|
||||
);
|
||||
}
|
||||
return _prefsWithCache!;
|
||||
}
|
||||
|
||||
static List<Collection> loadCollections() {
|
||||
final jsonString = _prefs.getString(_collectionsKey) ?? '[]';
|
||||
final jsonList = jsonDecode(jsonString) as List;
|
||||
return jsonList
|
||||
.map((json) => Collection.fromJson(json as Map<String, dynamic>))
|
||||
.toList();
|
||||
}
|
||||
|
||||
static Future<void> saveCollections(List<Collection> collections) async {
|
||||
final jsonList = collections.map((c) => c.toJson()).toList();
|
||||
await _prefs.setString(_collectionsKey, jsonEncode(jsonList));
|
||||
}
|
||||
|
||||
static List<Bookmark> loadAllBookmarks() {
|
||||
final jsonString = _prefs.getString(_bookmarksKey) ?? '[]';
|
||||
final jsonList = jsonDecode(jsonString) as List;
|
||||
return jsonList
|
||||
.map((json) => Bookmark.fromJson(json as Map<String, dynamic>))
|
||||
.toList();
|
||||
}
|
||||
|
||||
static Future<void> saveAllBookmarks(List<Bookmark> bookmarks) async {
|
||||
final jsonList = bookmarks.map((b) => b.toJson()).toList();
|
||||
await _prefs.setString(_bookmarksKey, jsonEncode(jsonList));
|
||||
}
|
||||
|
||||
static List<Bookmark> loadBookmarksForCollection(int collectionId) {
|
||||
final allBookmarks = loadAllBookmarks();
|
||||
return allBookmarks.where((b) => b.collectionId == collectionId).toList();
|
||||
}
|
||||
|
||||
static Future<void> addBookmark(Bookmark bookmark) async {
|
||||
final bookmarks = loadAllBookmarks();
|
||||
bookmarks.add(bookmark);
|
||||
await saveAllBookmarks(bookmarks);
|
||||
}
|
||||
|
||||
static Future<void> deleteBookmarkById(int bookmarkId) async {
|
||||
final bookmarks = loadAllBookmarks();
|
||||
bookmarks.removeWhere((b) => b.id == bookmarkId);
|
||||
await saveAllBookmarks(bookmarks);
|
||||
}
|
||||
|
||||
static Future<void> deleteBookmarksForCollection(int collectionId) async {
|
||||
final bookmarks = loadAllBookmarks();
|
||||
bookmarks.removeWhere((b) => b.collectionId == collectionId);
|
||||
await saveAllBookmarks(bookmarks);
|
||||
}
|
||||
|
||||
static Future<void> updateBookmarkById(
|
||||
int bookmarkId, {
|
||||
String? name,
|
||||
String? description,
|
||||
}) async {
|
||||
final bookmarks = loadAllBookmarks();
|
||||
final index = bookmarks.indexWhere((b) => b.id == bookmarkId);
|
||||
|
||||
if (index == -1) return;
|
||||
|
||||
if (name != null) bookmarks[index].name = name;
|
||||
if (description != null) bookmarks[index].description = description;
|
||||
|
||||
await saveAllBookmarks(bookmarks);
|
||||
}
|
||||
|
||||
static Map<String, int> getStats() {
|
||||
final statsJson = _prefs.getString(_statsKey) ?? '{}';
|
||||
final stats = jsonDecode(statsJson) as Map<String, dynamic>;
|
||||
return {
|
||||
'totalCollections': stats['totalCollections'] ?? 0,
|
||||
'totalBookmarks': stats['totalBookmarks'] ?? 0,
|
||||
};
|
||||
}
|
||||
|
||||
static Future<void> updateStats() async {
|
||||
final collections = loadCollections();
|
||||
final bookmarks = loadAllBookmarks();
|
||||
|
||||
final stats = {
|
||||
'totalCollections': collections.length,
|
||||
'totalBookmarks': bookmarks.length,
|
||||
'lastUpdated': DateTime.now().millisecondsSinceEpoch,
|
||||
};
|
||||
|
||||
await _prefs.setString(_statsKey, jsonEncode(stats));
|
||||
}
|
||||
}
|
||||
135
pubspec.lock
135
pubspec.lock
@@ -65,6 +65,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -74,15 +90,20 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1"
|
||||
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "6.0.0"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -111,10 +132,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: lints
|
||||
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
|
||||
sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
version: "6.0.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -147,6 +168,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -155,6 +200,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.6"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.3"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: a2608114b1ffdcbc9c120eb71a0e207c71da56202852d4aab8a5e30a82269e74
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.12"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.4"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.3"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@@ -224,6 +333,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "15.0.2"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
sdks:
|
||||
dart: ">=3.9.2 <4.0.0"
|
||||
flutter: ">=3.18.0-18.0.pre.54"
|
||||
flutter: ">=3.29.0"
|
||||
|
||||
@@ -14,12 +14,13 @@ dependencies:
|
||||
|
||||
cupertino_icons: ^1.0.8
|
||||
android_intent_plus: ^6.0.0
|
||||
shared_preferences: ^2.3.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
flutter_lints: ^5.0.0
|
||||
flutter_lints: ^6.0.0
|
||||
|
||||
flutter:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user