382 lines
12 KiB
Dart
382 lines
12 KiB
Dart
import 'dart:io';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:live_activities/live_activities.dart';
|
|
|
|
class LiveActivitiesService {
|
|
// Use a singleton pattern
|
|
static final LiveActivitiesService _instance =
|
|
LiveActivitiesService._internal();
|
|
|
|
// LiveActivities plugin instance
|
|
final LiveActivities _liveActivities = LiveActivities();
|
|
bool _isInitialized = false;
|
|
bool _isSupported = false;
|
|
String? _appGroupId;
|
|
String? _urlScheme;
|
|
|
|
factory LiveActivitiesService() => _instance;
|
|
LiveActivitiesService._internal();
|
|
|
|
/// Initialize the Live Activities service with specific app group ID and URL scheme
|
|
Future<bool> init(
|
|
{required String appGroupId, required String urlScheme}) async {
|
|
debugPrint(
|
|
'LiveActivitiesService: Initializing with appGroupId: $appGroupId, urlScheme: $urlScheme');
|
|
|
|
// Store directly in the instance
|
|
_appGroupId = appGroupId;
|
|
_urlScheme = urlScheme;
|
|
|
|
// Initialize the plugin with the app group ID
|
|
try {
|
|
// Using the init method of the plugin with appGroupId
|
|
await _liveActivities.init(appGroupId: appGroupId);
|
|
debugPrint(
|
|
'LiveActivitiesService: Initialized plugin with appGroupId: $appGroupId');
|
|
} catch (e) {
|
|
debugPrint('LiveActivitiesService: Error initializing plugin: $e');
|
|
}
|
|
|
|
final result = await initialize();
|
|
|
|
// Debug verification
|
|
debugPrint(
|
|
'LiveActivitiesService: After init - appGroupId: $_appGroupId, initialized: $_isInitialized, supported: $_isSupported');
|
|
|
|
return result;
|
|
}
|
|
|
|
/// Initialize the Live Activities service
|
|
Future<bool> initialize() async {
|
|
if (_isInitialized) {
|
|
debugPrint(
|
|
'LiveActivitiesService: Already initialized, supported: $_isSupported, appGroupId: $_appGroupId');
|
|
return _isSupported;
|
|
}
|
|
|
|
// Live Activities are only supported on iOS 16.1+
|
|
if (!Platform.isIOS) {
|
|
debugPrint(
|
|
'LiveActivitiesService: Platform is not iOS, Live Activities not supported');
|
|
_isSupported = false;
|
|
_isInitialized = true;
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
// Request permissions explicitly
|
|
final permissionGranted = await _requestLiveActivitiesPermission();
|
|
if (!permissionGranted) {
|
|
debugPrint('LiveActivitiesService: Permission not granted');
|
|
_isSupported = false;
|
|
_isInitialized = true;
|
|
return false;
|
|
}
|
|
|
|
// Check if Live Activities are supported on this device
|
|
_isSupported = await _liveActivities.areActivitiesEnabled();
|
|
_isInitialized = true;
|
|
|
|
debugPrint(
|
|
'LiveActivitiesService: Initialized, supported: $_isSupported, appGroupId: $_appGroupId');
|
|
return _isSupported;
|
|
} catch (e) {
|
|
debugPrint('LiveActivitiesService: Error initializing: $e');
|
|
_isSupported = false;
|
|
_isInitialized = true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Request permission for Live Activities
|
|
Future<bool> _requestLiveActivitiesPermission() async {
|
|
try {
|
|
// Check if permission is already granted
|
|
bool alreadyGranted = await _liveActivities.areActivitiesEnabled();
|
|
if (alreadyGranted) {
|
|
debugPrint('LiveActivitiesService: Permission already granted');
|
|
return true;
|
|
}
|
|
|
|
// iOS 16.1+ requires the user to explicitly enable Live Activities
|
|
// There's no direct permission API, the user must enable it in Settings
|
|
// We can only check if it's enabled, not request it directly
|
|
debugPrint(
|
|
'LiveActivitiesService: Checking Live Activities availability');
|
|
final isEnabled = await _liveActivities.areActivitiesEnabled();
|
|
|
|
if (!isEnabled) {
|
|
debugPrint(
|
|
'LiveActivitiesService: Live Activities not enabled. User needs to enable in Settings');
|
|
}
|
|
|
|
return isEnabled;
|
|
} catch (e) {
|
|
debugPrint('LiveActivitiesService: Error checking permission: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Get appGroupId safely, ensuring it's available
|
|
String? _getAppGroupId() {
|
|
if (_appGroupId == null) {
|
|
debugPrint(
|
|
'LiveActivitiesService: Warning - appGroupId is null. Please call init() first.');
|
|
debugPrint(
|
|
'LiveActivitiesService: Current state: initialized=$_isInitialized, supported=$_isSupported');
|
|
}
|
|
return _appGroupId;
|
|
}
|
|
|
|
/// Helper method to create a search activity
|
|
Future<String?> createSearchActivity({
|
|
required String title,
|
|
required String query,
|
|
required String count,
|
|
}) async {
|
|
if (!_isInitialized) await initialize();
|
|
if (!_isSupported) return null;
|
|
|
|
try {
|
|
// Use instance appGroupId
|
|
final String? appGroupId = _getAppGroupId();
|
|
|
|
// Verify appGroupId is set
|
|
if (appGroupId == null) {
|
|
throw Exception('appGroupId is null. Please call init() first.');
|
|
}
|
|
|
|
// Always reinitialize with the current app group ID to ensure it's set correctly
|
|
await _liveActivities.init(appGroupId: appGroupId);
|
|
debugPrint(
|
|
'LiveActivitiesService: Ensuring plugin initialized with appGroupId: $appGroupId');
|
|
|
|
debugPrint(
|
|
'LiveActivitiesService: Creating activity with appGroupId: $appGroupId');
|
|
|
|
// Create data for the activity
|
|
final Map<String, dynamic> activityData = {
|
|
'title': title,
|
|
'query': query,
|
|
'resultsCount': count,
|
|
'timestamp': DateTime.now().toIso8601String(),
|
|
'appGroup': appGroupId,
|
|
};
|
|
|
|
// Add urlScheme if available
|
|
if (_urlScheme != null) {
|
|
activityData['urlScheme'] = _urlScheme;
|
|
}
|
|
|
|
debugPrint('LiveActivitiesService: Activity data: $activityData');
|
|
|
|
// Create the activity
|
|
final activityId = await _liveActivities.createActivity(activityData);
|
|
|
|
debugPrint(
|
|
'LiveActivitiesService: Created activity with ID: $activityId');
|
|
|
|
// Get current active activities count
|
|
final activities = await _liveActivities.getAllActivitiesIds();
|
|
debugPrint(
|
|
'LiveActivitiesService: Active activities count: ${activities?.length ?? 0}');
|
|
|
|
return activityId;
|
|
} catch (e) {
|
|
debugPrint('LiveActivitiesService: Error creating activity: $e');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// Update an existing search activity
|
|
Future<bool> updateSearchActivity({
|
|
required String activityId,
|
|
required String title,
|
|
required String query,
|
|
required String count,
|
|
}) async {
|
|
if (!_isInitialized) await initialize();
|
|
if (!_isSupported) return false;
|
|
|
|
try {
|
|
// Use instance appGroupId
|
|
final String? appGroupId = _getAppGroupId();
|
|
|
|
// Verify appGroupId is set
|
|
if (appGroupId == null) {
|
|
throw Exception('appGroupId is null. Please call init() first.');
|
|
}
|
|
|
|
// Always reinitialize with the current app group ID to ensure it's set correctly
|
|
await _liveActivities.init(appGroupId: appGroupId);
|
|
debugPrint(
|
|
'LiveActivitiesService: Ensuring plugin initialized with appGroupId: $appGroupId');
|
|
|
|
// Create updated data for the activity
|
|
final Map<String, dynamic> activityData = {
|
|
'title': title,
|
|
'query': query,
|
|
'resultsCount': count,
|
|
'timestamp': DateTime.now().toIso8601String(),
|
|
'appGroup': appGroupId,
|
|
};
|
|
|
|
// Add urlScheme if available
|
|
if (_urlScheme != null) {
|
|
activityData['urlScheme'] = _urlScheme;
|
|
}
|
|
|
|
// Update the activity
|
|
final success =
|
|
await _liveActivities.updateActivity(activityId, activityData);
|
|
|
|
debugPrint(
|
|
'LiveActivitiesService: Updated activity $activityId: $success');
|
|
return success ?? false;
|
|
} catch (e) {
|
|
debugPrint('LiveActivitiesService: Error updating activity: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// End an existing search activity
|
|
Future<bool> endSearchActivity(String activityId) async {
|
|
if (!_isInitialized) await initialize();
|
|
if (!_isSupported) return false;
|
|
|
|
try {
|
|
// Get the appGroupId
|
|
final String? appGroupId = _getAppGroupId();
|
|
|
|
// Verify appGroupId is set
|
|
if (appGroupId == null) {
|
|
throw Exception('appGroupId is null. Please call init() first.');
|
|
}
|
|
|
|
// Always reinitialize with the current app group ID to ensure it's set correctly
|
|
await _liveActivities.init(appGroupId: appGroupId);
|
|
debugPrint(
|
|
'LiveActivitiesService: Ensuring plugin initialized with appGroupId: $appGroupId');
|
|
|
|
debugPrint('LiveActivitiesService: Ending activity $activityId');
|
|
|
|
// End the activity
|
|
final success = await _liveActivities.endActivity(activityId);
|
|
|
|
debugPrint('LiveActivitiesService: Ended activity $activityId: $success');
|
|
return success ?? false;
|
|
} catch (e) {
|
|
debugPrint('LiveActivitiesService: Error ending activity: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Get all active activities
|
|
Future<List<String>?> getActiveActivities() async {
|
|
if (!_isInitialized) await initialize();
|
|
if (!_isSupported) return null;
|
|
|
|
try {
|
|
// Get the appGroupId
|
|
final String? appGroupId = _getAppGroupId();
|
|
|
|
// Verify appGroupId is set
|
|
if (appGroupId == null) {
|
|
throw Exception('appGroupId is null. Please call init() first.');
|
|
}
|
|
|
|
// Always reinitialize with the current app group ID to ensure it's set correctly
|
|
await _liveActivities.init(appGroupId: appGroupId);
|
|
debugPrint(
|
|
'LiveActivitiesService: Ensuring plugin initialized with appGroupId: $appGroupId');
|
|
|
|
final activities = await _liveActivities.getAllActivitiesIds();
|
|
debugPrint(
|
|
'LiveActivitiesService: Found ${activities?.length ?? 0} active activities');
|
|
return activities;
|
|
} catch (e) {
|
|
debugPrint('LiveActivitiesService: Error getting active activities: $e');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// End all active activities
|
|
Future<bool> endAllActivities() async {
|
|
if (!_isInitialized) await initialize();
|
|
if (!_isSupported) return false;
|
|
|
|
try {
|
|
// Get the appGroupId
|
|
final String? appGroupId = _getAppGroupId();
|
|
|
|
// Verify appGroupId is set
|
|
if (appGroupId == null) {
|
|
throw Exception('appGroupId is null. Please call init() first.');
|
|
}
|
|
|
|
// Always reinitialize with the current app group ID to ensure it's set correctly
|
|
await _liveActivities.init(appGroupId: appGroupId);
|
|
debugPrint(
|
|
'LiveActivitiesService: Ensuring plugin initialized with appGroupId: $appGroupId');
|
|
|
|
// First try using the native plugin method if available
|
|
final success = await _liveActivities.endAllActivities();
|
|
if (success == true) {
|
|
debugPrint(
|
|
'LiveActivitiesService: Ended all activities using plugin method');
|
|
return true;
|
|
}
|
|
|
|
// Fallback to manual method if plugin doesn't support endAllActivities
|
|
final activities = await getActiveActivities();
|
|
if (activities == null || activities.isEmpty) {
|
|
debugPrint('LiveActivitiesService: No active activities to end');
|
|
return true;
|
|
}
|
|
|
|
bool allEnded = true;
|
|
for (final activityId in activities) {
|
|
final ended = await endSearchActivity(activityId);
|
|
if (!ended) {
|
|
allEnded = false;
|
|
debugPrint(
|
|
'LiveActivitiesService: Failed to end activity $activityId');
|
|
}
|
|
}
|
|
|
|
debugPrint(
|
|
'LiveActivitiesService: Ended ${activities.length} activities manually');
|
|
return allEnded;
|
|
} catch (e) {
|
|
debugPrint('LiveActivitiesService: Error ending all activities: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Request notification permission if needed
|
|
Future<bool> requestNotificationPermission() async {
|
|
if (!Platform.isIOS) return false;
|
|
|
|
try {
|
|
debugPrint('LiveActivitiesService: Requesting notification permission');
|
|
// The LiveActivities plugin doesn't have a direct method to request notification permission
|
|
// This is usually handled by the main app's notification system
|
|
return true;
|
|
} catch (e) {
|
|
debugPrint(
|
|
'LiveActivitiesService: Error requesting notification permission: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Check if Live Activities are supported on this device
|
|
bool get isSupported => _isSupported;
|
|
|
|
/// Check if Live Activities are initialized
|
|
bool get isInitialized => _isInitialized;
|
|
|
|
/// Get the current appGroupId
|
|
String? get appGroupId => _appGroupId;
|
|
}
|