提交 36f5cc28 authored 作者: yueweilu's avatar yueweilu

离线逻辑

上级 4f37ba39
......@@ -302,5 +302,20 @@ abstract class LibraryAPI {
return false;
}
/// 15、批量上传离线笔记、高亮、划线的内容
static Future <bool> uploadOffline({
required String node,
}) async {
final result = await HttpService.to.post(
'/v1/book/Information/addOfflineNotes',
params: {
'nodes_list':node,
},
);
if (result.data is Map && result.data['is_success'] == 1){
return true;
}
return false;
}
}
\ No newline at end of file
......@@ -18,8 +18,6 @@ class Global {
// print('本地服务器已成功启动,根目录为: $documentRoot');
SqlManager.init();
WidgetsBinding.instance?.addObserver(AppLifecycleObserver());
await Future.wait([
......
......@@ -56,6 +56,8 @@ class BookDetailController extends GetxController with GetSingleTickerProviderSt
/// 获取图书详细信息
void getBookDetails() async {
bookDetails = await LibraryAPI.details(bookId:bookId);
// 将阅读最后章节写入到数据库
SqlManager.updateReadHistoryByBookId(int.parse(bookId), bookDetails.chapterId!.toInt());
update();
}
/// 收藏 与 取消收藏
......
......@@ -73,16 +73,38 @@ class LibraryController extends GetxController with GetTickerProviderStateMixin{
vsync: this,
duration: const Duration(milliseconds: 100),
);
super.onInit();
}
@override
void onReady() {
void onReady() async {
// 获取标签数据
_getLabels();
_getAds();
onRefresh();
Map<String, dynamic> data = {
'types': 1,
'book_id': 175,
'chapter_id': 334,
'is_open': 1,
'color': 'blue',
'content': 'This is a note content',
'upload': 0,
'positioning': 'top',
'note': 'This is a note',
'node_id': 0,
};
await SqlManager.insertData(data);
final result = await Tools.checkCurrentNetStatus();
// 有网络的时候上传 笔记
if (result){
upload();
}
super.onReady();
}
......@@ -176,20 +198,6 @@ 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);
......@@ -232,6 +240,18 @@ class LibraryController extends GetxController with GetTickerProviderStateMixin{
}
}
/// 批量上传离线笔记、高亮、划线的内容
void upload() async{
List<Map<String, dynamic>> data = await SqlManager.queryNoUploadData();
Console.log('查询到的数据----------------------------------------------------$data');
final result = await LibraryAPI.uploadOffline(node: jsonEncode(data));
// 上传成功后 更新数据库中的字段
if (result) {
SqlManager.updateUploadStatus();
}
}
/// 获取图书列表数据
Future<void> _getBooks([bool isRefresh = false]) async {
......
library library;
import 'dart:convert';
import 'package:azlistview/azlistview.dart';
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
......
......@@ -75,10 +75,25 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
// 上报开始阅读时间
_addReadTime(type: 'open');
_getChapters();
netStatus = await Tools.checkCurrentNetStatus();
// // 判断是否有离线文件 如果有使用离线阅读
readLocalHtml('');
readChapter(type: 1);
final exist = await _isExistFile(bookId);
if (netStatus && exist){
// 1、从数据库中获取读到那个章节
chapterId = await SqlManager.queryReadHistoryByBookId(int.parse(bookId));
chapterName = getChapterName(chapterId);
// 2、通过 chapterId 获取 对应离线的 html路径
String toReadHtmlPath = await getLocalReadHtml(chapterId);
// 3、开始读书
read(toReadHtmlPath);
// 获取当前 文件名称
currentHtmlName = path.basename(toReadHtmlPath);
update();
}
super.onReady();
}
......@@ -141,6 +156,8 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
}
// 初始化录音组件
Future<void> openTheRecorder() async {
// 获取权限
......@@ -198,7 +215,7 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
startRecording = false;
final path = await _mRecorder.stopRecorder();
var duration = await audioPlayer.setFilePath(path!);
print('-----duration---------------------$duration------');
Console.log('-----duration---------------------$duration------');
AudioModel audioModel = AudioModel(path: path,duration: Tools.formatDuration(duration!));
discussInputAudios.add(audioModel);
update();
......@@ -209,7 +226,7 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
String twoDigits(int n) => n.toString().padLeft(2, '0');
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return '${duration.inHours}:$twoDigitMinutes:${twoDigitSeconds}';
return '${duration.inHours}:$twoDigitMinutes:$twoDigitSeconds';
}
......@@ -276,7 +293,7 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
// return result;
OssTool tool = OssTool('zxts-comment-file');
final response = await tool.putObjectFile(path);
print('------response--------------------------${response.realUri}');
Console.log('------response--------------------------${response.realUri}');
return response.realUri.toString();
}
......@@ -426,12 +443,12 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
File(filePath)
..createSync(recursive: true)
..writeAsBytesSync(file.content as List<int>);
print('解压缩文件:$fileName,保存路径:$filePath');
('解压缩文件:$fileName,保存路径:$filePath');
}
}
} else {
print('未找到缓存中的文件或文件不存在');
Console.log('未找到缓存中的文件或文件不存在');
}
}
......@@ -441,12 +458,12 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
Directory directory = Directory(directoryPath);
bool directoryExists = await directory.exists();
if (directoryExists) {
print('存在名为 "$bookId" 的文件夹');
Console.log('存在名为 "$bookId" 的文件夹');
existDownFile = await Directory('${directory.path}/$bookId').exists();
}
else {
print('不存在名为 "$bookId" 的文件夹');
Console.log('不存在名为 "$bookId" 的文件夹');
existDownFile = false;
}
update();
......@@ -454,10 +471,46 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
}
Future<String> getLocalReadHtml(String chapterId) async{
String docPath = await _getDirectory();
String filePath = '$docPath/$bookId';
Directory directory = Directory(filePath);
// 获取目录下的所有文件
List<FileSystemEntity> files = directory.listSync(recursive: true);
for (var file in files) {
if (file is File && file.path.toLowerCase().endsWith('.html')) {
String fileName = path.basenameWithoutExtension(file.path);
if (fileName.split('-').last == chapterId){
return file.path;
}
}
}
return '';
}
// 开始阅读离线
void read(String toReadHtmlPath) async {
// 3、获取 离线文件的内容
final content = await readHtmlFileContent(toReadHtmlPath);
// 4、解密离线的内容
String htmlStr = EncryptUtil.aesDecrypt(content!);
// 5、将离线内容写入临时文件
String directoryPath = path.dirname(toReadHtmlPath);
String writeFilePath = '$directoryPath/read.html';
// 6、创建临时文件
File file = File(writeFilePath);
// 7、将HTML内容写入文件
await file.writeAsString(htmlStr);
webViewController.loadUrl(urlRequest: URLRequest(
url: Uri.parse(writeFilePath),
));
}
// 本地阅读 读取上一章节 或 下一章节
// 0 上一章节
// 1 下一章节
Future<String> readChapter({required int type}) async {
Future<void> readChapter({required int type}) async {
Console.log('---------------获取所有html---------------------------------');
String docPath = await _getDirectory();
......@@ -467,33 +520,45 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
List<FileSystemEntity> files = directory.listSync(recursive: true);
int findIndex = int.parse(currentHtmlName.split('-').first);
currentHtmlName;
if(type == 0){
findIndex--;
if(findIndex <0){
Toast.show('前面已没有章节');
// 已到最前
return '-1';
return ;
}
}
else{
findIndex++;
if(findIndex >files.length -1){
// 已到最后
return '1';
return ;
}
}
String toReadHtmlPath = '';
// 打印所有 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){
String fileName = path.basenameWithoutExtension(file.path);
if (int.parse(fileName.split('-').first) == findIndex){
print('HTML File--------------------------------${file.path}');
return file.path;
toReadHtmlPath = file.path;
chapterId = fileName.split('-').last;
chapterName = getChapterName(chapterId);
break;
}
}
}
return '0';
// 开始读书
read(toReadHtmlPath);
update();
}
// 读取html内容
......@@ -504,12 +569,30 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
return fileContent;
}
catch (e){
print('Error reading file: $e');
Console.log('Error reading file: $e');
return '';
}
}
// 通过 chapter_id 获取 chapter_name
String getChapterName(String chapterId){
for (ChapterModel model in chapters){
if ('${model.id}' == chapterId){
return model.name??'';
}
if (model.children !=null){
for (ChapterModel subModel in model.children!){
if ('${subModel.id}' == chapterId){
return subModel.name??'';
}
}
}
}
return '';
}
//获取存储目录
Future<String> _getDirectory() async {
// getTemporaryDirectory
......@@ -517,6 +600,8 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
return directory!.path;
}
/// 获取目录信息
void _getChapters() async {
chapters = await LibraryAPI.chapters(bookId: bookId);
......@@ -526,6 +611,7 @@ class ReadController extends FullLifeCycleController with GetSingleTickerProvide
/// 添加阅读时长
void _addReadTime({required type}) async{
final result = await LibraryAPI.addReadTime(bookId: bookId, readTypes: type);
Console.log('-------------$result-------------------');
}
/// 获取离线文件路径
void getBookDown() async{
......
......@@ -120,6 +120,11 @@ class _ReadPageState extends State<ReadPage> {
readController.titleInput.text = args.first.toString();
});
// 监听 上一节 下一节
controller.addJavaScriptHandler(handlerName: 'readCallBack', callback: (args){
});
},
),
// AnimatedPositioned(
......
......@@ -32,6 +32,7 @@ class SqlManager {
"types INTEGER, "
"book_id INTEGER, "
"chapter_id INTEGER, "
"node_id INTEGER, "
"is_open INTEGER, "
"color TEXT, "
"content TEXT, "
......@@ -65,15 +66,16 @@ class SqlManager {
}
// 将所有 upload 为 0 的数据的 upload 字段值更新为 1
static Future<void> updateUploadStatus() async {
await _database!.update(
final result = await _database!.update(
'members_book_notes',
{'upload': 1},
where: 'upload = ?',
whereArgs: [0],
);
Console.log('更新数据-------------------------------$result');
}
// 根据 book_id 查询当前读到的 章节
static Future<int> queryDataByBookId(int bookId) async {
static Future<String> queryReadHistoryByBookId(int bookId) async {
List<Map<String, dynamic>> results = await _database!.query(
'read_history',
where: 'book_id = ?',
......@@ -83,9 +85,9 @@ class SqlManager {
}
// 根据 book_id 写入当前读到的 章节
static Future<int?> updateReadHistoryBookId(int bookId ,int chapterId) async {
static Future<int> updateReadHistoryByBookId(int bookId ,int chapterId) async {
final result = await _database?.update(
final result = await _database!.update(
'members_book_notes',
{'chapter_id':chapterId},
where: 'book_id = ?',
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论