flutter_dashboard/lib/widgets/gitea_card.dart
jdysya 6b64d1a0cd refactor(widgets): 重构卡片组件的样式
- 统一了卡片的阴影、边框和圆角样式
- 调整了卡片的外边距
- 优化了部分卡片的内边距
- 统一了难度等级的命名方式
2025-06-10 16:33:54 +08:00

255 lines
8.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import '../services/auth_service.dart';
import 'package:timeago/timeago.dart' as timeago;
class GiteaCard extends StatefulWidget {
const GiteaCard({super.key});
@override
State<GiteaCard> createState() => _GiteaCardState();
}
class _GiteaCardState extends State<GiteaCard> {
List<dynamic> _activities = [];
bool _isLoading = false;
String? _error;
String _getOperationTypeText(String opType) {
switch (opType) {
case 'create_repo':
return '创建仓库';
case 'commit_repo':
return '提交代码';
case 'push_tag':
return '推送标签';
case 'create_issue':
return '创建 Issue';
case 'comment_issue':
return '评论 Issue';
case 'create_pull_request':
return '创建 Pull Request';
case 'merge_pull_request':
return '合并 Pull Request';
default:
return opType;
}
}
Widget _buildCommitContent(String content) {
try {
final data = jsonDecode(content);
final commits = data['Commits'] as List;
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['AuthorName']} <${commit['AuthorEmail']}>',
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
Text(
'提交时间: ${DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.parse(commit['Timestamp']))}',
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
);
}).toList(),
);
} catch (e) {
return Text(content);
}
}
Future<void> _fetchActivities() async {
setState(() {
_isLoading = true;
_error = null;
});
try {
final authService = Provider.of<AuthService>(context, listen: false);
final token = authService.credentials['gitea_token'];
final username = authService.credentials['gitea_username'];
if (token == null || token.isEmpty) {
throw Exception('未配置 Gitea Token');
}
if (username == null || username.isEmpty) {
throw Exception('未配置 Gitea 用户名');
}
final response = await http.get(
Uri.parse(
'https://git.jdysya.top/api/v1/users/$username/activities/feeds',
),
headers: {'Authorization': 'token $token'},
);
if (response.statusCode == 200) {
setState(() {
_activities = jsonDecode(response.body);
_isLoading = false;
});
} else {
throw Exception('请求失败: ${response.statusCode}');
}
} catch (e) {
setState(() {
_error = e.toString();
_isLoading = false;
});
}
}
@override
void initState() {
super.initState();
_fetchActivities();
}
@override
Widget build(BuildContext context) {
return Card(
elevation: 4,
shadowColor: Colors.deepPurple.withOpacity(0.3),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: BorderSide(color: Colors.deepPurple.withOpacity(0.1)),
),
margin: const EdgeInsets.symmetric(vertical: 8.0),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Gitea 最近活动',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
IconButton(
icon: const Icon(Icons.refresh),
onPressed: _isLoading ? null : _fetchActivities,
),
],
),
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 (_activities.isEmpty)
const Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text('暂无活动记录'),
),
)
else
Expanded(
child: ListView.builder(
itemCount: _activities.length,
itemBuilder: (context, index) {
final activity = _activities[index];
final repo = activity['repo'];
final created = activity['created'];
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(
radius: 16,
child: Text(
activity['act_user']['login'][0]
.toUpperCase(),
),
),
const SizedBox(width: 8),
Text(
activity['act_user']['login'],
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
const SizedBox(width: 8),
Text(
_getOperationTypeText(activity['op_type']),
),
],
),
const SizedBox(height: 8),
if (repo != null)
Text(
repo['full_name'],
style: const TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
),
),
if (activity['content'] != null)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child:
activity['op_type'] == 'commit_repo'
? _buildCommitContent(
activity['content'],
)
: Text(activity['content']),
),
const SizedBox(height: 8),
Text(
'时间: ${timeago.format(DateTime.parse(created), locale: 'zh_CN')}',
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
],
),
),
);
},
),
),
],
),
),
);
}
}