added persistence using shared preferences
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user