244 lines
7.2 KiB
Dart
244 lines
7.2 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
import '../models/hunt_card.dart';
|
|
|
|
enum HuntGameState {
|
|
cardSelection,
|
|
cardFlipped,
|
|
huntingActive,
|
|
hintMode,
|
|
completed,
|
|
}
|
|
|
|
class HuntState extends ChangeNotifier {
|
|
List<HuntCard> _cards = [];
|
|
HuntCard? _selectedCard;
|
|
HuntGameState _gameState = HuntGameState.cardSelection;
|
|
List<LeaderboardEntry> _leaderboard = [];
|
|
int _userPoints = 0;
|
|
bool _isLocationEnabled = false;
|
|
bool _isCameraPermissionGranted = false;
|
|
DateTime? _huntStartTime;
|
|
|
|
List<HuntCard> get cards => _cards;
|
|
HuntCard? get selectedCard => _selectedCard;
|
|
HuntGameState get gameState => _gameState;
|
|
List<LeaderboardEntry> get leaderboard => _leaderboard;
|
|
int get userPoints => _userPoints;
|
|
bool get isLocationEnabled => _isLocationEnabled;
|
|
bool get isCameraPermissionGranted => _isCameraPermissionGranted;
|
|
DateTime? get huntStartTime => _huntStartTime;
|
|
|
|
bool get hasTimeLeft {
|
|
if (_huntStartTime == null) return false;
|
|
final elapsed = DateTime.now().difference(_huntStartTime!);
|
|
return elapsed.inHours < 12;
|
|
}
|
|
|
|
Duration get timeRemaining {
|
|
if (_huntStartTime == null) return Duration.zero;
|
|
final elapsed = DateTime.now().difference(_huntStartTime!);
|
|
final remaining = const Duration(hours: 12) - elapsed;
|
|
return remaining.isNegative ? Duration.zero : remaining;
|
|
}
|
|
|
|
int get currentUserRank {
|
|
if (_leaderboard.isEmpty) return 0;
|
|
try {
|
|
return _leaderboard.firstWhere((e) => e.isCurrentUser).rank;
|
|
} catch (e) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void initializeGame() {
|
|
_cards = _generateMockCards();
|
|
_leaderboard = _generateMockLeaderboard();
|
|
_gameState = HuntGameState.cardSelection;
|
|
notifyListeners();
|
|
}
|
|
|
|
void selectCard(HuntCard card) {
|
|
_selectedCard = card;
|
|
notifyListeners();
|
|
}
|
|
|
|
void startHunt() {
|
|
if (_selectedCard != null) {
|
|
_huntStartTime = DateTime.now();
|
|
_gameState = HuntGameState.huntingActive;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
void activateHintMode() {
|
|
if (_gameState == HuntGameState.huntingActive) {
|
|
_gameState = HuntGameState.hintMode;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
void setLocationEnabled(bool enabled) {
|
|
_isLocationEnabled = enabled;
|
|
notifyListeners();
|
|
}
|
|
|
|
void setCameraPermissionGranted(bool granted) {
|
|
_isCameraPermissionGranted = granted;
|
|
notifyListeners();
|
|
}
|
|
|
|
void completeHunt() {
|
|
if (_selectedCard != null) {
|
|
_userPoints += _selectedCard!.points;
|
|
_gameState = HuntGameState.completed;
|
|
_updateLeaderboard();
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
void resetGame() {
|
|
_selectedCard = null;
|
|
_gameState = HuntGameState.cardSelection;
|
|
_huntStartTime = null;
|
|
notifyListeners();
|
|
}
|
|
|
|
void _updateLeaderboard() {
|
|
for (int i = 0; i < _leaderboard.length; i++) {
|
|
if (_leaderboard[i].isCurrentUser) {
|
|
_leaderboard[i] = _leaderboard[i].copyWith(totalPoints: _userPoints);
|
|
break;
|
|
}
|
|
}
|
|
|
|
_leaderboard.sort((a, b) => b.totalPoints.compareTo(a.totalPoints));
|
|
|
|
for (int i = 0; i < _leaderboard.length; i++) {
|
|
_leaderboard[i] = _leaderboard[i].copyWith(rank: i + 1);
|
|
}
|
|
}
|
|
|
|
List<HuntCard> _generateMockCards() {
|
|
return [
|
|
HuntCard(
|
|
id: '1',
|
|
category: 'Coffee Shop',
|
|
categoryIcon: '☕',
|
|
points: 150,
|
|
question: 'In the heart of a grand shopping center, where fountains dance and skiers gather in warmth. Look for a café where the scent of coffee and the aroma of books intertwine.',
|
|
answer: 'Kino Café',
|
|
description: 'A cozy book café in Isfahan City Center',
|
|
targetLatitude: 32.625042058762496,
|
|
targetLongitude: 51.7264112781341,
|
|
hintLatitude: 32.625042058762496,
|
|
hintLongitude: 51.7264112781341,
|
|
hintDescription: 'Our store is located on Chahar Bagh Abbasi Street',
|
|
),
|
|
HuntCard(
|
|
id: '2',
|
|
category: 'Restaurant',
|
|
categoryIcon: '🍽️',
|
|
points: 200,
|
|
question: 'Where spices tell stories of ancient Persia, and every dish carries the warmth of tradition. Seek the place where saffron meets hospitality.',
|
|
answer: 'Shahrzad Restaurant',
|
|
description: 'Traditional Persian cuisine restaurant',
|
|
targetLatitude: 32.625042058762496,
|
|
targetLongitude: 51.7264112781341,
|
|
hintLatitude: 32.625042058762496,
|
|
hintLongitude: 51.7264112781341,
|
|
hintDescription: 'Find the AR clue near the traditional architecture',
|
|
),
|
|
HuntCard(
|
|
id: '3',
|
|
category: 'Fashion Store',
|
|
categoryIcon: '👕',
|
|
points: 120,
|
|
question: 'Where fashion meets elegance, and every thread tells a story of style. Find the boutique that dresses dreams.',
|
|
answer: 'Zara Store',
|
|
description: 'International fashion retailer',
|
|
targetLatitude: 32.625042058762496,
|
|
targetLongitude: 51.7264112781341,
|
|
hintLatitude: 32.625042058762496,
|
|
hintLongitude: 51.7264112781341,
|
|
hintDescription: 'Check the AR marker at the fashion district entrance',
|
|
),
|
|
HuntCard(
|
|
id: '4',
|
|
category: 'Electronics',
|
|
categoryIcon: '📱',
|
|
points: 180,
|
|
question: 'In the digital realm where innovation never sleeps, discover the place where technology meets tomorrow.',
|
|
answer: 'TechnoCity',
|
|
description: 'Electronics and gadgets store',
|
|
targetLatitude: 32.625042058762496,
|
|
targetLongitude: 51.7264112781341,
|
|
hintLatitude: 32.625042058762496,
|
|
hintLongitude: 51.7264112781341,
|
|
hintDescription: 'Look for the AR guide near the tech display',
|
|
),
|
|
HuntCard(
|
|
id: '5',
|
|
category: 'Bookstore',
|
|
categoryIcon: '📚',
|
|
points: 100,
|
|
question: 'Where words dance on pages and knowledge finds its home. Seek the sanctuary of stories and wisdom.',
|
|
answer: 'Ketabsara Bookstore',
|
|
description: 'Literary paradise with rare collections',
|
|
targetLatitude: 32.625042058762496,
|
|
targetLongitude: 51.7264112781341,
|
|
hintLatitude: 32.625042058762496,
|
|
hintLongitude: 51.7264112781341,
|
|
hintDescription: 'Find the AR clue in the literature section',
|
|
),
|
|
]..sort((a, b) => b.points.compareTo(a.points));
|
|
}
|
|
|
|
List<LeaderboardEntry> _generateMockLeaderboard() {
|
|
return [
|
|
const LeaderboardEntry(
|
|
id: '1',
|
|
name: 'Alex Thompson',
|
|
avatar: '🏆',
|
|
totalPoints: 850,
|
|
rank: 1,
|
|
),
|
|
const LeaderboardEntry(
|
|
id: '2',
|
|
name: 'Sarah Johnson',
|
|
avatar: '🥈',
|
|
totalPoints: 720,
|
|
rank: 2,
|
|
),
|
|
const LeaderboardEntry(
|
|
id: '3',
|
|
name: 'Mike Chen',
|
|
avatar: '🥉',
|
|
totalPoints: 680,
|
|
rank: 3,
|
|
),
|
|
LeaderboardEntry(
|
|
id: 'current_user',
|
|
name: 'You',
|
|
avatar: '👤',
|
|
totalPoints: _userPoints,
|
|
rank: 4,
|
|
isCurrentUser: true,
|
|
),
|
|
const LeaderboardEntry(
|
|
id: '4',
|
|
name: 'Emma Davis',
|
|
avatar: '🌟',
|
|
totalPoints: 420,
|
|
rank: 5,
|
|
),
|
|
const LeaderboardEntry(
|
|
id: '5',
|
|
name: 'David Wilson',
|
|
avatar: '⚡',
|
|
totalPoints: 380,
|
|
rank: 6,
|
|
),
|
|
];
|
|
}
|
|
}
|