factor:布局颜色重构
This commit is contained in:
@@ -27,7 +27,7 @@ class MyApp extends StatelessWidget {
|
|||||||
home: HomePage(),
|
home: HomePage(),
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
scaffoldBackgroundColor: Color(0xFFF5F5F5),
|
useMaterial3: true,
|
||||||
fontFamily: 'CustomFont',
|
fontFamily: 'CustomFont',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class _BlogPageState extends State<BlogPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ListView.builder(
|
return ListView.separated(
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
itemCount: provider.blogList.length,
|
itemCount: provider.blogList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
@@ -94,6 +94,9 @@ class _BlogPageState extends State<BlogPage> {
|
|||||||
child: BlogCard(blog: blog),
|
child: BlogCard(blog: blog),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
|
return SizedBox(height: 8);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class _CategoryListPageState extends State<CategoryListPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBlogList(BlogProvider provider) {
|
Widget _buildBlogList(BlogProvider provider) {
|
||||||
return ListView.builder(
|
return ListView.separated(
|
||||||
itemCount: provider.blogList.length,
|
itemCount: provider.blogList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final blog = provider.blogList[index];
|
final blog = provider.blogList[index];
|
||||||
@@ -33,6 +33,9 @@ class _CategoryListPageState extends State<CategoryListPage> {
|
|||||||
child: buildBlogListItem(context, blog, index + 1),
|
child: buildBlogListItem(context, blog, index + 1),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
|
return SizedBox(height: 8);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,12 +36,15 @@ class _CategoryPageState extends State<CategoryPage> {
|
|||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
// 分类列表
|
// 分类列表
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.separated(
|
||||||
itemCount: provider.categoryList.length,
|
itemCount: provider.categoryList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final category = provider.categoryList[index];
|
final category = provider.categoryList[index];
|
||||||
return buildCategoryCard(context, category);
|
return buildCategoryCard(context, category);
|
||||||
},
|
},
|
||||||
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
|
return SizedBox(height: 8);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:blog_app/utils/index.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:blog_app/provider/blog.dart';
|
import 'package:blog_app/provider/blog.dart';
|
||||||
import 'package:blog_app/widget/blog.dart';
|
import 'package:blog_app/widget/blog.dart';
|
||||||
@@ -131,29 +132,35 @@ class StatsPageState extends State<StatsPage> {
|
|||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
childAspectRatio: 2,
|
childAspectRatio: 2,
|
||||||
|
mainAxisSpacing: 8,
|
||||||
|
crossAxisSpacing: 8,
|
||||||
children: [
|
children: [
|
||||||
buildStatsCard(
|
buildStatsCard(
|
||||||
|
icon: Icons.article,
|
||||||
context: context,
|
context: context,
|
||||||
title: '博客数量',
|
title: '博客数量',
|
||||||
count: provider.overviewStats.blogCount,
|
count: provider.overviewStats.blogCount.toString(),
|
||||||
unit: '篇',
|
unit: '篇',
|
||||||
),
|
),
|
||||||
buildStatsCard(
|
buildStatsCard(
|
||||||
|
icon: Icons.folder,
|
||||||
context: context,
|
context: context,
|
||||||
title: '分类数量',
|
title: '分类数量',
|
||||||
count: provider.overviewStats.categoryCount,
|
count: provider.overviewStats.categoryCount.toString(),
|
||||||
unit: '个',
|
unit: '个',
|
||||||
),
|
),
|
||||||
buildStatsCard(
|
buildStatsCard(
|
||||||
|
icon: Icons.remove_red_eye,
|
||||||
context: context,
|
context: context,
|
||||||
title: '访问量',
|
title: '访问量',
|
||||||
count: provider.overviewStats.visitCount,
|
count: formatChineseDecimal(provider.overviewStats.visitCount),
|
||||||
unit: '次',
|
unit: '次',
|
||||||
),
|
),
|
||||||
buildStatsCard(
|
buildStatsCard(
|
||||||
|
icon: Icons.text_fields,
|
||||||
context: context,
|
context: context,
|
||||||
title: '总字数',
|
title: '总字数',
|
||||||
count: provider.overviewStats.wordCount,
|
count: formatChineseDecimal(provider.overviewStats.wordCount),
|
||||||
unit: '字',
|
unit: '字',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -181,44 +188,32 @@ class StatsPageState extends State<StatsPage> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 8),
|
||||||
_buildBlogStatsGrid(provider),
|
_buildBlogStatsGrid(provider),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 8),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: chartHeight,
|
height: chartHeight,
|
||||||
child: buildCard(
|
child: BuildCard(child: _buildApprovedStats(provider)),
|
||||||
context: context,
|
|
||||||
child: _buildApprovedStats(provider),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 8),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: chartHeight,
|
height: chartHeight,
|
||||||
child: buildCard(context: context, child: _buildVisitStats(provider)),
|
child: BuildCard(child: _buildVisitStats(provider)),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 8),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: chartHeight,
|
height: chartHeight,
|
||||||
child: buildCard(
|
child: BuildCard(child: _buildVisitRankStats(provider)),
|
||||||
context: context,
|
|
||||||
child: _buildVisitRankStats(provider),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 8),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: chartHeight,
|
height: chartHeight,
|
||||||
child: buildCard(
|
child: BuildCard(child: _buildCategoryStats(provider)),
|
||||||
context: context,
|
|
||||||
child: _buildCategoryStats(provider),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 8),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: chartHeight,
|
height: chartHeight,
|
||||||
child: buildCard(
|
child: BuildCard(child: _buildReadRankStats(provider)),
|
||||||
context: context,
|
|
||||||
child: _buildReadRankStats(provider),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -233,8 +228,8 @@ class StatsPageState extends State<StatsPage> {
|
|||||||
if (blogProvider.isLoading)
|
if (blogProvider.isLoading)
|
||||||
buildLoadingIndicator()
|
buildLoadingIndicator()
|
||||||
else
|
else
|
||||||
SingleChildScrollView(child: _buildContent(blogProvider))
|
SingleChildScrollView(child: _buildContent(blogProvider)),
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class TimelinePageState extends State<TimelinePage> {
|
|||||||
|
|
||||||
return Timeline.tileBuilder(
|
return Timeline.tileBuilder(
|
||||||
theme: TimelineThemeData(nodePosition: 0, indicatorPosition: 0),
|
theme: TimelineThemeData(nodePosition: 0, indicatorPosition: 0),
|
||||||
padding: EdgeInsets.all(6),
|
padding: EdgeInsets.all(0),
|
||||||
builder: TimelineTileBuilder.connected(
|
builder: TimelineTileBuilder.connected(
|
||||||
itemCount: provider.blogList.length,
|
itemCount: provider.blogList.length,
|
||||||
connectorBuilder:
|
connectorBuilder:
|
||||||
@@ -39,9 +39,12 @@ class TimelinePageState extends State<TimelinePage> {
|
|||||||
},
|
},
|
||||||
contentsBuilder: (context, index) {
|
contentsBuilder: (context, index) {
|
||||||
final blog = provider.blogList[index];
|
final blog = provider.blogList[index];
|
||||||
return InkWell(
|
return Padding(
|
||||||
onTap: () => navigatorToBlogDetail(context, blog.id),
|
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||||
child: buildBlogListItem(context, blog, index + 1),
|
child: InkWell(
|
||||||
|
onTap: () => navigatorToBlogDetail(context, blog.id),
|
||||||
|
child: buildBlogListItem(context, blog, index + 1),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -26,3 +26,28 @@ PageResult<T> convertPageResponse<T>(
|
|||||||
'Expected a Map for page response conversion, but got ${data.runtimeType}',
|
'Expected a Map for page response conversion, but got ${data.runtimeType}',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 将数字格式化为中文单位(万/亿)
|
||||||
|
String formatChineseDecimal(num number, {int decimalPlaces = 2}) {
|
||||||
|
if (number < 10000) {
|
||||||
|
return number.toString();
|
||||||
|
} else if (number < 100000000) {
|
||||||
|
// 万单位
|
||||||
|
double result = number / 10000.0;
|
||||||
|
return '${_formatDecimal(result, decimalPlaces)}万';
|
||||||
|
} else {
|
||||||
|
// 亿单位
|
||||||
|
double result = number / 100000000.0;
|
||||||
|
return '${_formatDecimal(result, decimalPlaces)}亿';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatDecimal(double number, int decimalPlaces) {
|
||||||
|
// 去除末尾的0和小数点
|
||||||
|
String formatted = number.toStringAsFixed(decimalPlaces);
|
||||||
|
if (formatted.contains('.')) {
|
||||||
|
formatted = formatted.replaceAll(RegExp(r'0*$'), '');
|
||||||
|
formatted = formatted.replaceAll(RegExp(r'\.$'), '');
|
||||||
|
}
|
||||||
|
return formatted;
|
||||||
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class BlogCard extends StatelessWidget {
|
|||||||
alignment: WrapAlignment.center,
|
alignment: WrapAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
if (blog.isGreat)
|
if (blog.isGreat)
|
||||||
_buildBlogLabelItem('精品', Icons.workspace_premium, Colors.amber),
|
_buildBlogLabelItem('精品', Icons.workspace_premium, Colors.deepOrange),
|
||||||
if (blog.topValue > 1)
|
if (blog.topValue > 1)
|
||||||
_buildBlogLabelItem('置顶', Icons.push_pin, Colors.red),
|
_buildBlogLabelItem('置顶', Icons.push_pin, Colors.red),
|
||||||
_buildBlogLabelItem(blog.category, Icons.folder, Colors.blue),
|
_buildBlogLabelItem(blog.category, Icons.folder, Colors.blue),
|
||||||
@@ -114,26 +114,20 @@ class BlogCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return buildCard(
|
final colors = Theme.of(context).colorScheme;
|
||||||
context: context,
|
|
||||||
child: Padding(
|
return BuildCard(
|
||||||
padding: EdgeInsets.all(12),
|
child: Column(
|
||||||
child: Column(
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
children: [
|
||||||
children: [
|
_buildBlogTitle(context),
|
||||||
_buildBlogTitle(context),
|
SizedBox(height: 16),
|
||||||
SizedBox(height: 16),
|
_buildBlogLabel(),
|
||||||
_buildBlogLabel(),
|
SizedBox(height: 16),
|
||||||
SizedBox(height: 16),
|
Container(height: 1, width: 80, color: colors.primary),
|
||||||
Container(
|
SizedBox(height: 16),
|
||||||
height: 1,
|
_buildBlogSummary(),
|
||||||
width: 80,
|
],
|
||||||
color: Theme.of(context).colorScheme.primary,
|
|
||||||
),
|
|
||||||
SizedBox(height: 16),
|
|
||||||
_buildBlogSummary(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -164,8 +158,7 @@ Widget buildCategoryTitle(BuildContext context, int count) {
|
|||||||
Widget buildCategoryCard(BuildContext context, BlogCategory category) {
|
Widget buildCategoryCard(BuildContext context, BlogCategory category) {
|
||||||
final colors = Theme.of(context).colorScheme;
|
final colors = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
return buildCard(
|
return BuildCard(
|
||||||
context: context,
|
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Container(
|
leading: Container(
|
||||||
width: 50,
|
width: 50,
|
||||||
@@ -222,18 +215,12 @@ Widget buildListTitle(int count) {
|
|||||||
Widget buildBlogListItem(BuildContext context, Blog blog, int index) {
|
Widget buildBlogListItem(BuildContext context, Blog blog, int index) {
|
||||||
final colors = Theme.of(context).colorScheme;
|
final colors = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
return buildCard(
|
return BuildCard(
|
||||||
context: context,
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(10),
|
padding: EdgeInsets.all(0),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text('$index.', style: TextStyle(fontWeight: FontWeight.w500)),
|
||||||
'$index.',
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.w500
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Text(
|
Text(
|
||||||
formatDateString(blog.createTime),
|
formatDateString(blog.createTime),
|
||||||
@@ -260,48 +247,65 @@ Widget buildBlogListItem(BuildContext context, Blog blog, int index) {
|
|||||||
|
|
||||||
Widget buildStatsCard({
|
Widget buildStatsCard({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
|
required IconData icon,
|
||||||
required String title,
|
required String title,
|
||||||
required int count,
|
required String count,
|
||||||
required String unit,
|
required String unit,
|
||||||
}) {
|
}) {
|
||||||
return buildCard(
|
final colors = Theme.of(context).colorScheme;
|
||||||
context: context,
|
|
||||||
child: Column(
|
return BuildCard(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Container(
|
||||||
title,
|
padding: const EdgeInsets.all(12),
|
||||||
style: TextStyle(
|
decoration: BoxDecoration(
|
||||||
fontSize: 16,
|
color: colors.primary.withAlpha(50),
|
||||||
color: Colors.grey.shade600,
|
shape: BoxShape.circle,
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
),
|
||||||
|
child: Icon(icon, size: 26, color: colors.primary),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
SizedBox(width: 6),
|
||||||
Row(
|
Expanded(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
Text(
|
children: [
|
||||||
count.toString(),
|
Text(
|
||||||
style: const TextStyle(
|
title,
|
||||||
fontSize: 28,
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontSize: 16,
|
||||||
color: Colors.black87,
|
color: Colors.grey.shade600,
|
||||||
height: 1.0,
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 6),
|
||||||
const SizedBox(width: 4),
|
Row(
|
||||||
Text(
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
unit,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
style: TextStyle(
|
children: [
|
||||||
fontSize: 14,
|
Text(
|
||||||
color: Colors.grey.shade600,
|
count,
|
||||||
fontWeight: FontWeight.w500,
|
style: TextStyle(
|
||||||
|
fontSize: 28,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: colors.primary,
|
||||||
|
height: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Text(
|
||||||
|
unit,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey.shade600,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
Widget buildCard({required BuildContext context, required Widget child}) {
|
class BuildCard extends StatelessWidget {
|
||||||
final colors = Theme.of(context).colorScheme;
|
final Widget? child;
|
||||||
return Card(
|
|
||||||
elevation: 0,
|
const BuildCard({super.key, this.child});
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
|
||||||
child: Container(
|
@override
|
||||||
width: double.infinity,
|
Widget build(BuildContext context) {
|
||||||
|
final colors = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: colors.surface,
|
color: colors.surfaceContainer,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
border: Border.all(color: colors.outline.withAlpha(50), width: 1),
|
|
||||||
),
|
),
|
||||||
child: Padding(padding: EdgeInsets.all(8), child: child),
|
padding: const EdgeInsets.all(16),
|
||||||
),
|
child: child,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget circleIconButton({
|
Widget circleIconButton({
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ Widget buildSearchField({
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget buildSearchResultItem(BuildContext context, BlogSearch blog) {
|
Widget buildSearchResultItem(BuildContext context, BlogSearch blog) {
|
||||||
return buildCard(
|
return BuildCard(
|
||||||
context: context,
|
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
blog.title,
|
blog.title,
|
||||||
@@ -56,11 +55,14 @@ Widget buildSearchResultList(
|
|||||||
BuildContext context,
|
BuildContext context,
|
||||||
List<BlogSearch> searchResultList,
|
List<BlogSearch> searchResultList,
|
||||||
) {
|
) {
|
||||||
return ListView.builder(
|
return ListView.separated(
|
||||||
itemCount: searchResultList.length,
|
itemCount: searchResultList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return buildSearchResultItem(context, searchResultList[index]);
|
return buildSearchResultItem(context, searchResultList[index]);
|
||||||
},
|
},
|
||||||
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
|
return SizedBox(height: 8);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user