revert(mobile): 回滚火柴人组件到稳定版本

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-24 03:00:52 -08:00
parent 27bee6d7f1
commit e2872b13fb
1 changed files with 125 additions and 124 deletions

View File

@ -8,7 +8,7 @@ class StickmanRankingData {
final String nickname; final String nickname;
final String? avatarUrl; final String? avatarUrl;
final int completedCount; // final int completedCount; //
final int targetCount; // (5/1) final int targetCount; // (: 50000, : 10000)
final double monthlyEarnings; // final double monthlyEarnings; //
final bool isCurrentUser; // final bool isCurrentUser; //
final String? accountSequence; // final String? accountSequence; //
@ -25,10 +25,7 @@ class StickmanRankingData {
}); });
/// (0.0 - 1.0) /// (0.0 - 1.0)
/// completedCount / targetCount 100% double get progress => (completedCount / targetCount).clamp(0.0, 1.0);
double get progress => targetCount > 0
? (completedCount / targetCount).clamp(0.0, 1.0)
: 0.0;
} }
/// ///
@ -184,26 +181,21 @@ class _StickmanRaceWidgetState extends State<StickmanRaceWidget>
return SizedBox( return SizedBox(
height: raceTrackHeight, height: raceTrackHeight,
child: LayoutBuilder( child: Stack(
builder: (context, constraints) { children: [
final containerWidth = constraints.maxWidth; // 线
Positioned.fill(
// Positioned widgets child: CustomPaint(
final List<Widget> children = [ painter: _TrackPainter(
// 线 trackCount: sortedRankings.length,
Positioned.fill(
child: CustomPaint(
painter: _TrackPainter(
trackCount: sortedRankings.length,
),
), ),
), ),
]; ),
// //
for (int index = 0; index < trackCount; index++) { ...List.generate(trackCount, (index) {
final verticalPosition = index * trackHeight + 10 + trackHeight / 2 - 16; final verticalPosition = index * trackHeight + 10 + trackHeight / 2 - 16;
children.add(Positioned( return Positioned(
right: 8, right: 8,
top: verticalPosition, top: verticalPosition,
child: const Icon( child: const Icon(
@ -211,125 +203,134 @@ class _StickmanRaceWidgetState extends State<StickmanRaceWidget>
color: Colors.red, color: Colors.red,
size: 24, size: 24,
), ),
)); );
} }),
// //
for (int index = 0; index < sortedRankings.length; index++) { ...sortedRankings.asMap().entries.map((entry) {
final data = sortedRankings[index]; final index = entry.key;
final widgets = _buildStickmanWidgets(data, index, sortedRankings.length, raceTrackHeight, containerWidth); final data = entry.value;
children.addAll(widgets); return _buildStickman(data, index, sortedRankings.length, raceTrackHeight);
} }),
],
return AnimatedBuilder(
animation: _bounceController,
builder: (context, child) {
return Stack(
clipBehavior: Clip.none,
children: children,
);
},
);
},
), ),
); );
} }
/// Positioned widgets ///
List<Widget> _buildStickmanWidgets(StickmanRankingData data, int rank, int total, double raceTrackHeight, double containerWidth) { Widget _buildStickman(StickmanRankingData data, int rank, int total, double raceTrackHeight) {
// (0.0 - 1.0) // ()
final progress = data.progress; final horizontalProgress = data.progress;
// () // ()
//
final usableHeight = raceTrackHeight - 40; final usableHeight = raceTrackHeight - 40;
final trackHeight = usableHeight / total; final trackHeight = usableHeight / total;
final verticalPosition = rank * trackHeight + 10; final verticalPosition = rank * trackHeight + 10;
// : return AnimatedBuilder(
// = 70 () animation: _bounceController,
// = - = (containerWidth - 32) - 50 = containerWidth - 82 builder: (context, child) {
const double startX = 70.0; //
final double endX = containerWidth - 82.0; final bounce = _bounceController.value * 3;
final double stickmanLeft = startX + (endX - startX) * progress;
final bounce = _bounceController.value * 3; // - padding(32) - padding(32) - (40) - (30)
// 100%
final screenWidth = MediaQuery.of(context).size.width;
final containerWidth = screenWidth - 32 - 32; // padding + padding
final stickmanHalfWidth = 30.0; //
final flagAreaWidth = 40.0; // right:824+
final nicknameAreaWidth = 65.0; //
final availableWidth = containerWidth - flagAreaWidth - stickmanHalfWidth - nicknameAreaWidth;
final leftPosition = nicknameAreaWidth + availableWidth * horizontalProgress;
return [ return Positioned(
// - left: 0,
Positioned( top: verticalPosition - bounce,
left: 0, child: Row(
top: verticalPosition + 15 - bounce, mainAxisSize: MainAxisSize.min,
child: SizedBox( crossAxisAlignment: CrossAxisAlignment.center,
width: 65, children: [
child: Container( // -
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2), SizedBox(
decoration: BoxDecoration( width: nicknameAreaWidth,
color: data.isCurrentUser child: Container(
? const Color(0xFFD4AF37).withValues(alpha: 0.2) padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
: Colors.white.withValues(alpha: 0.8), decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), color: data.isCurrentUser
border: data.isCurrentUser ? const Color(0xFFD4AF37).withValues(alpha: 0.2)
? Border.all(color: const Color(0xFFD4AF37), width: 1) : Colors.white.withValues(alpha: 0.8),
: null, borderRadius: BorderRadius.circular(4),
), border: data.isCurrentUser
child: Text( ? Border.all(color: const Color(0xFFD4AF37), width: 1)
data.nickname, : null,
style: TextStyle( ),
fontSize: 9, child: Text(
fontFamily: 'Inter', data.nickname,
fontWeight: data.isCurrentUser ? FontWeight.w600 : FontWeight.w400, style: TextStyle(
color: data.isCurrentUser fontSize: 9,
? const Color(0xFFD4AF37) fontFamily: 'Inter',
: const Color(0xFF5D4037), fontWeight:
), data.isCurrentUser ? FontWeight.w600 : FontWeight.w400,
overflow: TextOverflow.ellipsis, color: data.isCurrentUser
textAlign: TextAlign.center, ? const Color(0xFFD4AF37)
), : const Color(0xFF5D4037),
), ),
), overflow: TextOverflow.ellipsis,
), textAlign: TextAlign.center,
//
Positioned(
left: stickmanLeft,
top: verticalPosition - bounce,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
//
Container(
constraints: const BoxConstraints(maxWidth: 60),
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: data.isCurrentUser
? const Color(0xFFD4AF37)
: const Color(0xFF8B5A2B),
borderRadius: BorderRadius.circular(8),
),
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
'${_formatNumber(data.completedCount)}',
style: const TextStyle(
fontSize: 9,
fontFamily: 'Inter',
fontWeight: FontWeight.w600,
color: Colors.white,
), ),
), ),
), ),
), //
const SizedBox(height: 2), SizedBox(
// width: leftPosition - nicknameAreaWidth + stickmanHalfWidth * 2,
RunningStickman( child: Row(
size: 36, mainAxisAlignment: MainAxisAlignment.end,
color: data.isCurrentUser children: [
? const Color(0xFFD4AF37) Column(
: const Color(0xFF5D4037), mainAxisSize: MainAxisSize.min,
), children: [
], //
), Container(
), constraints: const BoxConstraints(maxWidth: 60),
]; padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: data.isCurrentUser
? const Color(0xFFD4AF37)
: const Color(0xFF8B5A2B),
borderRadius: BorderRadius.circular(8),
),
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
'${_formatNumber(data.completedCount)}',
style: const TextStyle(
fontSize: 9,
fontFamily: 'Inter',
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
),
const SizedBox(height: 2),
//
RunningStickman(
size: 36,
color: data.isCurrentUser
? const Color(0xFFD4AF37)
: const Color(0xFF5D4037),
),
],
),
],
),
),
],
),
);
},
);
} }
/// ///