|
|
@@ -0,0 +1,290 @@
|
|
|
+import 'package:games_services/games_services.dart';
|
|
|
+import 'dart:async';
|
|
|
+import 'dart:io';
|
|
|
+
|
|
|
+/// Manages Google Play Games Services integration
|
|
|
+class GooglePlayGamesManager {
|
|
|
+ static GooglePlayGamesManager? _instance;
|
|
|
+ static GooglePlayGamesManager get instance {
|
|
|
+ _instance ??= GooglePlayGamesManager._internal();
|
|
|
+ return _instance!;
|
|
|
+ }
|
|
|
+
|
|
|
+ GooglePlayGamesManager._internal();
|
|
|
+
|
|
|
+ bool _isInitialized = false;
|
|
|
+ bool _isSignedIn = false;
|
|
|
+ String? _playerId;
|
|
|
+ String? _playerName;
|
|
|
+
|
|
|
+ // Achievement IDs - These need to be configured in Google Play Console
|
|
|
+ static const String achievementFirstBubble = 'achievement_first_bubble';
|
|
|
+ static const String achievement100Bubbles = 'achievement_100_bubbles';
|
|
|
+ static const String achievement1000Bubbles = 'achievement_1000_bubbles';
|
|
|
+ static const String achievement5000Bubbles = 'achievement_5000_bubbles';
|
|
|
+ static const String achievementZenMaster = 'achievement_zen_master';
|
|
|
+ static const String achievementSpeedDemon = 'achievement_speed_demon';
|
|
|
+ static const String achievementPerfectSession = 'achievement_perfect_session';
|
|
|
+
|
|
|
+ // Leaderboard IDs - These need to be configured in Google Play Console
|
|
|
+ static const String leaderboardHighScore = 'leaderboard_high_score';
|
|
|
+ static const String leaderboardZenMode = 'leaderboard_zen_mode';
|
|
|
+ static const String leaderboardTotalBubbles = 'leaderboard_total_bubbles';
|
|
|
+ static const String leaderboardLongestSession = 'leaderboard_longest_session';
|
|
|
+
|
|
|
+ /// Initialize Google Play Games Services
|
|
|
+ Future<bool> initialize() async {
|
|
|
+ if (_isInitialized) return true;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // Only available on Android
|
|
|
+ if (!Platform.isAndroid) {
|
|
|
+ print('Google Play Games Services only available on Android');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ _isInitialized = true;
|
|
|
+ return true;
|
|
|
+ } catch (e) {
|
|
|
+ print('Error initializing Google Play Games: $e');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Sign in to Google Play Games
|
|
|
+ Future<bool> signIn() async {
|
|
|
+ if (!_isInitialized) {
|
|
|
+ await initialize();
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ final result = await GamesServices.signIn();
|
|
|
+ _isSignedIn = result != null && result.isNotEmpty;
|
|
|
+
|
|
|
+ if (_isSignedIn) {
|
|
|
+ _playerId = result;
|
|
|
+ print('Successfully signed in to Google Play Games: $_playerId');
|
|
|
+
|
|
|
+ // Get player name
|
|
|
+ try {
|
|
|
+ final playerName = await GamesServices.getPlayerName();
|
|
|
+ _playerName = playerName;
|
|
|
+ print('Player name: $_playerName');
|
|
|
+ } catch (e) {
|
|
|
+ print('Could not get player name: $e');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return _isSignedIn;
|
|
|
+ } catch (e) {
|
|
|
+ print('Error signing in to Google Play Games: $e');
|
|
|
+ _isSignedIn = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Sign out from Google Play Games
|
|
|
+ Future<void> signOut() async {
|
|
|
+ try {
|
|
|
+ // Note: games_services package doesn't have a signOut method
|
|
|
+ // We'll just reset our local state
|
|
|
+ _isSignedIn = false;
|
|
|
+ _playerId = null;
|
|
|
+ _playerName = null;
|
|
|
+ print('Successfully signed out from Google Play Games');
|
|
|
+ } catch (e) {
|
|
|
+ print('Error signing out from Google Play Games: $e');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Check if signed in
|
|
|
+ bool get isSignedIn => _isSignedIn;
|
|
|
+
|
|
|
+ /// Get player ID
|
|
|
+ String? get playerId => _playerId;
|
|
|
+
|
|
|
+ /// Get player name
|
|
|
+ String? get playerName => _playerName;
|
|
|
+
|
|
|
+ /// Submit score to leaderboard
|
|
|
+ Future<bool> submitScore(String leaderboardId, int score) async {
|
|
|
+ if (!_isSignedIn) {
|
|
|
+ print('Not signed in to Google Play Games');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ await GamesServices.submitScore(
|
|
|
+ score: Score(
|
|
|
+ androidLeaderboardID: leaderboardId,
|
|
|
+ value: score,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ print('Score $score submitted to leaderboard $leaderboardId');
|
|
|
+ return true;
|
|
|
+ } catch (e) {
|
|
|
+ print('Error submitting score: $e');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Show leaderboards
|
|
|
+ Future<void> showLeaderboards() async {
|
|
|
+ if (!_isSignedIn) {
|
|
|
+ print('Not signed in to Google Play Games');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ await GamesServices.showLeaderboards();
|
|
|
+ } catch (e) {
|
|
|
+ print('Error showing leaderboards: $e');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Show specific leaderboard
|
|
|
+ Future<void> showLeaderboard(String leaderboardId) async {
|
|
|
+ if (!_isSignedIn) {
|
|
|
+ print('Not signed in to Google Play Games');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ await GamesServices.showLeaderboards(
|
|
|
+ androidLeaderboardID: leaderboardId,
|
|
|
+ );
|
|
|
+ } catch (e) {
|
|
|
+ print('Error showing leaderboard: $e');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Unlock achievement
|
|
|
+ Future<bool> unlockAchievement(String achievementId) async {
|
|
|
+ if (!_isSignedIn) {
|
|
|
+ print('Not signed in to Google Play Games');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ await GamesServices.unlock(
|
|
|
+ achievement: Achievement(
|
|
|
+ androidID: achievementId,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ print('Achievement $achievementId unlocked');
|
|
|
+ return true;
|
|
|
+ } catch (e) {
|
|
|
+ print('Error unlocking achievement: $e');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Increment achievement (for incremental achievements)
|
|
|
+ Future<bool> incrementAchievement(String achievementId, int steps) async {
|
|
|
+ if (!_isSignedIn) {
|
|
|
+ print('Not signed in to Google Play Games');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ await GamesServices.increment(
|
|
|
+ achievement: Achievement(
|
|
|
+ androidID: achievementId,
|
|
|
+ steps: steps,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ print('Achievement $achievementId incremented by $steps steps');
|
|
|
+ return true;
|
|
|
+ } catch (e) {
|
|
|
+ print('Error incrementing achievement: $e');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Show achievements
|
|
|
+ Future<void> showAchievements() async {
|
|
|
+ if (!_isSignedIn) {
|
|
|
+ print('Not signed in to Google Play Games');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ await GamesServices.showAchievements();
|
|
|
+ } catch (e) {
|
|
|
+ print('Error showing achievements: $e');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Check achievement-related milestones for bubble popping
|
|
|
+ Future<void> checkBubbleAchievements(int totalBubbles) async {
|
|
|
+ if (!_isSignedIn) return;
|
|
|
+
|
|
|
+ // First bubble achievement
|
|
|
+ if (totalBubbles >= 1) {
|
|
|
+ await unlockAchievement(achievementFirstBubble);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 100 bubbles achievement
|
|
|
+ if (totalBubbles >= 100) {
|
|
|
+ await unlockAchievement(achievement100Bubbles);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1000 bubbles achievement
|
|
|
+ if (totalBubbles >= 1000) {
|
|
|
+ await unlockAchievement(achievement1000Bubbles);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5000 bubbles achievement
|
|
|
+ if (totalBubbles >= 5000) {
|
|
|
+ await unlockAchievement(achievement5000Bubbles);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Check zen mode achievements
|
|
|
+ Future<void> checkZenModeAchievements(double sessionTime) async {
|
|
|
+ if (!_isSignedIn) return;
|
|
|
+
|
|
|
+ // Zen master achievement (10 minutes in zen mode)
|
|
|
+ if (sessionTime >= 600) {
|
|
|
+ await unlockAchievement(achievementZenMaster);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Check score-based achievements
|
|
|
+ Future<void> checkScoreAchievements(int score, double timeToReachScore) async {
|
|
|
+ if (!_isSignedIn) return;
|
|
|
+
|
|
|
+ // Speed demon achievement (reach 1000 points in under 2 minutes)
|
|
|
+ if (score >= 1000 && timeToReachScore <= 120) {
|
|
|
+ await unlockAchievement(achievementSpeedDemon);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Submit various scores to leaderboards
|
|
|
+ Future<void> submitGameResults({
|
|
|
+ required int finalScore,
|
|
|
+ required bool isZenMode,
|
|
|
+ required int totalBubblesPopped,
|
|
|
+ required double sessionLength,
|
|
|
+ }) async {
|
|
|
+ if (!_isSignedIn) return;
|
|
|
+
|
|
|
+ // Submit to appropriate leaderboards
|
|
|
+ if (isZenMode) {
|
|
|
+ await submitScore(leaderboardZenMode, sessionLength.round());
|
|
|
+ } else {
|
|
|
+ await submitScore(leaderboardHighScore, finalScore);
|
|
|
+ }
|
|
|
+
|
|
|
+ await submitScore(leaderboardTotalBubbles, totalBubblesPopped);
|
|
|
+ await submitScore(leaderboardLongestSession, sessionLength.round());
|
|
|
+
|
|
|
+ // Check achievements
|
|
|
+ await checkBubbleAchievements(totalBubblesPopped);
|
|
|
+ if (isZenMode) {
|
|
|
+ await checkZenModeAchievements(sessionLength);
|
|
|
+ } else {
|
|
|
+ await checkScoreAchievements(finalScore, sessionLength);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|