task_card.dart 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import 'package:flutter/material.dart';
  2. import 'package:go_router/go_router.dart';
  3. import 'package:asr_client/models/task.dart';
  4. import 'package:asr_client/pages/tasks/widgets/task_status_chip.dart';
  5. import 'package:asr_client/theme/app_colors.dart';
  6. class TaskCard extends StatelessWidget {
  7. const TaskCard({super.key, required this.task});
  8. final Task task;
  9. @override
  10. Widget build(BuildContext context) {
  11. return Card(
  12. color: AppColors.card,
  13. elevation: 0,
  14. margin: const EdgeInsets.only(bottom: 10),
  15. shape: RoundedRectangleBorder(
  16. borderRadius: BorderRadius.circular(14),
  17. side: const BorderSide(color: AppColors.line),
  18. ),
  19. child: InkWell(
  20. onTap: () => context.go('/recording'),
  21. borderRadius: BorderRadius.circular(14),
  22. child: Padding(
  23. padding: const EdgeInsets.all(14),
  24. child: Column(
  25. crossAxisAlignment: CrossAxisAlignment.start,
  26. children: [
  27. Row(
  28. children: [
  29. TaskStatusChip(status: task.status),
  30. const Spacer(),
  31. if (task.timeInfo != null)
  32. Text(
  33. task.timeInfo!,
  34. style: const TextStyle(
  35. fontSize: 11,
  36. color: AppColors.ink3,
  37. fontFamily: 'monospace',
  38. ),
  39. ),
  40. ],
  41. ),
  42. const SizedBox(height: 9),
  43. Text(
  44. task.title,
  45. style: const TextStyle(
  46. fontSize: 15,
  47. fontWeight: FontWeight.w700,
  48. color: AppColors.ink,
  49. ),
  50. ),
  51. const SizedBox(height: 3),
  52. Text(
  53. task.project,
  54. style: const TextStyle(fontSize: 12, color: AppColors.ink2),
  55. ),
  56. if (task.status == TaskStatus.recording &&
  57. task.progress != null) ...[
  58. const SizedBox(height: 12),
  59. _ProgressBar(progress: task.progress!),
  60. ],
  61. if (task.footNote != null) ...[
  62. const SizedBox(height: 9),
  63. Text(
  64. task.footNote!,
  65. style: const TextStyle(fontSize: 11, color: AppColors.ink3),
  66. ),
  67. ],
  68. ],
  69. ),
  70. ),
  71. ),
  72. );
  73. }
  74. }
  75. class _ProgressBar extends StatelessWidget {
  76. const _ProgressBar({required this.progress});
  77. final double progress;
  78. @override
  79. Widget build(BuildContext context) {
  80. final clamped = progress.clamp(0.0, 1.0);
  81. return Column(
  82. crossAxisAlignment: CrossAxisAlignment.start,
  83. children: [
  84. ClipRRect(
  85. borderRadius: BorderRadius.circular(4),
  86. child: LinearProgressIndicator(
  87. value: clamped,
  88. backgroundColor: AppColors.line,
  89. valueColor: const AlwaysStoppedAnimation<Color>(AppColors.app),
  90. minHeight: 6,
  91. ),
  92. ),
  93. const SizedBox(height: 5),
  94. Text(
  95. '${(clamped * 100).toInt()}%',
  96. style: const TextStyle(
  97. fontSize: 10.5,
  98. color: AppColors.appDark,
  99. fontWeight: FontWeight.w700,
  100. ),
  101. ),
  102. ],
  103. );
  104. }
  105. }