diff --git a/src/AUTH/GoogleAUTH.js b/src/AUTH/GoogleAUTH.js index 93f86b9..274a242 100644 --- a/src/AUTH/GoogleAUTH.js +++ b/src/AUTH/GoogleAUTH.js @@ -5,6 +5,7 @@ import { File, Directory, Paths } from 'expo-file-system'; import { AuthServiceBase } from './AuthServiceBase'; import MediaMetadataService from '../services/MediaMetadataService'; import { logError } from '../services/ErrorHandler'; +import { Platform, Linking } from 'react-native'; WebBrowser.maybeCompleteAuthSession(); @@ -378,50 +379,80 @@ class GoogleAUTH extends AuthServiceBase { return results; } - async pickPhotos() { - try { - console.log('Creating Google Photos Picker session…'); - const session = await this._createPickerSession(); + async pickPhotos() { + try { + console.log('Creating Google Photos Picker session…'); + const session = await this._createPickerSession(); - if (session?.error) { - return this._buildPickerError(session.error.code, session.error.message); - } - if (!session?.id || !session?.pickerUri) { - return this._buildPickerError(0, 'Failed to create Picker session'); - } + if (session?.error) { + return this._buildPickerError(session.error.code, session.error.message); + } + if (!session?.id || !session?.pickerUri) { + return this._buildPickerError(0, 'Failed to create Picker session'); + } - console.log('Picker session created:', session.id); - console.log('Opening picker for user selection…'); + console.log('Picker session created:', session.id); + console.log('Opening picker for user selection…'); + console.log('Platform:', Platform.OS); + console.log('Picker URI:', session.pickerUri.substring(0, 100) + '...'); - await WebBrowser.openBrowserAsync(session.pickerUri, { - dismissButtonStyle: 'done', - presentationStyle: 'pageSheet', - }); + // Try WebBrowser first + let browserOpened = false; + try { + const result = await WebBrowser.openBrowserAsync(session.pickerUri, { + dismissButtonStyle: 'done', + presentationStyle: 'pageSheet', + }); + browserOpened = true; + console.log('WebBrowser closed with result:', result?.type); + } catch (webBrowserErr) { + console.warn('WebBrowser failed:', webBrowserErr.message); + // Fallback: try direct URL linking on Android APK builds + if (Platform.OS === 'android') { + console.log('Attempting fallback with Linking.openURL...'); + try { + const canOpen = await Linking.canOpenURL(session.pickerUri); + console.log('Can open URL:', canOpen); + if (canOpen) { + await Linking.openURL(session.pickerUri); + browserOpened = true; + } else { + console.warn('System cannot open picker URL'); + } + } catch (linkErr) { + console.warn('Linking.openURL failed:', linkErr.message); + } + } + } - console.log('Browser closed — polling for selected photos…'); + if (!browserOpened) { + return this._buildPickerError(0, 'Failed to open browser/picker. Please check your internet connection and try again.'); + } - const ready = await this._waitForSession(session.id); - if (!ready) { - return this._buildPickerError(0, 'No photos were selected or the picker was dismissed', session.id); - } + console.log('Browser closed — polling for selected photos…'); - const result = await this._fetchPickerMediaItems(session.id, 100, null); - let mediaItems = this._normalisePickerItems(result.mediaItems); + const ready = await this._waitForSession(session.id); + if (!ready) { + return this._buildPickerError(0, 'No photos were selected or the picker was dismissed', session.id); + } - console.log(`Picker returned ${mediaItems.length} selected items, downloading…`); - mediaItems = await this.downloadPickerPhotos(mediaItems); - console.log(`Downloaded ${mediaItems.filter((m) => m.local_path).length} photos to cache`); + const result = await this._fetchPickerMediaItems(session.id, 100, null); + let mediaItems = this._normalisePickerItems(result.mediaItems); - return { - mediaItems, - nextPageToken: result.nextPageToken || null, - sessionId: session.id, - }; - } catch (error) { - logError('Pick Photos', error); - return EMPTY_PICK_RESULT; - } - } + console.log(`Picker returned ${mediaItems.length} selected items, downloading…`); + mediaItems = await this.downloadPickerPhotos(mediaItems); + console.log(`Downloaded ${mediaItems.filter((m) => m.local_path).length} photos to cache`); + + return { + mediaItems, + nextPageToken: result.nextPageToken || null, + sessionId: session.id, + }; + } catch (error) { + logError('Pick Photos', error); + return EMPTY_PICK_RESULT; + } + } async getMorePhotos(pageSize = 100, pageToken, sessionId) { try { diff --git a/src/screens/HomeScreen.js b/src/screens/HomeScreen.js index ebfaf9c..0a6e213 100644 --- a/src/screens/HomeScreen.js +++ b/src/screens/HomeScreen.js @@ -272,6 +272,7 @@ const HomeScreen = ({ navigation, route }) => { const googleAccount = linkedAccounts.find((a) => a.service_type === 'GOOGLE_PHOTOS'); if (!googleAccount) { console.warn('No Google account linked'); + Alert.alert('Error', 'No Google account linked. Please link your Google account in Settings.'); return; } @@ -297,6 +298,11 @@ const HomeScreen = ({ navigation, route }) => { if (result?.error) { logError('Import Google Photos', result.error.message); + Alert.alert( + 'Google Photos Picker Error', + result.error.message || 'Failed to open Google Photos picker. Please try again.', + [{ text: 'OK' }] + ); } else if (result?.mediaItems?.length) { await Promise.all(result.mediaItems.map((item) => DatabaseService.saveMediaItem(userId, item))); @@ -306,6 +312,9 @@ const HomeScreen = ({ navigation, route }) => { setAllMedia((prev) => mergeMediaAcrossServices([...prev, ...result.mediaItems])); console.log(`Imported ${result.mediaItems.length} photos from Google`); + Alert.alert('Success', `Imported ${result.mediaItems.length} photos from Google Photos`); + } else { + console.log('No photos selected'); } if (googleAuth.accessToken && googleAuth.accessToken !== data.accessToken) { @@ -318,6 +327,11 @@ const HomeScreen = ({ navigation, route }) => { } } catch (err) { logError('Import Google Photos', err); + Alert.alert( + 'Error', + `Failed to import from Google Photos: ${err.message}`, + [{ text: 'OK' }] + ); } finally { setImporting(false); }