// packages/feature_game_spider/lib/widgets/card_widget.dart import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../models/spider_card.dart'; import '../controllers/spider_game_controller.dart'; class CardWidget extends StatelessWidget { final SpiderCard card; final double width; final double height; final bool isDraggable; // 👈 [추가] const CardWidget({ super.key, required this.card, required this.width, required this.height, this.isDraggable = true, // 👈 [추가] 기본값은 true }); @override Widget build(BuildContext context) { // 🔽 [수정] isDraggable이 false이면, 드래그 기능 없이 카드 앞면만 즉시 반환 if (!isDraggable) { return _buildCardFace(context, card); } // --- (isDraggable이 true일 때만 아래 로직 실행) --- final controller = Provider.of(context, listen: false); final List draggableStack = controller.getDraggableStack(card); final bool canDrag = draggableStack.isNotEmpty; return Draggable>( data: draggableStack, // 🔽 [수정] 겹침 높이 계산을 0.4로 수정 feedback: Opacity( opacity: 0.8, child: SizedBox( width: width, height: height + (draggableStack.length - 1) * (height * 0.4), // 👈 0.22 -> 0.4 child: Stack( children: List.generate(draggableStack.length, (index) { return Positioned( top: index * (height * 0.4), // 👈 0.22 -> 0.4 left: 0, // 🔽 [수정] 여기는 CardWidget이 아닌 _buildCardFace를 직접 호출 (중첩 Draggable 방지) child: _buildCardFace(context, draggableStack[index]), ); }), ), ), ), childWhenDragging: _buildCardPlaceholder(context), child: (card.isBeingDragged) ? _buildCardPlaceholder(context) : _buildCardFace(context, card), onDragStarted: () { if (canDrag) { controller.onDragStarted(draggableStack); } }, onDraggableCanceled: (velocity, offset) { controller.onDragCancelled(); }, onDragEnd: (details) { if (controller.draggedCards.isNotEmpty) { controller.onDragCancelled(); } }, ); } // ( _buildCardFace, _buildRankText, _buildCenterSymbols 는 이전과 동일 ) Widget _buildCardFace(BuildContext context, SpiderCard card) { return Container( width: width, height: height, decoration: BoxDecoration( color: card.isFaceUp ? Colors.white : Theme.of(context).primaryColor, border: Border.all(color: Colors.black54, width: 0.5), borderRadius: BorderRadius.circular(width * 0.08), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 2, offset: const Offset(1, 1), ) ], ), child: card.isFaceUp ? Stack( children: [ _buildRankText(card, Alignment.topLeft), _buildRankText(card, Alignment.bottomRight), _buildCenterSymbols(card), ], ) : null, ); } Widget _buildRankText(SpiderCard card, Alignment alignment) { final bool isTopLeft = alignment == Alignment.topLeft; final double fontSize = width * 0.4; final double padding = width * 0.05; Widget content = Column( mainAxisSize: MainAxisSize.min, children: [ Text( card.rankText, style: TextStyle( color: card.isRed ? Colors.red : Colors.black, fontWeight: FontWeight.bold, fontSize: fontSize, ), ), Text( card.suitSymbol, style: TextStyle( color: card.isRed ? Colors.red : Colors.black, fontSize: fontSize * 0.5, ), ), ], ); if (!isTopLeft) { content = Transform.rotate( angle: math.pi, child: content, ); } return Positioned( top: isTopLeft ? padding : null, left: isTopLeft ? padding : null, bottom: isTopLeft ? null : padding, right: isTopLeft ? null : padding, child: content, ); } Widget _buildCenterSymbols(SpiderCard card) { final double symbolSize = width * 0.2; final double bigSymbolSize = width * 0.7; if (card.rank > 10) { return Center( child: Text( card.suitSymbol, style: TextStyle( color: card.isRed ? Colors.red : Colors.black, fontSize: bigSymbolSize, ), ), ); } if (card.rank == 1) { return Center( child: Text( card.suitSymbol, style: TextStyle( color: card.isRed ? Colors.red : Colors.black, fontSize: bigSymbolSize * 0.8, ), ), ); } List symbols = []; Widget symbol(Alignment align) { return Align( alignment: align, child: Text( card.suitSymbol, style: TextStyle( color: card.isRed ? Colors.red : Colors.black, fontSize: symbolSize, ), ), ); } Widget flippedSymbol(Alignment align) { return Align( alignment: align, child: Transform.rotate( angle: math.pi, child: Text( card.suitSymbol, style: TextStyle( color: card.isRed ? Colors.red : Colors.black, fontSize: symbolSize, ), ), ), ); } switch (card.rank) { case 2: symbols.add(symbol(Alignment.topCenter)); symbols.add(flippedSymbol(Alignment.bottomCenter)); break; case 3: symbols.add(symbol(Alignment.topCenter)); symbols.add(symbol(Alignment.center)); symbols.add(flippedSymbol(Alignment.bottomCenter)); break; case 4: symbols.add(symbol(Alignment.topLeft)); symbols.add(symbol(Alignment.topRight)); symbols.add(flippedSymbol(Alignment.bottomLeft)); symbols.add(flippedSymbol(Alignment.bottomRight)); break; case 5: symbols.addAll([ symbol(Alignment.topLeft), symbol(Alignment.topRight), symbol(Alignment.center), flippedSymbol(Alignment.bottomLeft), flippedSymbol(Alignment.bottomRight), ]); break; case 6: symbols.addAll([ symbol(Alignment.topLeft), symbol(Alignment.topRight), symbol(Alignment.centerLeft), symbol(Alignment.centerRight), flippedSymbol(Alignment.bottomLeft), flippedSymbol(Alignment.bottomRight), ]); break; case 7: symbols.addAll([ symbol(Alignment.topLeft), symbol(Alignment.topRight), symbol(const Alignment(0.0, -0.25)), symbol(Alignment.centerLeft), symbol(Alignment.centerRight), flippedSymbol(Alignment.bottomLeft), flippedSymbol(Alignment.bottomRight), ]); break; case 8: symbols.addAll([ symbol(Alignment.topLeft), symbol(Alignment.topRight), symbol(const Alignment(0.0, -0.25)), symbol(Alignment.centerLeft), symbol(Alignment.centerRight), flippedSymbol(Alignment.bottomLeft), flippedSymbol(Alignment.bottomRight), flippedSymbol(const Alignment(0.0, 0.25)), ]); break; case 9: symbols.addAll([ symbol(const Alignment(-0.8, -0.6)), symbol(const Alignment(0.8, -0.6)), symbol(const Alignment(-0.8, 0.0)), symbol(const Alignment(0.8, 0.0)), symbol(Alignment.center), flippedSymbol(const Alignment(-0.8, 0.6)), flippedSymbol(const Alignment(0.8, 0.6)), symbol(const Alignment(0.0, -0.8)), flippedSymbol(const Alignment(0.0, 0.8)), ]); break; case 10: symbols.addAll([ symbol(const Alignment(-0.8, -0.7)), symbol(const Alignment(0.8, -0.7)), symbol(const Alignment(-0.8, -0.1)), symbol(const Alignment(0.8, -0.1)), symbol(const Alignment(0.0, -0.9)), symbol(const Alignment(0.0, -0.4)), flippedSymbol(const Alignment(-0.8, 0.7)), flippedSymbol(const Alignment(0.8, 0.7)), flippedSymbol(const Alignment(0.0, 0.9)), flippedSymbol(const Alignment(0.0, 0.4)), ]); break; } return Padding( padding: EdgeInsets.symmetric(horizontal: width * 0.2, vertical: height * 0.15), child: Stack(children: symbols), ); } Widget _buildCardPlaceholder(BuildContext context) { return Container( width: width, height: height, decoration: BoxDecoration( color: Theme.of(context).scaffoldBackgroundColor.withOpacity(0.5), borderRadius: BorderRadius.circular(width * 0.08), ), ); } }