feat:增加博客卡片内容
This commit is contained in:
31
lib/apis/blog.dart
Normal file
31
lib/apis/blog.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'package:blog_app/models/blog.dart';
|
||||
import 'package:blog_app/models/common.dart';
|
||||
import 'package:blog_app/utils/http_utils.dart';
|
||||
import 'package:blog_app/utils/index.dart';
|
||||
|
||||
Future<PageResult<Blog>> queryBlogByPageApi(int currentPage, int pageSize) {
|
||||
return HttpUtil().get<PageResult<Blog>>(
|
||||
"/blog/page",
|
||||
queryParameters: {"currentPage": currentPage, "pageSize": pageSize},
|
||||
converter: (data) => convertPageResponse(data, Blog.fromJson),
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<Blog>> queryBlogByConditionApi(
|
||||
String category,
|
||||
String title,
|
||||
int year,
|
||||
) {
|
||||
return HttpUtil().get<List<Blog>>(
|
||||
"/blog/condition",
|
||||
queryParameters: {"category": category, "title": title, "year": year},
|
||||
converter: (data) => convertListResponse<Blog>(data, Blog.fromJson),
|
||||
);
|
||||
}
|
||||
|
||||
Future<Blog> queryBlogByIdApi(int id) {
|
||||
return HttpUtil().get<Blog>(
|
||||
"blog/$id/content",
|
||||
converter: (data) => Blog.fromJson(data),
|
||||
);
|
||||
}
|
||||
@@ -3,6 +3,6 @@ class AppConfig {
|
||||
// 网络配置
|
||||
// http://192.168.1.3:8100
|
||||
// http://14.103.235.151:81/food-service
|
||||
static const String baseApiUrl = "https://cxx0822.iepose.cn/blog-api/blog";
|
||||
static const String baseApiUrl = "https://cxx0822.iepose.cn/blog-api";
|
||||
// static const String baseApiUrl = "http://172.29.101.108:8100";
|
||||
}
|
||||
195
lib/main.dart
195
lib/main.dart
@@ -1,6 +1,10 @@
|
||||
import 'package:blog_app/pages/home_page.dart';
|
||||
import 'package:blog_app/utils/sp_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() {
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await SPUtil.init();
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
@@ -8,192 +12,11 @@ class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('博客卡片Demo'),
|
||||
backgroundColor: Colors.blue,
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [Colors.blue.shade50, Colors.purple.shade50],
|
||||
),
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
BlogCard(
|
||||
title: 'Flutter开发实战',
|
||||
description: '本文详细介绍了如何使用Flutter开发高性能的跨平台应用,包含最佳实践和性能优化技巧。通过实际案例演示了状态管理、路由导航、网络请求等核心功能的实现方式,帮助开发者快速掌握Flutter开发精髓。',
|
||||
labels: [
|
||||
BlogLabel('精品', Icons.star, Colors.amber),
|
||||
BlogLabel('置顶', Icons.push_pin, Colors.red),
|
||||
BlogLabel('技术', Icons.category, Colors.blue),
|
||||
BlogLabel('2024-01-15', Icons.calendar_today, Colors.green),
|
||||
BlogLabel('2024-01-20', Icons.update, Colors.orange),
|
||||
BlogLabel('2.3k', Icons.remove_red_eye, Colors.purple),
|
||||
BlogLabel('3.2k字', Icons.text_fields, Colors.indigo),
|
||||
BlogLabel('8分钟', Icons.access_time, Colors.brown),
|
||||
BlogLabel('24', Icons.comment, Colors.teal),
|
||||
],
|
||||
),
|
||||
|
||||
SizedBox(height: 20),
|
||||
|
||||
BlogCard(
|
||||
title: 'Dart语言特性深入解析',
|
||||
description: '深入探讨Dart语言的现代特性,包括空安全、异步编程、扩展方法等高级功能。结合实例讲解如何利用Dart的特性编写更安全、更高效的代码,提升开发效率和代码质量。',
|
||||
labels: [
|
||||
BlogLabel('推荐', Icons.thumb_up, Colors.pink),
|
||||
BlogLabel('编程', Icons.code, Colors.blue),
|
||||
BlogLabel('2024-01-10', Icons.calendar_today, Colors.green),
|
||||
BlogLabel('2024-01-18', Icons.update, Colors.orange),
|
||||
BlogLabel('1.5k', Icons.remove_red_eye, Colors.purple),
|
||||
BlogLabel('2.1k字', Icons.text_fields, Colors.indigo),
|
||||
BlogLabel('6分钟', Icons.access_time, Colors.brown),
|
||||
BlogLabel('18', Icons.comment, Colors.teal),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
home: HomePage(),
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
fontFamily: 'CustomFont'
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BlogLabel {
|
||||
final String text;
|
||||
final IconData icon;
|
||||
final Color color;
|
||||
|
||||
BlogLabel(this.text, this.icon, this.color);
|
||||
}
|
||||
|
||||
class BlogCard extends StatelessWidget {
|
||||
final String title;
|
||||
final String description;
|
||||
final List<BlogLabel> labels;
|
||||
|
||||
const BlogCard({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.labels,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
elevation: 4,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Container(
|
||||
width: double.infinity, // 确保宽度对齐
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [Colors.white, Colors.grey.shade50],
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
// 标题 - 居中
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue.shade800,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
||||
SizedBox(height: 16),
|
||||
|
||||
// 单行标签 - 居中,更小的尺寸
|
||||
Container(
|
||||
width: double.infinity,
|
||||
child: Wrap(
|
||||
spacing: 6,
|
||||
runSpacing: 6,
|
||||
alignment: WrapAlignment.center,
|
||||
children: labels.map((label) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: label.color.withAlpha(30),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: label.color.withAlpha(20),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(label.icon, size: 12, color: label.color),
|
||||
SizedBox(width: 4),
|
||||
Text(
|
||||
label.text,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: label.color,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 16),
|
||||
|
||||
// 分隔线
|
||||
Container(
|
||||
height: 1,
|
||||
width: 80,
|
||||
color: Colors.blue.shade200,
|
||||
),
|
||||
|
||||
SizedBox(height: 16),
|
||||
|
||||
// 描述 - 放在下面,大约100字
|
||||
Container(
|
||||
width: double.infinity,
|
||||
child: Text(
|
||||
description,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade700,
|
||||
height: 1.6,
|
||||
),
|
||||
textAlign: TextAlign.justify,
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
scaffoldBackgroundColor: Color(0xFFF5F5F5),
|
||||
fontFamily: 'CustomFont',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
62
lib/models/blog.dart
Normal file
62
lib/models/blog.dart
Normal file
@@ -0,0 +1,62 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
// flutter pub run build_runner build
|
||||
part 'blog.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class Blog {
|
||||
@JsonKey(name: 'id')
|
||||
final int id;
|
||||
|
||||
@JsonKey(name: 'title')
|
||||
final String title;
|
||||
|
||||
@JsonKey(name: 'topValue')
|
||||
final int topValue;
|
||||
|
||||
@JsonKey(name: 'isGreat')
|
||||
final bool isGreat;
|
||||
|
||||
@JsonKey(name: 'category')
|
||||
final String category;
|
||||
|
||||
@JsonKey(name: 'summary')
|
||||
final String summary;
|
||||
|
||||
@JsonKey(name: 'content')
|
||||
final String? content;
|
||||
|
||||
@JsonKey(name: 'wordCount')
|
||||
final int wordCount;
|
||||
|
||||
@JsonKey(name: 'readDuration')
|
||||
final int readDuration;
|
||||
|
||||
@JsonKey(name: 'visitCount')
|
||||
final int visitCount;
|
||||
|
||||
@JsonKey(name: 'createTime')
|
||||
final String createTime;
|
||||
|
||||
@JsonKey(name: 'updateTime')
|
||||
final String updateTime;
|
||||
|
||||
Blog({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.topValue,
|
||||
required this.isGreat,
|
||||
required this.category,
|
||||
required this.summary,
|
||||
this.content,
|
||||
required this.wordCount,
|
||||
required this.readDuration,
|
||||
required this.visitCount,
|
||||
required this.createTime,
|
||||
required this.updateTime,
|
||||
});
|
||||
|
||||
factory Blog.fromJson(Map<String, dynamic> json) => _$BlogFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$BlogToJson(this);
|
||||
}
|
||||
37
lib/models/blog.g.dart
Normal file
37
lib/models/blog.g.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'blog.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
Blog _$BlogFromJson(Map<String, dynamic> json) => Blog(
|
||||
id: (json['id'] as num).toInt(),
|
||||
title: json['title'] as String,
|
||||
topValue: (json['topValue'] as num).toInt(),
|
||||
isGreat: json['isGreat'] as bool,
|
||||
category: json['category'] as String,
|
||||
summary: json['summary'] as String,
|
||||
content: json['content'] as String?,
|
||||
wordCount: (json['wordCount'] as num).toInt(),
|
||||
readDuration: (json['readDuration'] as num).toInt(),
|
||||
visitCount: (json['visitCount'] as num).toInt(),
|
||||
createTime: json['createTime'] as String,
|
||||
updateTime: json['updateTime'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$BlogToJson(Blog instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'title': instance.title,
|
||||
'topValue': instance.topValue,
|
||||
'isGreat': instance.isGreat,
|
||||
'category': instance.category,
|
||||
'summary': instance.summary,
|
||||
'content': instance.content,
|
||||
'wordCount': instance.wordCount,
|
||||
'readDuration': instance.readDuration,
|
||||
'visitCount': instance.visitCount,
|
||||
'createTime': instance.createTime,
|
||||
'updateTime': instance.updateTime,
|
||||
};
|
||||
37
lib/models/common.dart
Normal file
37
lib/models/common.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'common.g.dart';
|
||||
|
||||
@JsonSerializable(genericArgumentFactories: true)
|
||||
class PageResult<T> {
|
||||
@JsonKey(name: 'records')
|
||||
final List<T> records;
|
||||
|
||||
@JsonKey(name: 'total')
|
||||
final int total;
|
||||
|
||||
@JsonKey(name: 'size')
|
||||
final int size;
|
||||
|
||||
@JsonKey(name: 'current')
|
||||
final int current;
|
||||
|
||||
@JsonKey(name: 'pages')
|
||||
final int pages;
|
||||
|
||||
const PageResult({
|
||||
required this.records,
|
||||
required this.total,
|
||||
required this.size,
|
||||
required this.current,
|
||||
required this.pages,
|
||||
});
|
||||
|
||||
factory PageResult.fromJson(
|
||||
Map<String, dynamic> json,
|
||||
T Function(Object? json) fromJsonT,
|
||||
) => _$PageResultFromJson(json, fromJsonT);
|
||||
|
||||
Map<String, dynamic> toJson(Object? Function(T value) toJsonT) =>
|
||||
_$PageResultToJson(this, toJsonT);
|
||||
}
|
||||
29
lib/models/common.g.dart
Normal file
29
lib/models/common.g.dart
Normal file
@@ -0,0 +1,29 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'common.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
PageResult<T> _$PageResultFromJson<T>(
|
||||
Map<String, dynamic> json,
|
||||
T Function(Object? json) fromJsonT,
|
||||
) => PageResult<T>(
|
||||
records: (json['records'] as List<dynamic>).map(fromJsonT).toList(),
|
||||
total: (json['total'] as num).toInt(),
|
||||
size: (json['size'] as num).toInt(),
|
||||
current: (json['current'] as num).toInt(),
|
||||
pages: (json['pages'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$PageResultToJson<T>(
|
||||
PageResult<T> instance,
|
||||
Object? Function(T value) toJsonT,
|
||||
) => <String, dynamic>{
|
||||
'records': instance.records.map(toJsonT).toList(),
|
||||
'total': instance.total,
|
||||
'size': instance.size,
|
||||
'current': instance.current,
|
||||
'pages': instance.pages,
|
||||
};
|
||||
38
lib/pages/blog_page.dart
Normal file
38
lib/pages/blog_page.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
import 'package:blog_app/apis/blog.dart';
|
||||
import 'package:blog_app/models/blog.dart';
|
||||
import 'package:blog_app/widget/blog.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BlogPage extends StatefulWidget {
|
||||
const BlogPage({super.key});
|
||||
|
||||
@override
|
||||
State<BlogPage> createState() => _BlogPageState();
|
||||
}
|
||||
|
||||
class _BlogPageState extends State<BlogPage> {
|
||||
late List<Blog> blogList = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// 初始加载数据
|
||||
_loadData();
|
||||
}
|
||||
|
||||
Future<void> _loadData() async {
|
||||
final result = await queryBlogByPageApi(1, 10);
|
||||
|
||||
setState(() {
|
||||
blogList = result.records;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
itemCount: blogList.length,
|
||||
itemBuilder: (context, index) => BlogCard(blog: blogList[index]),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:blog_app/pages/about_page.dart';
|
||||
import 'package:blog_app/pages/blog_page.dart';
|
||||
import 'package:blog_app/pages/message_page.dart';
|
||||
import 'package:blog_app/pages/profile_page.dart';
|
||||
import 'package:blog_app/pages/settings_page.dart';
|
||||
@@ -14,16 +15,11 @@ class _HomePageState extends State<HomePage> {
|
||||
late PageController _pageController;
|
||||
|
||||
// 页面标题列表
|
||||
final List<String> _pageTitles = [
|
||||
'个人资料',
|
||||
'消息中心',
|
||||
'设置',
|
||||
'关于我们',
|
||||
];
|
||||
final List<String> _pageTitles = ['博客', '消息中心', '设置', '关于我们'];
|
||||
|
||||
// 页面图标列表
|
||||
final List<IconData> _pageIcons = [
|
||||
Icons.home,
|
||||
Icons.article,
|
||||
Icons.person,
|
||||
Icons.message,
|
||||
Icons.settings,
|
||||
@@ -42,15 +38,31 @@ class _HomePageState extends State<HomePage> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Widget _buildPageView() {
|
||||
return PageView(
|
||||
controller: _pageController,
|
||||
onPageChanged: (index) {
|
||||
setState(() {
|
||||
_currentPageIndex = index;
|
||||
});
|
||||
},
|
||||
children: [BlogPage(), MessagePage(), SettingsPage(), AboutPage()],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(_pageTitles[_currentPageIndex]),
|
||||
backgroundColor: Colors.blue,
|
||||
title: Text(
|
||||
_pageTitles[_currentPageIndex],
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
elevation: 0,
|
||||
leading: Builder(
|
||||
builder: (context) => IconButton(
|
||||
builder:
|
||||
(context) => IconButton(
|
||||
icon: Icon(Icons.menu, color: Colors.white),
|
||||
onPressed: () => Scaffold.of(context).openDrawer(),
|
||||
),
|
||||
@@ -63,20 +75,7 @@ class _HomePageState extends State<HomePage> {
|
||||
],
|
||||
),
|
||||
drawer: _buildDrawer(),
|
||||
body: PageView(
|
||||
controller: _pageController,
|
||||
onPageChanged: (index) {
|
||||
setState(() {
|
||||
_currentPageIndex = index;
|
||||
});
|
||||
},
|
||||
children: [
|
||||
ProfilePage(),
|
||||
MessagePage(),
|
||||
SettingsPage(),
|
||||
AboutPage(),
|
||||
],
|
||||
),
|
||||
body: Padding(padding: EdgeInsets.all(10), child: _buildPageView()),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -94,12 +93,13 @@ class _HomePageState extends State<HomePage> {
|
||||
child: ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
children: [
|
||||
...List.generate(_pageTitles.length, (index) =>
|
||||
_buildDrawerItem(
|
||||
...List.generate(
|
||||
_pageTitles.length,
|
||||
(index) => _buildDrawerItem(
|
||||
icon: _pageIcons[index],
|
||||
title: _pageTitles[index],
|
||||
index: index,
|
||||
)
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -128,11 +128,7 @@ class _HomePageState extends State<HomePage> {
|
||||
CircleAvatar(
|
||||
radius: 40,
|
||||
backgroundColor: Colors.white.withOpacity(0.3),
|
||||
child: Icon(
|
||||
Icons.person,
|
||||
size: 50,
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Icon(Icons.person, size: 50, color: Colors.white),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
@@ -146,10 +142,7 @@ class _HomePageState extends State<HomePage> {
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
'user@example.com',
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 14,
|
||||
),
|
||||
style: TextStyle(color: Colors.white70, fontSize: 14),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -174,24 +167,31 @@ class _HomePageState extends State<HomePage> {
|
||||
child: ListTile(
|
||||
leading: Icon(
|
||||
icon,
|
||||
color: isSelected ? Colors.blue :
|
||||
isSpecialItem ? Colors.grey[600] : Colors.grey[700],
|
||||
color:
|
||||
isSelected
|
||||
? Colors.blue
|
||||
: isSpecialItem
|
||||
? Colors.grey[600]
|
||||
: Colors.grey[700],
|
||||
size: 24,
|
||||
),
|
||||
title: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: isSelected ? Colors.blue :
|
||||
isSpecialItem ? Colors.grey[600] : Colors.grey[800],
|
||||
color:
|
||||
isSelected
|
||||
? Colors.blue
|
||||
: isSpecialItem
|
||||
? Colors.grey[600]
|
||||
: Colors.grey[800],
|
||||
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
trailing: isSelected ? Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 16,
|
||||
color: Colors.blue,
|
||||
) : null,
|
||||
trailing:
|
||||
isSelected
|
||||
? Icon(Icons.arrow_forward_ios, size: 16, color: Colors.blue)
|
||||
: null,
|
||||
onTap: () {
|
||||
if (!isSpecialItem) {
|
||||
// 正常页面切换
|
||||
@@ -228,101 +228,3 @@ class _HomePageState extends State<HomePage> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 各个页面组件
|
||||
class HomeContentPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 欢迎卡片
|
||||
Card(
|
||||
elevation: 4,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.waving_hand, size: 40, color: Colors.amber),
|
||||
SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'欢迎回来!',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
'今天也是美好的一天',
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 20),
|
||||
|
||||
// 功能网格
|
||||
GridView.count(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 16,
|
||||
mainAxisSpacing: 16,
|
||||
children: [
|
||||
_buildFeatureCard('数据统计', Icons.analytics, Colors.blue),
|
||||
_buildFeatureCard('文件管理', Icons.folder, Colors.green),
|
||||
_buildFeatureCard('消息通知', Icons.notifications, Colors.orange),
|
||||
_buildFeatureCard('系统设置', Icons.settings, Colors.purple),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFeatureCard(String title, IconData icon, Color color) {
|
||||
return Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon, size: 40, color: color),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:blog_app/utils/http_util.dart';
|
||||
import 'package:blog_app/utils/http_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:markdown_widget/config/toc.dart';
|
||||
import 'package:markdown_widget/widget/markdown.dart';
|
||||
|
||||
13
lib/utils/date_utils.dart
Normal file
13
lib/utils/date_utils.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
String formatDate(DateTime date) {
|
||||
return DateFormat('yyyy-MM-dd').format(date);
|
||||
}
|
||||
|
||||
String formatDateString(String date) {
|
||||
return DateFormat('yyyy-MM-dd').format(DateTime.parse(date));
|
||||
}
|
||||
|
||||
String formatTime(DateTime datetime) {
|
||||
return DateFormat('yyyy-MM-dd HH:mm:ss').format(datetime);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:blog_app/config/app_config.dart';
|
||||
import 'package:blog_app/utils/sp_util.dart';
|
||||
import 'package:blog_app/utils/sp_utils.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import 'log_util.dart';
|
||||
import 'log_utils.dart';
|
||||
|
||||
class HttpUtil {
|
||||
static final HttpUtil _instance = HttpUtil._internal();
|
||||
28
lib/utils/index.dart
Normal file
28
lib/utils/index.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
import 'package:blog_app/models/common.dart';
|
||||
|
||||
List<T> convertListResponse<T>(
|
||||
dynamic data,
|
||||
T Function(Map<String, dynamic>) fromJson,
|
||||
) {
|
||||
if (data is List) {
|
||||
return data.map((item) => fromJson(item as Map<String, dynamic>)).toList();
|
||||
}
|
||||
throw FormatException(
|
||||
'Expected a list of items for conversion, but got ${data.runtimeType}',
|
||||
);
|
||||
}
|
||||
|
||||
PageResult<T> convertPageResponse<T>(
|
||||
dynamic data,
|
||||
T Function(Map<String, dynamic>) fromJson,
|
||||
) {
|
||||
if (data is Map<String, dynamic>) {
|
||||
return PageResult<T>.fromJson(
|
||||
data,
|
||||
(json) => fromJson(json as Map<String, dynamic>),
|
||||
);
|
||||
}
|
||||
throw FormatException(
|
||||
'Expected a Map for page response conversion, but got ${data.runtimeType}',
|
||||
);
|
||||
}
|
||||
144
lib/widget/blog.dart
Normal file
144
lib/widget/blog.dart
Normal file
@@ -0,0 +1,144 @@
|
||||
import 'package:blog_app/models/blog.dart';
|
||||
import 'package:blog_app/utils/date_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BlogLabel {
|
||||
final String text;
|
||||
final IconData icon;
|
||||
final Color color;
|
||||
|
||||
BlogLabel(this.text, this.icon, this.color);
|
||||
}
|
||||
|
||||
class BlogCard extends StatelessWidget {
|
||||
final Blog blog;
|
||||
|
||||
const BlogCard({super.key, required this.blog});
|
||||
|
||||
Widget _buildBlogLabelItem(String text, IconData icon, Color color) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withAlpha(30),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: color.withAlpha(20), width: 1),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(icon, size: 12, color: color),
|
||||
SizedBox(width: 4),
|
||||
Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: color,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBlogLabel() {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: Wrap(
|
||||
spacing: 6,
|
||||
runSpacing: 6,
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
if (blog.isGreat)
|
||||
_buildBlogLabelItem('精品', Icons.workspace_premium, Colors.amber),
|
||||
if (blog.topValue > 1)
|
||||
_buildBlogLabelItem('置顶', Icons.push_pin, Colors.red),
|
||||
_buildBlogLabelItem(blog.category, Icons.folder, Colors.blue),
|
||||
_buildBlogLabelItem(
|
||||
formatDateString(blog.createTime),
|
||||
Icons.calendar_today,
|
||||
Colors.green,
|
||||
),
|
||||
_buildBlogLabelItem(
|
||||
formatDateString(blog.updateTime),
|
||||
Icons.calendar_month,
|
||||
Colors.orange,
|
||||
),
|
||||
_buildBlogLabelItem(
|
||||
'${blog.visitCount} 次',
|
||||
Icons.remove_red_eye,
|
||||
Colors.purple,
|
||||
),
|
||||
_buildBlogLabelItem(
|
||||
'${blog.wordCount} 字',
|
||||
Icons.text_fields,
|
||||
Colors.indigo,
|
||||
),
|
||||
_buildBlogLabelItem(
|
||||
'${blog.readDuration} 分钟',
|
||||
Icons.access_time,
|
||||
Colors.brown,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBlogTitle(BuildContext context) {
|
||||
return Text(
|
||||
blog.title,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBlogSummary() {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: Text(
|
||||
blog.summary,
|
||||
style: TextStyle(color: Colors.grey.shade700, height: 1.6),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
|
||||
return Card(
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: colors.surface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: colors.outline.withAlpha(50), width: 1),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
_buildBlogTitle(context),
|
||||
SizedBox(height: 16),
|
||||
_buildBlogLabel(),
|
||||
SizedBox(height: 16),
|
||||
Container(height: 1, width: 80, color: Theme.of(context).colorScheme.primary),
|
||||
SizedBox(height: 16),
|
||||
_buildBlogSummary(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
328
pubspec.lock
328
pubspec.lock
@@ -1,6 +1,22 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "85.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "974859dc0ff5f37bc4313244b3218c791810d03ab3470a579580279ba971a48d"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "7.7.1"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -25,6 +41,70 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
build:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
sha256: "51dc711996cbf609b90cbe5b335bbce83143875a9d58e4b5c6d3c4f684d3dda7"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.5.4"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: bf05f6e12cfea92d3c09308d7bcdab1906cd8a179b023269eed00c071004b957
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "4.1.1"
|
||||
build_resolvers:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: ee4257b3f20c0c90e72ed2b57ad637f694ccba48839a821e87db762548c22a62
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.5.4"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "382a4d649addbfb7ba71a3631df0ec6a45d5ab9b098638144faf27f02778eb53"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.5.4"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: "85fbbb1036d576d966332a3f5ce83f2ce66a40bea1a94ad2d5fc29a19a0d3792"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "9.1.2"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_collection
|
||||
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
built_value:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: a30f0a0e38671e89a492c44d005b5545b830a961575bbd8336d42869ff71066d
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "8.12.0"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -33,6 +113,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: checked_yaml
|
||||
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -41,6 +129,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: code_builder
|
||||
sha256: "11654819532ba94c34de52ff5feb52bd81cba1de00ef2ed622fd50295f9d4243"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "4.11.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -49,6 +145,22 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.19.1"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.0.7"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -57,6 +169,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.0.8"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
dio:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -97,6 +217,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -128,6 +256,30 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: frontend_server_client
|
||||
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: graphs
|
||||
sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
highlight:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -136,6 +288,22 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
http:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.6.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_multi_server
|
||||
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.2.2"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -144,6 +312,46 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "4.1.2"
|
||||
intl:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: intl
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: io
|
||||
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
json_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: json_annotation
|
||||
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "4.9.0"
|
||||
json_serializable:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: json_serializable
|
||||
sha256: c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "6.9.5"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -184,6 +392,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.6.2"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
markdown:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -232,6 +448,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -280,6 +504,30 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pool
|
||||
sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.5.2"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
scroll_to_index:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -344,11 +592,43 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.4.2"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
sha256: a447acb083d3a5ef17f983dd36201aeea33fedadb3228fa831f2f0c92f0f3aca
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.3.7"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -373,6 +653,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_transform
|
||||
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -397,6 +685,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.7.4"
|
||||
timing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: timing
|
||||
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -493,6 +789,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "14.3.1"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.1.4"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -501,6 +805,22 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -509,6 +829,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.7.0 <4.0.0"
|
||||
flutter: ">=3.29.0"
|
||||
|
||||
@@ -38,6 +38,7 @@ dependencies:
|
||||
dio: ^5.7.0
|
||||
shared_preferences: ^2.3.0
|
||||
logger: ^2.6.0
|
||||
json_annotation: ^4.9.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@@ -49,6 +50,9 @@ dev_dependencies:
|
||||
# package. See that file for information about deactivating specific lint
|
||||
# rules and activating additional ones.
|
||||
flutter_lints: ^5.0.0
|
||||
build_runner: ^2.4.5
|
||||
json_serializable: ^6.7.1
|
||||
intl: ^0.19.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
Reference in New Issue
Block a user