refactor(github_card): 重构 GitHub 卡片组件

- 优化了 GitHub 事件加载和显示逻辑
- 添加了事件类型文本转换功能
- 改进了错误处理和加载状态显示
- 调整了卡片样式和布局
This commit is contained in:
高手 2025-06-09 21:02:07 +08:00
parent bfedef58f4
commit f7d2fc10a4
2 changed files with 187 additions and 94 deletions

View File

@ -1,16 +1,10 @@
# dashboard
## dashboard
A new Flutter project.
个人项目信息面板
## Getting Started
## 配置获取
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
- leetcode:浏览器获取随便找一个xhr请求,从Header中获取cookie,user-slug在个人页面url中
- gitea: 用户设置 >> 应用 >> 生成令牌(授予全部权限)
- kodbox: 参考官方文档[获取accesstoken](https://doc.kodcloud.com/v2/#/user/user?id=%e8%8e%b7%e5%8f%96accesstoken)的方式
- github: Settings >> Developer Settings >> Personal access tokens (classic)

View File

@ -14,101 +14,200 @@ class GithubCard extends StatefulWidget {
class _GithubCardState extends State<GithubCard> {
final GithubService _githubService = GithubService();
late Future<List<GithubEvent>> _eventsFuture;
List<GithubEvent> _events = [];
bool _isLoading = false;
String? _error;
String _getEventTypeText(String type) {
switch (type) {
case 'PushEvent':
return '推送代码';
case 'CreateEvent':
return '创建仓库';
case 'IssuesEvent':
return 'Issue 操作';
case 'PullRequestEvent':
return 'Pull Request 操作';
case 'ForkEvent':
return 'Fork 仓库';
case 'WatchEvent':
return '关注仓库';
case 'StarEvent':
return 'Star 仓库';
default:
return type;
}
}
Widget _buildCommitContent(List<Commit> commits) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:
commits.map((commit) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
commit.message,
style: const TextStyle(fontWeight: FontWeight.bold),
),
Text(
'作者: ${commit.author.name} <${commit.author.email}>',
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
);
}).toList(),
);
}
Future<void> _fetchEvents() async {
setState(() {
_isLoading = true;
_error = null;
});
try {
final authService = Provider.of<AuthService>(context, listen: false);
final username = authService.credentials['github_username'];
final token = authService.credentials['github_token'];
if (username == null || token == null) {
throw Exception('请在设置中配置 GitHub 用户名和 Token');
}
final events = await _githubService.getUserEvents(username, token);
setState(() {
_events = events;
_isLoading = false;
});
} catch (e) {
setState(() {
_error = e.toString();
_isLoading = false;
});
}
}
@override
void initState() {
super.initState();
_loadEvents();
}
void _loadEvents() {
final authService = Provider.of<AuthService>(context, listen: false);
final username = authService.credentials['github_username'];
final token = authService.credentials['github_token'];
if (username != null && token != null) {
_eventsFuture = _githubService.getUserEvents(username, token);
}
_fetchEvents();
}
@override
Widget build(BuildContext context) {
final authService = Provider.of<AuthService>(context);
final username = authService.credentials['github_username'];
final token = authService.credentials['github_token'];
if (username == null || token == null) {
return const Center(child: Text('请在设置中配置 GitHub 用户名和 Token'));
}
return FutureBuilder<List<GithubEvent>>(
future: _eventsFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('加载失败: ${snapshot.error}'));
}
if (!snapshot.hasData || snapshot.data!.isEmpty) {
return const Center(child: Text('暂无活动数据'));
}
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
final event = snapshot.data![index];
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(event.actor.avatarUrl),
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'GitHub 最近活动',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
title: Text(
_getEventTitle(event),
style: const TextStyle(fontWeight: FontWeight.bold),
IconButton(
icon: const Icon(Icons.refresh),
onPressed: _isLoading ? null : _fetchEvents,
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('仓库: ${event.repo.name}'),
Text(
'时间: ${timeago.format(event.createdAt, locale: "zh_CN")}',
),
if (event.type == 'PushEvent' &&
event.payload.commits != null)
...event.payload.commits!.map(
(commit) => Text(
'提交: ${commit.message}',
style: const TextStyle(fontSize: 12),
],
),
if (_isLoading)
const Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: CircularProgressIndicator(),
),
)
else if (_error != null)
Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
_error!,
style: const TextStyle(color: Colors.red),
),
),
)
else if (_events.isEmpty)
const Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text('暂无活动记录'),
),
)
else
Expanded(
child: ListView.builder(
itemCount: _events.length,
itemBuilder: (context, index) {
final event = _events[index];
return Card(
margin: const EdgeInsets.symmetric(vertical: 4.0),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
backgroundImage: NetworkImage(
event.actor.avatarUrl,
),
),
const SizedBox(width: 8),
Text(
event.actor.login,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
const SizedBox(width: 8),
Text(_getEventTypeText(event.type)),
],
),
const SizedBox(height: 8),
Text(
event.repo.name,
style: const TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
),
),
if (event.type == 'PushEvent' &&
event.payload.commits != null)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: _buildCommitContent(
event.payload.commits!,
),
),
const SizedBox(height: 8),
Text(
'时间: ${timeago.format(event.createdAt, locale: 'zh_CN')}',
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
],
),
),
],
);
},
),
isThreeLine: true,
),
);
},
);
},
],
),
),
);
}
String _getEventTitle(GithubEvent event) {
switch (event.type) {
case 'WatchEvent':
return '${event.actor.login} 关注了 ${event.repo.name}';
case 'PushEvent':
return '${event.actor.login} 推送了代码到 ${event.repo.name}';
case 'CreateEvent':
return '${event.actor.login} 创建了 ${event.repo.name}';
case 'ForkEvent':
return '${event.actor.login} Fork 了 ${event.repo.name}';
default:
return '${event.actor.login}${event.repo.name} 进行了 ${event.type} 操作';
}
}
}