此提交包含多项变更: 1. 新增鸿蒙平台支持,完善设备检测与数据库适配 2. 替换旧版分享插件API为SharePlus 3. 批量迁移StateNotifier到Notifier以适配新版Riverpod 4. 修复zip编码判断、图表API参数等bug 5. 更新应用图标、启动页资源与多尺寸适配图标 6. 调整Android最小SDK版本与应用名称 7. 优化日志打印与正则表达式使用 8. 修正编辑器画布样式初始化与配置逻辑 9. 更新依赖与CI插件配置
206 lines
5.8 KiB
Dart
206 lines
5.8 KiB
Dart
// ============================================================
|
|
// 闲言APP — 文章创作状态管理
|
|
// 创建时间: 2026-04-29
|
|
// 更新时间: 2026-04-29
|
|
// 作用: 文章列表/详情/创作/我的文章状态管理
|
|
// 上次更新: 初始创建
|
|
// ============================================================
|
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../../../core/utils/logger.dart';
|
|
import '../models/article_models.dart';
|
|
import '../services/article_service.dart';
|
|
|
|
class ArticleState {
|
|
const ArticleState({
|
|
this.isLoading = false,
|
|
this.isSubmitting = false,
|
|
this.error,
|
|
this.articles = const [],
|
|
this.myArticles = const [],
|
|
this.currentArticle,
|
|
this.comments = const [],
|
|
this.page = 1,
|
|
this.hasMore = true,
|
|
this.myPage = 1,
|
|
this.myHasMore = true,
|
|
this.selectedCategory,
|
|
this.searchKeyword = '',
|
|
});
|
|
|
|
final bool isLoading;
|
|
final bool isSubmitting;
|
|
final String? error;
|
|
final List<Article> articles;
|
|
final List<Article> myArticles;
|
|
final Article? currentArticle;
|
|
final List<ArticleComment> comments;
|
|
final int page;
|
|
final bool hasMore;
|
|
final int myPage;
|
|
final bool myHasMore;
|
|
final String? selectedCategory;
|
|
final String searchKeyword;
|
|
|
|
ArticleState copyWith({
|
|
bool? isLoading,
|
|
bool? isSubmitting,
|
|
String? error,
|
|
bool clearError = false,
|
|
List<Article>? articles,
|
|
List<Article>? myArticles,
|
|
Article? currentArticle,
|
|
bool clearCurrentArticle = false,
|
|
List<ArticleComment>? comments,
|
|
int? page,
|
|
bool? hasMore,
|
|
int? myPage,
|
|
bool? myHasMore,
|
|
String? selectedCategory,
|
|
bool clearSelectedCategory = false,
|
|
String? searchKeyword,
|
|
bool clearSearch = false,
|
|
}) {
|
|
return ArticleState(
|
|
isLoading: isLoading ?? this.isLoading,
|
|
isSubmitting: isSubmitting ?? this.isSubmitting,
|
|
error: clearError ? null : (error ?? this.error),
|
|
articles: articles ?? this.articles,
|
|
myArticles: myArticles ?? this.myArticles,
|
|
currentArticle: clearCurrentArticle
|
|
? null
|
|
: (currentArticle ?? this.currentArticle),
|
|
comments: comments ?? this.comments,
|
|
page: page ?? this.page,
|
|
hasMore: hasMore ?? this.hasMore,
|
|
myPage: myPage ?? this.myPage,
|
|
myHasMore: myHasMore ?? this.myHasMore,
|
|
selectedCategory: clearSelectedCategory
|
|
? null
|
|
: (selectedCategory ?? this.selectedCategory),
|
|
searchKeyword: clearSearch ? '' : (searchKeyword ?? this.searchKeyword),
|
|
);
|
|
}
|
|
}
|
|
|
|
class ArticleNotifier extends Notifier<ArticleState> {
|
|
@override
|
|
ArticleState build() => const ArticleState();
|
|
ArticleNotifier();
|
|
|
|
/// 加载文章列表
|
|
Future<void> loadArticles({
|
|
bool refresh = false,
|
|
String? category,
|
|
String? keyword,
|
|
}) async {
|
|
if (state.isLoading && !refresh) return;
|
|
final page = refresh ? 1 : state.page;
|
|
state = state.copyWith(
|
|
isLoading: true,
|
|
clearError: true,
|
|
page: page,
|
|
selectedCategory: category ?? state.selectedCategory,
|
|
searchKeyword: keyword ?? state.searchKeyword,
|
|
);
|
|
|
|
try {
|
|
final articles = await ArticleService.getArticleList(
|
|
page: page,
|
|
category: category ?? state.selectedCategory,
|
|
keyword: keyword ?? state.searchKeyword,
|
|
);
|
|
state = state.copyWith(
|
|
articles: refresh ? articles : [...state.articles, ...articles],
|
|
isLoading: false,
|
|
page: page + 1,
|
|
hasMore: articles.length >= 20,
|
|
);
|
|
} catch (e) {
|
|
Log.e('加载文章列表失败', e);
|
|
state = state.copyWith(isLoading: false, error: '加载失败');
|
|
}
|
|
}
|
|
|
|
/// 加载文章详情
|
|
Future<void> loadArticleDetail({required int id}) async {
|
|
state = state.copyWith(isLoading: true, clearError: true);
|
|
try {
|
|
final article = await ArticleService.getArticleDetail(id: id);
|
|
final comments =
|
|
await ArticleService.getArticleComments(articleId: id);
|
|
state = state.copyWith(
|
|
currentArticle: article,
|
|
comments: comments,
|
|
isLoading: false,
|
|
);
|
|
} catch (e) {
|
|
Log.e('加载文章详情失败', e);
|
|
state = state.copyWith(isLoading: false, error: '加载失败');
|
|
}
|
|
}
|
|
|
|
/// 提交文章
|
|
Future<bool> submitArticle({
|
|
int? id,
|
|
required String title,
|
|
required String content,
|
|
String? summary,
|
|
String? category,
|
|
List<String>? tags,
|
|
}) async {
|
|
state = state.copyWith(isSubmitting: true);
|
|
try {
|
|
await ArticleService.submitArticle(
|
|
id: id,
|
|
title: title,
|
|
content: content,
|
|
summary: summary,
|
|
category: category,
|
|
tags: tags,
|
|
);
|
|
state = state.copyWith(isSubmitting: false);
|
|
return true;
|
|
} catch (e) {
|
|
Log.e('提交文章失败', e);
|
|
state = state.copyWith(isSubmitting: false);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 加载我的文章
|
|
Future<void> loadMyArticles({bool refresh = false}) async {
|
|
if (state.isLoading && !refresh) return;
|
|
final page = refresh ? 1 : state.myPage;
|
|
state = state.copyWith(isLoading: true, clearError: true, myPage: page);
|
|
|
|
try {
|
|
final articles = await ArticleService.getMyArticles(page: page);
|
|
state = state.copyWith(
|
|
myArticles:
|
|
refresh ? articles : [...state.myArticles, ...articles],
|
|
isLoading: false,
|
|
myPage: page + 1,
|
|
myHasMore: articles.length >= 20,
|
|
);
|
|
} catch (e) {
|
|
Log.e('加载我的文章失败', e);
|
|
state = state.copyWith(isLoading: false, error: '加载失败');
|
|
}
|
|
}
|
|
|
|
/// 删除文章
|
|
Future<bool> deleteArticle({required int id}) async {
|
|
try {
|
|
return await ArticleService.deleteArticle(id: id);
|
|
} catch (e) {
|
|
Log.e('删除文章失败', e);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
final articleProvider =
|
|
NotifierProvider<ArticleNotifier, ArticleState>(ArticleNotifier.new);
|