提交 26d783a7 authored 作者: yueweilu's avatar yueweilu

sqlite

上级 7d0e3e5b
......@@ -16,6 +16,11 @@ class Global {
// InAppLocalhostServer(documentRoot: '$documentRoot/',shared: true);
// await localhostServer.start();
// print('本地服务器已成功启动,根目录为: $documentRoot');
SqlManager.init();
WidgetsBinding.instance?.addObserver(AppLifecycleObserver());
await Future.wait([
// 配置存储
......@@ -33,3 +38,11 @@ class Global {
});
}
}
class AppLifecycleObserver extends WidgetsBindingObserver {
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused || state == AppLifecycleState.detached) {
SqlManager.closeDatabase(); // 应用进入后台时关闭数据库连接
}
}
}
\ No newline at end of file
......@@ -26,8 +26,11 @@ void main() {
// print('2222222---------$name');
// final result = EncryptUtil.aesDecrypt(name);
// Console.log('解密--------------------------$result');
runApp(const MyApp());
//FlutterNativeSplash.remove();
});
});
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
......
......@@ -175,6 +175,21 @@ class LibraryController extends GetxController with GetTickerProviderStateMixin{
/// 获取tab分类数据
void _getTabs() async {
Map<String, dynamic> data = {
'types': 1,
'book_id': 123,
'chapter_id': 456,
// 'is_open': 1,
// 'color': 'blue',
// 'content': 'This is a note content',
// 'del': 0,
// 'positioning': 'top',
// 'note': 'This is a note',
};
await SqlManager.insertData(data);
categories = await LibraryAPI.categories();
tabController.dispose();
tabController = TabController(length:categories.length, vsync: this);
......
......@@ -57,6 +57,10 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
// 网络状态
bool netStatus = false;
// 当前html名称 0-318.html
late String currentHtmlName = '';
///------------------------------------------ 页面 生命周期--------------------------------------------------------
@override
void onInit() {
......@@ -73,19 +77,8 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
_getChapters();
netStatus = await Tools.checkCurrentNetStatus();
// // 判断是否有离线文件 如果有使用离线阅读
// final exist = await _isExistFile(bookId);
// // 没有网并且有离线文件 离线阅读
// String path = await _getDirectory();
// String finalPath = '$path/174/0-318.html';
// final content = await readHtmlFileContent(finalPath);
// Console.log('原始内容-----------------$content');
// String htmlStr = EncryptUtil.aesDecrypt(content!);
// Console.log('解密-----------------$htmlStr');
// if (netStatus && exist){
// Console.log('-------------使用本地文件-------------------');
// webViewController.loadData(data: htmlStr??'');
// }
readLocalHtml('');
readChapter(type: 1);
super.onReady();
}
......@@ -102,6 +95,21 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
}
///------------------------------------------ 页面 生命周期--------------------------------------------------------
void chooseTool(ToolModel selectedModel){
for (var model in tools) {
// 如果当前遍历到的工具是选中的,并且不是点击的工具,则取消选中
if (model.selected && model != selectedModel) {
model.selected = false;
}
// 如果当前遍历到的工具是点击的工具,切换选中状态
else if (model == selectedModel) {
model.selected = !model.selected;
}
}
toolModel = selectedModel;
update();
}
void setShow(bool value) {
_show = !value;
update();
......@@ -364,22 +372,6 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
void chooseTool(ToolModel selectedModel){
for (var model in tools) {
// 如果当前遍历到的工具是选中的,并且不是点击的工具,则取消选中
if (model.selected && model != selectedModel) {
model.selected = false;
}
// 如果当前遍历到的工具是点击的工具,切换选中状态
else if (model == selectedModel) {
model.selected = !model.selected;
}
}
toolModel = selectedModel;
update();
}
// AnimationController get controller => _controller;
void _onCommentFocusChanged() {
......@@ -412,45 +404,14 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
/// 获取目录信息
void _getChapters() async {
chapters = await LibraryAPI.chapters(bookId: bookId);
update();
}
/// 添加阅读时长
void _addReadTime({required type}) async{
final result = await LibraryAPI.addReadTime(bookId: bookId, readTypes: type);
}
/// 获取离线文件路径
void getBookDown() async{
final exit = await _isExistFile(bookId);
// 存在离线文件
if (exit){
}
else{
final result = await LibraryAPI.getbookDownloadParam(bookId: bookId);
Console.log('----------_getBookDown------------------${result.download}');
// final String savePath = await _getDirectory();
// LibraryAPI.downBookByUrl(url: result.download!,savePath: '$savePath$bookId.zip',onReceiveProgress: (int received,int total){
// if (total !=-1){
// double progress = (received / total) * 100;
// Console.log('Download progress: $progress%');
// }
// });
extractZipFileFromCache(result.download!);
}
}
///------------------------------------------离线逻辑--------------------------------------------------------
// 下载文件
Future<void> extractZipFileFromCache(String url) async {
// 从缓存中获取 ZIP 文件
var file = await DefaultCacheManager().getSingleFile(url);
if (file != null) {
Toast.show('离线成功');
// 读取 ZIP 文件内容
Uint8List bytes = await file.readAsBytes();
// 解压缩 ZIP 文件
......@@ -468,12 +429,12 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
print('解压缩文件:$fileName,保存路径:$filePath');
}
}
} else {
print('未找到缓存中的文件或文件不存在');
}
}
// 判断是否存在离线文件
Future<bool> _isExistFile(String bookId) async {
String directoryPath = await _getDirectory();
......@@ -493,6 +454,48 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
}
// 本地阅读 读取上一章节 或 下一章节
// 0 上一章节
// 1 下一章节
Future<String> readChapter({required int type}) async {
Console.log('---------------获取所有html---------------------------------');
String docPath = await _getDirectory();
String filePath = '$docPath/$bookId';
Directory directory = Directory(filePath);
// 获取目录下的所有文件
List<FileSystemEntity> files = directory.listSync(recursive: true);
int findIndex = int.parse(currentHtmlName.split('-').first);
currentHtmlName;
if(type == 0){
findIndex--;
if(findIndex <0){
// 已到最前
return '-1';
}
}
else{
findIndex++;
if(findIndex >files.length -1){
// 已到最后
return '1';
}
}
// 打印所有 HTML 文件路径
for (var file in files) {
if (file is File && file.path.toLowerCase().endsWith('.html')) {
String fileName = path.basename(file.path);
if (int.parse(fileName.split('-').first) == 2){
print('HTML File--------------------------------${file.path}');
return file.path;
}
}
}
return '0';
}
// 读取html内容
Future<String?> readHtmlFileContent(String filePath) async {
try {
......@@ -514,6 +517,40 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
return directory!.path;
}
/// 获取目录信息
void _getChapters() async {
chapters = await LibraryAPI.chapters(bookId: bookId);
update();
}
/// 添加阅读时长
void _addReadTime({required type}) async{
final result = await LibraryAPI.addReadTime(bookId: bookId, readTypes: type);
}
/// 获取离线文件路径
void getBookDown() async{
final exit = await _isExistFile(bookId);
// 存在离线文件
if (exit){
}
else{
final result = await LibraryAPI.getbookDownloadParam(bookId: bookId);
Console.log('----------_getBookDown------------------${result.download}');
// final String savePath = await _getDirectory();
// LibraryAPI.downBookByUrl(url: result.download!,savePath: '$savePath$bookId.zip',onReceiveProgress: (int received,int total){
// if (total !=-1){
// double progress = (received / total) * 100;
// Console.log('Download progress: $progress%');
// }
// });
extractZipFileFromCache(result.download!);
}
}
///------------------------------------------ app 生命周期--------------------------------------------------------
// 当应用程序从后台切换到前台并变为活动状态时调用。这通常在用户从其他应用程序返回到你的应用程序时发生
......
......@@ -34,6 +34,7 @@ import '../../widgets/index.dart';
import '../book_category/index.dart';
import '../user_discuss_des/index.dart';
import '../user_notes_des/index.dart';
import 'package:path/path.dart' as path;
part 'view.dart';
part 'controller.dart';
......
......@@ -64,8 +64,8 @@ class _ReadPageState extends State<ReadPage> {
children: [
InAppWebView(
initialUrlRequest: URLRequest(
// url: Uri.parse('http://150.158.138.40:9200/read.html'),
url: Uri.parse("/storage/emulated/0/Android/data/com.zijin.book.flutter_book/files/174/7-325.html"),
url: Uri.parse('http://150.158.138.40:9200/read.html'),
// url: Uri.parse("/storage/emulated/0/Android/data/com.zijin.book.flutter_book/files/174/7-325.html"),
),
contextMenu: ContextMenu(
options: ContextMenuOptions(hideDefaultSystemContextMenuItems: true),
......
......@@ -11,6 +11,8 @@ const String kLocalPassword = 'local_password';
const String kLocalUserInfo = 'local_user_info';
const String kSearchHistory = 'search_history';
const String kFailOrder = 'failOrder';
const String kNoteTable = 'members_book_notes';
const String kReadTable = 'read_history';
......
......@@ -28,6 +28,8 @@ import 'package:flutter_oss_aliyun/flutter_oss_aliyun.dart';
import '../models/index.dart';
import '../widgets/index.dart';
import 'package:sqflite/sqflite.dart';
part 'constants.dart';
part 'screen.dart';
......@@ -43,3 +45,4 @@ part 'clear_cache_util.dart';
part 'access.dart';
part 'assets_picker.dart';
part 'oss.dart';
part 'sql.dart';
\ No newline at end of file
part of utils;
class SqlManager {
static const _version = 1;
static const _name= "zi_jing_app_flutter.db";
static Database? _database;
///初始化
static init() async {
// open the database
var databasesPath = await getDatabasesPath();
// var databasesPath = await Tools.getDirectory();
String dbName = _name;
Console.log('databasesPath---------$databasesPath');
if(databasesPath != null) {
String path = databasesPath + dbName;
if (Platform.isIOS) {
path = "$databasesPath/$dbName";
}
_database = await openDatabase(path, version: _version,
onCreate: (Database db, int version) async {
// When creating the db, create the table
// await db.execute("CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT, value INTEGER, num REAL)");
// 笔记表
await db.execute("CREATE TABLE $kNoteTable ("
"id INTEGER PRIMARY KEY, "
"types INTEGER, "
"book_id INTEGER, "
"chapter_id INTEGER, "
"is_open INTEGER, "
"color TEXT, "
"content TEXT, "
"upload INTEGER, "
"positioning TEXT, "
"note TEXT)"
);
// // 阅读章节表
await db.execute("CREATE TABLE $kReadTable ("
"id INTEGER PRIMARY KEY, "
"book_id INTEGER, "
"chapter_id INTEGER)"
);
});
}
}
// 关闭数据库
static Future<void> closeDatabase() async {
await _database?.close();
}
// 查询所有没有上传的数据
static Future<List<Map<String, dynamic>>> queryNoUploadData() async {
List<Map<String, dynamic>> results = await _database!.query(
'members_book_notes',
where: 'upload = ?',
whereArgs: [0],
);
return results.isNotEmpty ? results : [];
}
// 将所有 upload 为 0 的数据的 upload 字段值更新为 1
static Future<void> updateUploadStatus() async {
await _database!.update(
'members_book_notes',
{'upload': 1},
where: 'upload = ?',
whereArgs: [0],
);
}
// 根据 book_id 查询当前读到的 章节
static Future<int> queryDataByBookId(int bookId) async {
List<Map<String, dynamic>> results = await _database!.query(
'read_history',
where: 'book_id = ?',
whereArgs: [bookId],
);
return results.isNotEmpty ? results.first['chapter_id'] : 0;
}
// 根据 book_id 写入当前读到的 章节
static Future<int?> updateReadHistoryBookId(int bookId ,int chapterId) async {
final result = await _database?.update(
'members_book_notes',
{'chapter_id':chapterId},
where: 'book_id = ?',
whereArgs: [bookId],
);
return result;
}
// 插入数据
static Future<void> insertData(Map<String, dynamic> data) async {
final result = await _database?.insert(
'members_book_notes',
data,
conflictAlgorithm: ConflictAlgorithm.replace,
);
Console.log('插入数据-------------------------------$result');
}
// 查询所有数据
static Future<List<Map<String, dynamic>>?> queryAllData() async {
return await _database?.query('members_book_notes');
}
// 根据 ID 查询数据
static Future<Map<String, dynamic>?> queryDataById(int id) async {
List<Map<String, dynamic>> results = await _database!.query(
'members_book_notes',
where: 'id = ?',
whereArgs: [id],
);
return results.isNotEmpty ? results.first : null;
}
// 更新数据
static Future<void> updateData(int id, Map<String, dynamic> newData) async {
await _database?.update(
'members_book_notes',
newData,
where: 'id = ?',
whereArgs: [id],
);
}
// 删除数据
static Future<void> deleteData(int id) async {
await _database?.delete(
'members_book_notes',
where: 'id = ?',
whereArgs: [id],
);
}
}
......@@ -75,6 +75,27 @@ abstract class Tools {
// // I am not connected to any network.
// }
}
// static void readChapter({required int type}) async {
// Console.log('---------------获取所有html---------------------------------');
// String docPath = await getDirectory();
// String filePath = '$docPath/$1';
// Directory directory = Directory(filePath);
// // 获取目录下的所有文件
// List<FileSystemEntity> files = directory.listSync(recursive: true);
//
// // 打印所有 HTML 文件路径
// for (var file in files) {
// if (file is File && file.path.toLowerCase().endsWith('.html')) {
// Console.log('HTML File: ${file.path}');
// }
// }
// Console.log('---------------获取所有html---------------------------------');
// // 先找到对应文件
// if(type == 0){
//
// }
// }
}
......
......@@ -867,7 +867,7 @@ packages:
source: hosted
version: "1.9.1"
sqflite:
dependency: transitive
dependency: "direct main"
description:
name: sqflite
sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6
......
......@@ -113,6 +113,8 @@ dependencies:
archive: ^3.1.2
# 判断当前网络情况
connectivity_plus: ^5.0.2
# 数据库
sqflite: ^2.3.2
dev_dependencies:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论