feat:增加加载中显示

This commit is contained in:
2025-11-16 00:09:39 +08:00
parent d512a77f5f
commit 47b6fb9937
15 changed files with 697 additions and 541 deletions

View File

@@ -1,8 +1,9 @@
import 'package:blog_app/apis/blog.dart';
import 'package:blog_app/models/blog.dart';
import 'package:blog_app/widget/common.dart';
import 'package:blog_app/widget/markdown.dart';
import 'package:provider/provider.dart';
import 'package:blog_app/provider/blog.dart';
import 'package:flutter/material.dart';
import 'package:markdown_widget/config/toc.dart';
import 'package:markdown_widget/widget/markdown.dart';
class BlogDetailPage extends StatefulWidget {
final int blogId;
@@ -16,20 +17,14 @@ class BlogDetailPage extends StatefulWidget {
class _BlogDetailPageState extends State<BlogDetailPage> {
final tocController = TocController();
bool _showToc = false;
late Future<Blog> _blogDetail;
@override
void initState() {
super.initState();
_blogDetail = _loadBlogDetail();
}
Future<Blog> _loadBlogDetail() async {
try {
return await queryBlogByIdApi(widget.blogId);
} catch (e) {
throw Exception('获取博客详情失败: $e');
}
// 初始化加载数据
WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<BlogProvider>().queryBlogById(widget.blogId);
});
}
Widget _buildBlogTitle(String title) {
@@ -43,113 +38,64 @@ class _BlogDetailPageState extends State<BlogDetailPage> {
);
}
Widget _buildTocPanel() => Visibility(
visible: _showToc,
child: Align(
alignment: Alignment.bottomRight,
child: Container(
width: 250,
height: 400,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(50),
blurRadius: 8,
offset: const Offset(0, 4),
),
],
border: Border.all(color: Colors.grey[300]!),
),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'目录',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
],
),
),
Expanded(
child: TocWidget(
controller: tocController,
tocTextStyle: TextStyle(fontSize: 14),
),
),
],
),
),
),
);
Widget _buildMarkdown(String data) =>
MarkdownWidget(data: data, tocController: tocController);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('博客详情')),
body: Container(
padding: EdgeInsets.all(16),
child: FutureBuilder<Blog>(
future: _blogDetail,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [Text('加载失败: ${snapshot.error}')],
),
);
}
if (!snapshot.hasData) {
return Center(child: Text('暂无数据'));
}
final blogDetail = snapshot.data!;
return _buildBlogDetailContent(context, blogDetail);
},
),
),
floatingActionButton: FloatingActionButton(
Widget? buildFloatingActionButton(BlogProvider provider) {
if (!provider.isLoading) {
return FloatingActionButton(
onPressed: () => setState(() => _showToc = !_showToc),
mini: true,
backgroundColor: Theme.of(context).primaryColor,
child: Icon(_showToc ? Icons.close : Icons.list, color: Colors.white),
),
);
);
} else {
return null;
}
}
Widget _buildBlogDetailContent(BuildContext context, Blog blogDetail) {
Widget _buildContent(BlogProvider provider) {
if (provider.error != null) {
return buildErrorInfo(
errorInfo: provider.error!,
onPressed: () => provider.queryBlogById(widget.blogId),
);
}
return Stack(
children: [
Column(
children: [
_buildBlogTitle(blogDetail.title),
_buildBlogTitle(provider.currentBlog.title),
SizedBox(height: 10),
Expanded(child: _buildMarkdown(blogDetail.content!)),
Expanded(
child: buildMarkdown(
tocController: tocController,
data: provider.currentBlog.content!,
),
),
],
),
_buildTocPanel(),
buildTocPanel(tocController: tocController, showToc: _showToc),
],
);
}
@override
Widget build(BuildContext context) {
final blogProvider = context.watch<BlogProvider>();
return Scaffold(
appBar: AppBar(title: Text('博客详情')),
body: Container(
padding: EdgeInsets.all(16),
child: Stack(
children: [
if (blogProvider.isLoading)
buildLoadingIndicator()
else
_buildContent(blogProvider),
],
),
),
floatingActionButton: buildFloatingActionButton(blogProvider),
);
}
}