forked from lxm_flutter/FlutterUnit
✨ 过时组件显示优化,数据库结构优化
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
class StrUnit {
|
||||
|
||||
// 小文字大小
|
||||
static const String version = 'V1.5.0';
|
||||
static const String version = 'V1.5.1';
|
||||
static const String appName = 'Flutter Unit';
|
||||
|
||||
static const String galleryInfo = """
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_unit/app/res/cons.dart';
|
||||
import 'package:flutter_unit/app/res/sp.dart';
|
||||
import 'package:flutter_unit/repositories/app_storage.dart';
|
||||
import 'package:flutter_unit/repositories/app_start.dart';
|
||||
import 'package:flutter_unit/repositories/local_storage.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'global_event.dart';
|
||||
@@ -13,11 +14,11 @@ import 'global_state.dart';
|
||||
|
||||
class GlobalBloc extends Bloc<GlobalEvent, GlobalState> {
|
||||
|
||||
final AppStorage storage;
|
||||
final AppStart storage;
|
||||
|
||||
GlobalBloc(this.storage):super(GlobalState());
|
||||
|
||||
Future<SharedPreferences> get sp => storage.sp;
|
||||
Future<SharedPreferences> get sp => LocalStorage.sp;
|
||||
|
||||
@override
|
||||
Stream<GlobalState> mapEventToState(GlobalEvent event) async* {
|
||||
@@ -29,8 +30,7 @@ class GlobalBloc extends Bloc<GlobalEvent, GlobalState> {
|
||||
// 切换字体事件处理 : 固化索引 + 产出新状态
|
||||
if (event is EventSwitchFontFamily) {
|
||||
int familyIndex = Cons.fontFamilySupport.indexOf(event.family);
|
||||
await sp
|
||||
..setInt(SP.fontFamily, familyIndex);
|
||||
await sp..setInt(SP.fontFamily, familyIndex);
|
||||
yield state.copyWith(fontFamily: event.family);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class WidgetModel extends Equatable {
|
||||
final String name;
|
||||
final String nameCN;
|
||||
final WidgetFamily family;
|
||||
final bool collected;
|
||||
final bool deprecated;
|
||||
final WidgetType type;
|
||||
final List<int> links;
|
||||
final double lever;
|
||||
@@ -39,7 +39,7 @@ class WidgetModel extends Equatable {
|
||||
this.name,
|
||||
this.nameCN,
|
||||
this.family,
|
||||
this.collected,
|
||||
this.deprecated,
|
||||
this.links,
|
||||
this.type,
|
||||
this.lever,
|
||||
@@ -55,21 +55,23 @@ class WidgetModel extends Equatable {
|
||||
name: po.name,
|
||||
nameCN: po.nameCN,
|
||||
family: Convert.toFamily(po.family),
|
||||
image: convertImage(po.image),
|
||||
image: convertImage(po.name),
|
||||
lever: po.lever,
|
||||
collected: po.collected == 1,
|
||||
deprecated: po.deprecated == 1,
|
||||
info: po.info,
|
||||
links: formatLinkTo(po.linkWidget),
|
||||
);
|
||||
}
|
||||
|
||||
static convertImage(String image) {
|
||||
return image.isEmpty ? null : AssetImage(image);
|
||||
static convertImage(String name) {
|
||||
// return image.isEmpty ? null : AssetImage(image);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'WidgetModel{id: $id, name: $name,collected: $collected}';
|
||||
return 'WidgetModel{id: $id, name: $name, nameCN: $nameCN, family: $family, deprecated: $deprecated, type: $type, links: $links, lever: $lever, image: $image, info: $info}';
|
||||
}
|
||||
|
||||
static List<int> formatLinkTo(String links) {
|
||||
@@ -81,6 +83,4 @@ class WidgetModel extends Equatable {
|
||||
}
|
||||
return links.split(',').map<int>((e)=>int.parse(e)).toList();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
91
lib/repositories/app_start.dart
Normal file
91
lib/repositories/app_start.dart
Normal file
@@ -0,0 +1,91 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_unit/app/res/cons.dart';
|
||||
import 'package:flutter_unit/app/res/sp.dart';
|
||||
import 'package:flutter_unit/blocs/global/global_state.dart';
|
||||
import 'package:flutter_unit/repositories/local_db.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
import 'local_storage.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2020-03-04
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明: 本地存储访问对象,用于读取配置数据,及初始化Database和SharedPreferences
|
||||
|
||||
class AppStart {
|
||||
// 初始化 App 固化的配置数据
|
||||
Future<GlobalState> initApp() async {
|
||||
SharedPreferences prefs = await LocalStorage.sp;
|
||||
//数据库不存在,执行拷贝
|
||||
String databasesPath = await getDatabasesPath();
|
||||
String dbPath = path.join(databasesPath, "flutter.db");
|
||||
|
||||
bool shouldCopy = await _checkShouldCopy(dbPath);
|
||||
|
||||
if (shouldCopy) {
|
||||
await _doCopyAssetsDb(dbPath);
|
||||
} else {
|
||||
print("=====flutter.db 已存在====");
|
||||
}
|
||||
|
||||
await LocalDb.instance.initDb();
|
||||
|
||||
bool showBg = prefs.getBool(SP.showBackground) ?? true;
|
||||
int themeIndex = prefs.getInt(SP.themeColorIndex) ?? 4;
|
||||
int fontIndex = prefs.getInt(SP.fontFamily) ?? 1;
|
||||
int codeIndex = prefs.getInt(SP.codeStyleIndex) ?? 0;
|
||||
int itemStyleIndex = prefs.getInt(SP.itemStyleIndex) ?? 0;
|
||||
|
||||
return GlobalState(
|
||||
showBackGround: showBg,
|
||||
themeColor: Cons.themeColorSupport.keys.toList()[themeIndex],
|
||||
fontFamily: Cons.fontFamilySupport[fontIndex],
|
||||
itemStyleIndex: itemStyleIndex,
|
||||
codeStyleIndex: codeIndex);
|
||||
}
|
||||
|
||||
Future<bool> _checkShouldCopy(String dbPath) async {
|
||||
bool shouldCopy = false;
|
||||
String versionStr = await rootBundle.loadString('assets/version.json');
|
||||
int dbVersion = await json.decode(versionStr)['dbVersion'];
|
||||
int versionInSP =
|
||||
await LocalStorage.getInt(LocalStorage.dbVersionKey) ?? -1;
|
||||
|
||||
// 版本升级,执行拷贝
|
||||
if (dbVersion > versionInSP) {
|
||||
shouldCopy = true;
|
||||
await LocalStorage.saveInt(LocalStorage.dbVersionKey,dbVersion);
|
||||
}
|
||||
|
||||
//非 release模式,执行拷贝
|
||||
const isPro = bool.fromEnvironment('dart.vm.product');
|
||||
if (!isPro) {
|
||||
shouldCopy = true;
|
||||
}
|
||||
|
||||
//数据库不存在,执行拷贝
|
||||
if (!File(dbPath).existsSync()) {
|
||||
shouldCopy = true;
|
||||
}
|
||||
|
||||
return shouldCopy;
|
||||
}
|
||||
|
||||
Future<void> _doCopyAssetsDb(String dbPath) async {
|
||||
Directory dir = Directory(path.dirname(dbPath));
|
||||
if (!dir.existsSync()) {
|
||||
await dir.create(recursive: true);
|
||||
}
|
||||
ByteData data = await rootBundle.load("assets/flutter.db");
|
||||
List<int> bytes =
|
||||
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
|
||||
await File(dbPath).writeAsBytes(bytes, flush: true);
|
||||
|
||||
print("=====flutter.db==== assets ======拷贝完成====");
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_unit/app/res/cons.dart';
|
||||
import 'package:flutter_unit/app/res/sp.dart';
|
||||
import 'package:flutter_unit/blocs/global/global_state.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
/// create by 张风捷特烈 on 2020-03-04
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明: 本地存储访问对象,用于读取配置数据,及初始化Database和SharedPreferences
|
||||
|
||||
class AppStorage {
|
||||
SharedPreferences _sp;
|
||||
Database _database;
|
||||
|
||||
Future<SharedPreferences> get sp async {
|
||||
_sp = _sp ?? await SharedPreferences.getInstance();
|
||||
return _sp;
|
||||
}
|
||||
|
||||
Future<Database> get db async {
|
||||
_database = _database ?? await initDb();
|
||||
return _database;
|
||||
}
|
||||
|
||||
// 初始化 App 固化的配置数据
|
||||
Future<GlobalState> initApp() async {
|
||||
SharedPreferences prefs = await sp;
|
||||
_database = await initDb();
|
||||
|
||||
bool showBg = prefs.getBool(SP.showBackground) ?? true;
|
||||
int themeIndex = prefs.getInt(SP.themeColorIndex) ?? 4;
|
||||
int fontIndex = prefs.getInt(SP.fontFamily) ?? 1;
|
||||
int codeIndex = prefs.getInt(SP.codeStyleIndex) ?? 0;
|
||||
int itemStyleIndex = prefs.getInt(SP.itemStyleIndex) ?? 0;
|
||||
|
||||
return GlobalState(
|
||||
showBackGround: showBg,
|
||||
themeColor: Cons.themeColorSupport.keys.toList()[themeIndex],
|
||||
fontFamily: Cons.fontFamilySupport[fontIndex],
|
||||
itemStyleIndex: itemStyleIndex,
|
||||
codeStyleIndex: codeIndex);
|
||||
}
|
||||
|
||||
// 初始化数据库
|
||||
Future<Database> initDb() async {
|
||||
String databasesPath = await getDatabasesPath();
|
||||
String dbPath = path.join(databasesPath, "flutter.db");
|
||||
bool exists = await databaseExists(dbPath);
|
||||
const isPro = bool.fromEnvironment('dart.vm.product'); //是否release模式
|
||||
|
||||
if (!isPro) {
|
||||
if (!exists) {
|
||||
await Directory(path.dirname(dbPath)).create(recursive: true);
|
||||
}
|
||||
ByteData data = await rootBundle.load(path.join("assets", "flutter.db"));
|
||||
List<int> bytes =
|
||||
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
|
||||
await File(dbPath).writeAsBytes(bytes, flush: true);
|
||||
print("==== debug ===== assets ======拷贝完成====");
|
||||
return await openDatabase(dbPath, readOnly: false);
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
await Directory(path.dirname(dbPath)).create(recursive: true);
|
||||
ByteData data = await rootBundle.load(path.join("assets", "flutter.db"));
|
||||
List<int> bytes =
|
||||
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
|
||||
await File(dbPath).writeAsBytes(bytes, flush: true);
|
||||
print("==== release ===== assets ======拷贝完成====");
|
||||
} else {
|
||||
print("========= 数据库 ======已存在====");
|
||||
}
|
||||
_database = await openDatabase(dbPath, readOnly: false);
|
||||
return _database;
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,9 @@ class WidgetPo extends Equatable {
|
||||
final int id;
|
||||
final String name;
|
||||
final String nameCN;
|
||||
final int collected;
|
||||
final int deprecated;
|
||||
final int family;
|
||||
final double lever;
|
||||
final String image;
|
||||
final String info;
|
||||
final String linkWidget;
|
||||
|
||||
@@ -20,11 +19,10 @@ class WidgetPo extends Equatable {
|
||||
{this.id,
|
||||
this.name,
|
||||
this.nameCN,
|
||||
this.collected,
|
||||
this.deprecated,
|
||||
this.family,
|
||||
this.lever,
|
||||
this.linkWidget,
|
||||
this.image,
|
||||
this.info});
|
||||
|
||||
factory WidgetPo.fromJson(Map<String, dynamic> map) {
|
||||
@@ -33,9 +31,8 @@ class WidgetPo extends Equatable {
|
||||
name: map['name'],
|
||||
nameCN: map["nameCN"],
|
||||
family: map["family"],
|
||||
collected: map["collected"] ?? 0,
|
||||
deprecated: map["deprecated"] ?? 0,
|
||||
lever: map["lever"].toDouble(),
|
||||
image: map["image"],
|
||||
linkWidget: map["linkWidget"],
|
||||
info: map["info"]);
|
||||
}
|
||||
@@ -46,9 +43,8 @@ class WidgetPo extends Equatable {
|
||||
"name": this.name,
|
||||
"nameCN": this.nameCN,
|
||||
"family": this.family,
|
||||
"collected": this.collected,
|
||||
"deprecated": this.deprecated,
|
||||
"lever": this.lever,
|
||||
"image": this.image,
|
||||
"linkWidget": this.linkWidget,
|
||||
"info": this.info
|
||||
};
|
||||
@@ -56,10 +52,10 @@ class WidgetPo extends Equatable {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'WidgetPo{id: $id, name: $name, nameCN: $nameCN, collected: $collected, family: $family, lever: $lever, image: $image, info: $info}';
|
||||
return 'WidgetPo{id: $id, name: $name, nameCN: $nameCN, deprecated: $deprecated, family: $family, lever: $lever, info: $info}';
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props =>
|
||||
[id, name, nameCN, collected, family, lever, image, info];
|
||||
[id, name, nameCN, deprecated, family, linkWidget, lever, info];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
import '../app_storage.dart';
|
||||
import '../app_start.dart';
|
||||
import '../bean/category_po.dart';
|
||||
|
||||
|
||||
@@ -19,16 +19,14 @@ import '../bean/category_po.dart';
|
||||
//""";
|
||||
|
||||
class CategoryDao {
|
||||
final AppStorage storage;
|
||||
final Database db;
|
||||
|
||||
CategoryDao(this.storage);
|
||||
CategoryDao(this.db);
|
||||
|
||||
Future<Database> get _db async =>await storage.db;
|
||||
|
||||
|
||||
Future<int> insert(CategoryPo category) async {
|
||||
//插入方法
|
||||
final db = await _db;
|
||||
String addSql = //插入数据
|
||||
"INSERT INTO "
|
||||
"category(id,name,color,info,priority,image,created,updated) "
|
||||
@@ -47,7 +45,6 @@ class CategoryDao {
|
||||
|
||||
Future<int> update(CategoryPo widget) async {
|
||||
//插入方法
|
||||
final db = await _db;
|
||||
String updateSql = //插入数据
|
||||
"UPDATE category SET name=? , color=? ,info=?, priority=?,image=?,updated=? "
|
||||
"WHERE id = ?";
|
||||
@@ -67,7 +64,6 @@ class CategoryDao {
|
||||
|
||||
|
||||
Future<int> addWidget(int categoryId,int widgetId,) async {
|
||||
final db = await _db;
|
||||
String addSql = //插入数据
|
||||
"INSERT INTO "
|
||||
"category_widget(widgetId,categoryId) "
|
||||
@@ -79,7 +75,6 @@ class CategoryDao {
|
||||
}
|
||||
|
||||
Future<int> addWidgets(int categoryId,List<dynamic> widgetIds) async {
|
||||
final db = await _db;
|
||||
String addSql = //插入数据
|
||||
"INSERT INTO "
|
||||
"category_widget(widgetId,categoryId) VALUES ";
|
||||
@@ -99,7 +94,6 @@ class CategoryDao {
|
||||
}
|
||||
|
||||
Future<bool> existByName(String name) async {
|
||||
final db = await _db;
|
||||
String sql = //插入数据
|
||||
"SELECT COUNT(name) as count FROM category "
|
||||
"WHERE name = ?";
|
||||
@@ -111,7 +105,6 @@ class CategoryDao {
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> queryAll() async {
|
||||
final db = await _db;
|
||||
List<Map<String, dynamic>> data = await db.rawQuery(
|
||||
"SELECT c.id,c.name,c.info,c.color,c.image,c.created,c.updated,c.priority,COUNT(cw.categoryId) as `count`"
|
||||
"FROM category AS c "
|
||||
@@ -123,7 +116,6 @@ class CategoryDao {
|
||||
}
|
||||
|
||||
Future<List<int>> categoryWidgetIds(int id) async {
|
||||
final db = await _db;
|
||||
List<Map<String, dynamic>> data = await db.rawQuery(
|
||||
"SELECT categoryId FROM `category_widget`"
|
||||
"WHERE widgetId = ?",
|
||||
@@ -134,7 +126,6 @@ class CategoryDao {
|
||||
|
||||
|
||||
Future<void> deleteCollect(int id) async {
|
||||
final db = await _db;
|
||||
await db.execute(
|
||||
"DELETE FROM category_widget "
|
||||
"WHERE categoryId = ?",
|
||||
@@ -146,7 +137,6 @@ class CategoryDao {
|
||||
}
|
||||
|
||||
Future<void> clear() async {
|
||||
final db = await _db;
|
||||
await db.execute(
|
||||
"DELETE FROM category_widget "
|
||||
"WHERE categoryId >0");
|
||||
@@ -157,7 +147,6 @@ class CategoryDao {
|
||||
|
||||
Future<int> removeWidget(int categoryId, int widgetId) async {
|
||||
//插入方法
|
||||
final db = await _db;
|
||||
String deleteSql = //插入数据
|
||||
"DELETE FROM "
|
||||
"category_widget WHERE categoryId = ? AND widgetId = ? ";
|
||||
@@ -169,7 +158,6 @@ class CategoryDao {
|
||||
}
|
||||
|
||||
Future<bool> existWidgetInCollect(int categoryId, int widgetId) async {
|
||||
final db = await _db;
|
||||
String sql = //插入数据
|
||||
"SELECT COUNT(id) as count FROM category_widget "
|
||||
"WHERE categoryId = ? AND widgetId = ?";
|
||||
@@ -199,7 +187,6 @@ class CategoryDao {
|
||||
"WHERE id IN (SELECT widgetId FROM category_widget WHERE categoryId = ?) "
|
||||
"ORDER BY lever DESC";
|
||||
|
||||
final db = await _db;
|
||||
return await db.rawQuery(querySql,[categoryId]);
|
||||
}
|
||||
|
||||
@@ -209,7 +196,6 @@ class CategoryDao {
|
||||
"WHERE id IN (SELECT widgetId FROM category_widget WHERE categoryId = ?) "
|
||||
"ORDER BY lever DESC";
|
||||
|
||||
final db = await _db;
|
||||
var data = await db.rawQuery(querySql,[categoryId]);
|
||||
return data.map<int>((e) => e["id"]).toList();
|
||||
}
|
||||
|
||||
64
lib/repositories/dao/like_dao.dart
Normal file
64
lib/repositories/dao/like_dao.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
class LikeDao {
|
||||
final Database db;
|
||||
|
||||
LikeDao(this.db);
|
||||
|
||||
Future<List<int>> likeWidgetIds() async {
|
||||
var result = await db.rawQuery("SELECT widget_id FROM like_widget");
|
||||
var ids = result.map<int>((e) => e['widget_id']).toList();
|
||||
return ids;
|
||||
}
|
||||
|
||||
// 如果已喜欢,取消喜欢
|
||||
// 如果未喜欢,设为喜欢
|
||||
Future<void> toggleCollect(int widgetId) async {
|
||||
bool liked = await isLiked(widgetId);
|
||||
|
||||
if (liked) {
|
||||
await unlike(widgetId, check: false);
|
||||
} else {
|
||||
await like(widgetId, check: false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<int> like(int widgetId, {bool check = true}) async {
|
||||
if (check) {
|
||||
// 如果 like ,直接取消,不执行 like 操作
|
||||
bool liked = await isLiked(widgetId);
|
||||
if (liked) return 0;
|
||||
}
|
||||
|
||||
return await db.rawInsert(
|
||||
"INSERT INTO "
|
||||
"like_widget(widget_id) "
|
||||
"VALUES (?);",
|
||||
[widgetId]);
|
||||
}
|
||||
|
||||
Future<void> unlike(int widgetId, {bool check = true}) async {
|
||||
if (check) {
|
||||
// 如果未 like ,直接取消,不执行 unlike 操作
|
||||
bool liked = await isLiked(widgetId);
|
||||
if (!liked) return;
|
||||
}
|
||||
await db.execute(
|
||||
"DELETE FROM like_widget "
|
||||
"WHERE widget_id = ?",
|
||||
[widgetId]);
|
||||
}
|
||||
|
||||
// 判断组件是否已 liked
|
||||
Future<bool> isLiked(int widgetId) async {
|
||||
var data = await db.rawQuery(
|
||||
"Select count(id) as `count` FROM like_widget "
|
||||
"WHERE widget_id = ?",
|
||||
[widgetId]);
|
||||
if (data.length > 0) {
|
||||
var result = data[0];
|
||||
return result['count'] as int > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
import 'package:flutter_unit/repositories/bean/node_po.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
import '../app_storage.dart';
|
||||
import '../app_start.dart';
|
||||
|
||||
|
||||
|
||||
class NodeDao {
|
||||
|
||||
final AppStorage storage;
|
||||
final Database db;
|
||||
|
||||
NodeDao(this.storage);
|
||||
|
||||
NodeDao(this.db);
|
||||
|
||||
Future<int> insert(NodePo widget) async {
|
||||
//插入方法
|
||||
final db = await storage.db;
|
||||
String addSql = //插入数据
|
||||
"INSERT INTO "
|
||||
"node(widgetId,name,priority,subtitle,code) "
|
||||
@@ -28,14 +29,12 @@ class NodeDao {
|
||||
|
||||
Future<List<Map<String, dynamic>>> queryAll() async {
|
||||
//插入方法
|
||||
final db = await storage.db;
|
||||
return await db.rawQuery("SELECT * "
|
||||
"FROM node");
|
||||
}
|
||||
|
||||
//根据 id 查询组件 node
|
||||
Future<List<Map<String, dynamic>>> queryById(int id) async {
|
||||
final db = await storage.db;
|
||||
return await db.rawQuery(
|
||||
"SELECT name,subtitle,code "
|
||||
"FROM node "
|
||||
|
||||
@@ -1,45 +1,40 @@
|
||||
|
||||
import 'package:flutter_unit/model/enums.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
import '../app_storage.dart';
|
||||
import '../app_start.dart';
|
||||
import '../bean/widget_po.dart';
|
||||
|
||||
|
||||
class WidgetDao {
|
||||
|
||||
final AppStorage storage;
|
||||
final Database db;
|
||||
|
||||
|
||||
WidgetDao(this.storage);
|
||||
WidgetDao(this.db);
|
||||
|
||||
Future<int> insert(WidgetPo widget) async {
|
||||
//插入方法
|
||||
final db = await storage.db;
|
||||
String addSql = //插入数据
|
||||
"INSERT INTO "
|
||||
"widget(id,name,nameCN,collected,family,lever,image,linkWidget,info) "
|
||||
"VALUES (?,?,?,?,?,?,?,?,?);";
|
||||
"widget(id,name,nameCN,deprecated,family,lever,linkWidget,info) "
|
||||
"VALUES (?,?,?,?,?,?,?,?);";
|
||||
return await db.transaction((tran) async => await tran.rawInsert(addSql, [
|
||||
widget.id,
|
||||
widget.name,
|
||||
widget.nameCN,
|
||||
widget.collected,
|
||||
widget.deprecated,
|
||||
widget.family,
|
||||
widget.lever,
|
||||
widget.image,
|
||||
widget.linkWidget,
|
||||
widget.info
|
||||
]));
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> queryAll() async {
|
||||
final db = await storage.db;
|
||||
return await db.rawQuery("SELECT * "
|
||||
"FROM widget");
|
||||
return await db.rawQuery("SELECT * FROM widget");
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> queryByFamily(WidgetFamily family) async {
|
||||
final db = await storage.db;
|
||||
return await db.rawQuery(
|
||||
"SELECT * "
|
||||
"FROM widget WHERE family = ? ORDER BY lever DESC",
|
||||
@@ -50,8 +45,6 @@ class WidgetDao {
|
||||
if (ids.length == 0) {
|
||||
return [];
|
||||
}
|
||||
final db = await storage.db;
|
||||
|
||||
String sql = "SELECT * "
|
||||
"FROM widget WHERE id in (${'?,' * (ids.length - 1)}?) ";
|
||||
|
||||
@@ -59,40 +52,11 @@ class WidgetDao {
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> search(SearchArgs arguments) async {
|
||||
final db = await storage.db;
|
||||
return await db.rawQuery(
|
||||
"SELECT * "
|
||||
"FROM widget WHERE name like ? AND lever IN(?,?,?,?,?) ORDER BY lever DESC",
|
||||
["%${arguments.name}%", ...arguments.stars]);
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> toggleCollect(int id) async {
|
||||
final db = await storage.db;
|
||||
List<Map<String, dynamic>> data = await db.rawQuery('SELECT collected FROM widget WHERE id = ?', [id]);
|
||||
bool collected = data.toList()[0]['collected']==1;
|
||||
return await db.rawQuery(
|
||||
"UPDATE widget SET collected = ? "
|
||||
"WHERE id = ?",
|
||||
[collected ? 0 : 1, id]);
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> queryCollect() async {
|
||||
final db = await storage.db;
|
||||
return await db.rawQuery("SELECT * "
|
||||
"FROM widget WHERE collected = 1 ORDER BY family,lever DESC");
|
||||
}
|
||||
|
||||
Future<bool> collected(int id) async {
|
||||
final db = await storage.db;
|
||||
List<Map<String, dynamic>> data = await db.rawQuery("SELECT collected "
|
||||
"FROM widget WHERE id = ?");
|
||||
|
||||
if(data.length>0){
|
||||
return data[0]['collected'] == 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SearchArgs {
|
||||
|
||||
50
lib/repositories/local_db.dart
Normal file
50
lib/repositories/local_db.dart
Normal file
@@ -0,0 +1,50 @@
|
||||
import 'package:flutter_unit/repositories/dao/like_dao.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
import 'dao/category_dao.dart';
|
||||
import 'dao/node_dao.dart';
|
||||
import 'dao/widget_dao.dart';
|
||||
|
||||
class LocalDb {
|
||||
Database _database;
|
||||
|
||||
LocalDb._();
|
||||
|
||||
static LocalDb instance = LocalDb._();
|
||||
|
||||
WidgetDao _widgetDao;
|
||||
CategoryDao _categoryDao;
|
||||
NodeDao _nodeDao;
|
||||
LikeDao _likeDao;
|
||||
|
||||
WidgetDao get widgetDao => _widgetDao;
|
||||
|
||||
CategoryDao get categoryDao => _categoryDao;
|
||||
|
||||
NodeDao get nodeDao => _nodeDao;
|
||||
|
||||
LikeDao get likeDao => _likeDao;
|
||||
|
||||
Database get db => _database;
|
||||
|
||||
Future<void> initDb({String name = "flutter.db"}) async {
|
||||
if (_database != null) return;
|
||||
String databasesPath = await getDatabasesPath();
|
||||
String dbPath = path.join(databasesPath, name);
|
||||
|
||||
_database = await openDatabase(dbPath);
|
||||
|
||||
_widgetDao = WidgetDao(_database);
|
||||
_categoryDao = CategoryDao(_database);
|
||||
_nodeDao = NodeDao(_database);
|
||||
_likeDao = LikeDao(_database);
|
||||
|
||||
print('初始化数据库....');
|
||||
}
|
||||
|
||||
Future<void> closeDb() async {
|
||||
await _database.close();
|
||||
_database = null;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ class LocalStorage {
|
||||
|
||||
static String tokenKey= "token_key";
|
||||
static String userKey= "user_key";
|
||||
static String dbVersionKey= "db_version_key";
|
||||
|
||||
static SharedPreferences _sp;
|
||||
|
||||
@@ -27,6 +28,14 @@ class LocalStorage {
|
||||
return (await sp).get(key);
|
||||
}
|
||||
|
||||
static Future<bool> saveInt(String key, int value) async {
|
||||
return (await sp).setInt(key, value);
|
||||
}
|
||||
|
||||
static Future<int> getInt(String key) async {
|
||||
return (await sp).getInt(key);
|
||||
}
|
||||
|
||||
static Future<bool> remove(String key) async {
|
||||
return (await sp).remove(key);
|
||||
}
|
||||
@@ -26,7 +26,6 @@ abstract class CategoryRepository {
|
||||
// 根据 Category 数据 同步 收藏集
|
||||
Future<bool> syncCategoryByData(String data,String likeData);
|
||||
|
||||
|
||||
//添加收藏集
|
||||
Future<bool> addCategory(CategoryPo categoryPo);
|
||||
|
||||
|
||||
@@ -6,9 +6,11 @@ import 'package:flutter_unit/model/widget_model.dart';
|
||||
import 'package:flutter_unit/repositories/bean/category_po.dart';
|
||||
import 'package:flutter_unit/repositories/bean/widget_po.dart';
|
||||
import 'package:flutter_unit/repositories/dao/category_dao.dart';
|
||||
import 'package:flutter_unit/repositories/local_db.dart';
|
||||
import 'package:flutter_unit/repositories/rep/category_repository.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
import '../../app_storage.dart';
|
||||
import '../../app_start.dart';
|
||||
|
||||
|
||||
|
||||
@@ -19,13 +21,10 @@ import '../../app_storage.dart';
|
||||
/// 说明:
|
||||
|
||||
class CategoryDbRepository implements CategoryRepository {
|
||||
final AppStorage storage;
|
||||
|
||||
CategoryDao _categoryDao;
|
||||
CategoryDao get _categoryDao => LocalDb.instance.categoryDao;
|
||||
|
||||
CategoryDbRepository(this.storage) {
|
||||
_categoryDao = CategoryDao(storage);
|
||||
}
|
||||
Database get db => LocalDb.instance.db;
|
||||
|
||||
@override
|
||||
Future<bool> addCategory(CategoryPo categoryPo) async {
|
||||
@@ -102,8 +101,6 @@ class CategoryDbRepository implements CategoryRepository {
|
||||
|
||||
@override
|
||||
Future<List<dynamic>> loadLikesData() async {
|
||||
|
||||
final db = await storage.db;
|
||||
var likes = await db.rawQuery("SELECT id "
|
||||
"FROM widget WHERE collected = 1 ORDER BY family,lever DESC");
|
||||
var likesData = likes.map((e) => e['id']).toList();
|
||||
@@ -114,7 +111,6 @@ class CategoryDbRepository implements CategoryRepository {
|
||||
|
||||
Future<void> _setLikes(List<dynamic> ids) async {
|
||||
if(ids.isEmpty) return;
|
||||
final db = await storage.db;
|
||||
String sql = 'UPDATE widget SET collected = 1 WHERE ';
|
||||
for(int i=0;i<ids.length;i++){
|
||||
if(i==0){
|
||||
|
||||
@@ -3,8 +3,10 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
|
||||
import 'package:flutter_unit/repositories/app_storage.dart';
|
||||
import 'package:flutter_unit/repositories/app_start.dart';
|
||||
import 'package:flutter_unit/repositories/bean/widget_po.dart';
|
||||
import 'package:flutter_unit/repositories/dao/like_dao.dart';
|
||||
import 'package:flutter_unit/repositories/local_db.dart';
|
||||
import 'package:flutter_unit/repositories/dao/node_dao.dart';
|
||||
import 'package:flutter_unit/repositories/dao/widget_dao.dart';
|
||||
import 'package:flutter_unit/model/enums.dart';
|
||||
@@ -20,15 +22,10 @@ import 'package:path_provider/path_provider.dart';
|
||||
/// 说明 : Widget数据仓库
|
||||
|
||||
class WidgetDbRepository implements WidgetRepository {
|
||||
final AppStorage storage;
|
||||
|
||||
WidgetDao _widgetDao;
|
||||
NodeDao _nodeDao;
|
||||
|
||||
WidgetDbRepository(this.storage) {
|
||||
_widgetDao = WidgetDao(storage);
|
||||
_nodeDao = NodeDao(storage);
|
||||
}
|
||||
WidgetDao get _widgetDao => LocalDb.instance.widgetDao;
|
||||
NodeDao get _nodeDao => LocalDb.instance.nodeDao;
|
||||
LikeDao get _likeDao => LocalDb.instance.likeDao;
|
||||
|
||||
@override
|
||||
Future<List<WidgetModel>> loadWidgets(WidgetFamily family) async {
|
||||
@@ -39,10 +36,10 @@ class WidgetDbRepository implements WidgetRepository {
|
||||
|
||||
@override
|
||||
Future<List<WidgetModel>> loadLikeWidgets() async {
|
||||
List<Map<String, dynamic>> data = await _widgetDao.queryCollect();
|
||||
List<int> likeIds = await _likeDao.likeWidgetIds();
|
||||
List<Map<String, dynamic>> data = await _widgetDao.queryByIds(likeIds);
|
||||
List<WidgetPo> widgets = data.map((e) => WidgetPo.fromJson(e)).toList();
|
||||
List<WidgetModel> list = widgets.map(WidgetModel.fromPo).toList();
|
||||
return list;
|
||||
return widgets.map(WidgetModel.fromPo).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -71,12 +68,12 @@ class WidgetDbRepository implements WidgetRepository {
|
||||
Future<void> toggleLike(
|
||||
int id,
|
||||
) {
|
||||
return _widgetDao.toggleCollect(id);
|
||||
return _likeDao.toggleCollect(id);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future<bool> collected(int id) async{
|
||||
return await _widgetDao.collected(id);
|
||||
Future<void> collected(int id) async{
|
||||
return await _likeDao.like(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,5 +19,5 @@ abstract class WidgetRepository {
|
||||
|
||||
Future<List<WidgetModel>> loadLikeWidgets();
|
||||
|
||||
Future<bool> collected(int id);
|
||||
Future<void> collected(int id);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'dart:convert';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter_unit/app/utils/http_utils/http_util.dart';
|
||||
import 'package:flutter_unit/repositories/dao/local_storage.dart';
|
||||
import 'package:flutter_unit/repositories/local_storage.dart';
|
||||
import 'package:flutter_unit/user_system/model/user.dart';
|
||||
import 'package:jwt_decoder/jwt_decoder.dart';
|
||||
|
||||
|
||||
@@ -119,9 +119,11 @@ class CouponWidgetListItem extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Text(data.name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.bold,
|
||||
decoration: (data.deprecated)?TextDecoration.lineThrough:TextDecoration.none,
|
||||
decorationThickness: 2,
|
||||
shadows: [
|
||||
Shadow(color: Colors.white, offset: Offset(.3, .3))
|
||||
])),
|
||||
|
||||
@@ -118,9 +118,11 @@ class SimpleWidgetListItem extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Text(data.name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.bold,
|
||||
decoration: (data.deprecated)?TextDecoration.lineThrough:TextDecoration.none,
|
||||
decorationThickness: 2,
|
||||
shadows: [
|
||||
Shadow(color: Colors.white, offset: Offset(.3, .3))
|
||||
])),
|
||||
|
||||
@@ -112,9 +112,11 @@ class TechnoWidgetListItem extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Text(data.name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.bold,
|
||||
decoration: (data.deprecated)?TextDecoration.lineThrough:TextDecoration.none,
|
||||
decorationThickness: 2,
|
||||
shadows: [
|
||||
Shadow(color: Colors.white, offset: Offset(.3, .3))
|
||||
])),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_unit/repositories/app_storage.dart';
|
||||
import 'package:flutter_unit/repositories/app_start.dart';
|
||||
import 'package:flutter_unit/repositories/local_db.dart';
|
||||
import 'package:flutter_unit/repositories/rep/impl/catagory_db_repository.dart';
|
||||
import 'package:flutter_unit/repositories/rep/impl/widget_db_repository.dart';
|
||||
import 'package:flutter_unit/repositories/rep/widget_repository.dart';
|
||||
@@ -16,7 +17,7 @@ import 'package:flutter_unit/blocs/bloc_exp.dart';
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明: Bloc提供器包裹层
|
||||
|
||||
final AppStorage storage = AppStorage();
|
||||
final AppStart storage = AppStart();
|
||||
|
||||
class BlocWrapper extends StatefulWidget {
|
||||
final Widget child;
|
||||
@@ -28,9 +29,9 @@ class BlocWrapper extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _BlocWrapperState extends State<BlocWrapper> {
|
||||
final WidgetRepository repository = WidgetDbRepository(storage);
|
||||
final WidgetRepository repository = WidgetDbRepository();
|
||||
|
||||
final categoryBloc = CategoryBloc(repository: CategoryDbRepository(storage));
|
||||
final categoryBloc = CategoryBloc(repository: CategoryDbRepository());
|
||||
final authBloc = AuthenticBloc()..add(const AppStarted());
|
||||
|
||||
@override
|
||||
@@ -79,6 +80,7 @@ class _BlocWrapperState extends State<BlocWrapper> {
|
||||
void dispose() {
|
||||
categoryBloc.close();
|
||||
authBloc.close();
|
||||
LocalDb.instance.closeDb();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,12 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_unit/app/router/unit_router.dart';
|
||||
import 'package:flutter_unit/blocs/bloc_exp.dart';
|
||||
import 'package:flutter_unit/model/category_model.dart';
|
||||
import 'package:flutter_unit/views/components/permanent/circle.dart';
|
||||
import 'package:flutter_unit/views/components/project/default/loading_shower.dart';
|
||||
import 'package:flutter_unit/views/components/project/no_more_widget.dart';
|
||||
|
||||
import 'package:flutter_unit/model/category_model.dart';
|
||||
import 'package:flutter_unit/views/components/project/dialogs/delete_category_dialog.dart';
|
||||
import 'package:flutter_unit/views/components/project/items/category_list_item.dart';
|
||||
import 'package:flutter_unit/views/components/project/no_more_widget.dart';
|
||||
|
||||
import 'edit_category_panel.dart';
|
||||
import 'empty_category.dart';
|
||||
@@ -26,7 +25,6 @@ class CategoryPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<CategoryBloc, CategoryState>(builder: (ctx, state) {
|
||||
print(state);
|
||||
if (state is CategoryLoadedState) {
|
||||
return CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
@@ -47,18 +45,21 @@ class CategoryPage extends StatelessWidget {
|
||||
|
||||
_buildContent(BuildContext context, CategoryLoadedState state) {
|
||||
return SliverPadding(
|
||||
padding: EdgeInsets.only(top:10, left: 10, right: 10, bottom: 0),
|
||||
padding: const EdgeInsets.only(top: 10, left: 10, right: 10, bottom: 0),
|
||||
sliver: SliverGrid(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(_, index) => Container(
|
||||
child: GestureDetector(
|
||||
onTap: () => _toDetailPage(context, state.categories[index]),
|
||||
child: CategoryListItem(
|
||||
data: state.categories[index],
|
||||
onDeleteItemClick: (model) => _deleteCollect(context, model),
|
||||
onEditItemClick: (model) => _editCollect(context, model),
|
||||
)),
|
||||
),
|
||||
(_, index) => Container(
|
||||
child: GestureDetector(
|
||||
onTap: () =>
|
||||
_toDetailPage(context, state.categories[index]),
|
||||
child: CategoryListItem(
|
||||
data: state.categories[index],
|
||||
onDeleteItemClick: (model) =>
|
||||
_deleteCollect(context, model),
|
||||
onEditItemClick: (model) =>
|
||||
_editCollect(context, model),
|
||||
)),
|
||||
),
|
||||
childCount: state.categories.length),
|
||||
gridDelegate: gridDelegate),
|
||||
);
|
||||
|
||||
@@ -203,7 +203,9 @@ class _WidgetDetailPageState extends State<WidgetDetailPage> {
|
||||
elevation: 2,
|
||||
shadowColor: Colors.orange,
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
labelStyle: const TextStyle(fontSize: 12, color: Colors.white),
|
||||
labelStyle: TextStyle(fontSize: 12, color: Colors.white,
|
||||
decoration: (e.deprecated)?TextDecoration.lineThrough:TextDecoration.none,
|
||||
decorationThickness: 2,),
|
||||
label: Text('${e.name}'),
|
||||
))
|
||||
.toList(),
|
||||
@@ -245,6 +247,8 @@ class WidgetDetailTitle extends StatelessWidget {
|
||||
model.nameCN,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
decoration: (model.deprecated)?TextDecoration.lineThrough:TextDecoration.none,
|
||||
decorationThickness: 2,
|
||||
color: Color(0xff1EBBFD),
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user