feat: enhance Google Photos integration; add platform-specific handling and user alerts for picker errors

This commit is contained in:
bobbert committed 2026-04-16 19:57:43 +01:00
1 parent 882571d53b
commit 183e33cbfa
2 files changed
+81 -36

No files matched your search

+67 -36
View File
@@ -5,6 +5,7 @@ import { File, Directory, Paths } from 'expo-file-system';
import { AuthServiceBase } from './AuthServiceBase'; import { AuthServiceBase } from './AuthServiceBase';
import MediaMetadataService from '../services/MediaMetadataService'; import MediaMetadataService from '../services/MediaMetadataService';
import { logError } from '../services/ErrorHandler'; import { logError } from '../services/ErrorHandler';
import { Platform, Linking } from 'react-native';
WebBrowser.maybeCompleteAuthSession(); WebBrowser.maybeCompleteAuthSession();
@@ -378,50 +379,80 @@ class GoogleAUTH extends AuthServiceBase {
return results; return results;
} }
async pickPhotos() { async pickPhotos() {
try { try {
console.log('Creating Google Photos Picker session…'); console.log('Creating Google Photos Picker session…');
const session = await this._createPickerSession(); const session = await this._createPickerSession();
if (session?.error) { if (session?.error) {
return this._buildPickerError(session.error.code, session.error.message); return this._buildPickerError(session.error.code, session.error.message);
} }
if (!session?.id || !session?.pickerUri) { if (!session?.id || !session?.pickerUri) {
return this._buildPickerError(0, 'Failed to create Picker session'); return this._buildPickerError(0, 'Failed to create Picker session');
} }
console.log('Picker session created:', session.id); console.log('Picker session created:', session.id);
console.log('Opening picker for user selection…'); 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, { // Try WebBrowser first
dismissButtonStyle: 'done', let browserOpened = false;
presentationStyle: 'pageSheet', 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); console.log('Browser closed — polling for selected photos…');
if (!ready) {
return this._buildPickerError(0, 'No photos were selected or the picker was dismissed', session.id);
}
const result = await this._fetchPickerMediaItems(session.id, 100, null); const ready = await this._waitForSession(session.id);
let mediaItems = this._normalisePickerItems(result.mediaItems); 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…`); const result = await this._fetchPickerMediaItems(session.id, 100, null);
mediaItems = await this.downloadPickerPhotos(mediaItems); let mediaItems = this._normalisePickerItems(result.mediaItems);
console.log(`Downloaded ${mediaItems.filter((m) => m.local_path).length} photos to cache`);
return { console.log(`Picker returned ${mediaItems.length} selected items, downloading…`);
mediaItems, mediaItems = await this.downloadPickerPhotos(mediaItems);
nextPageToken: result.nextPageToken || null, console.log(`Downloaded ${mediaItems.filter((m) => m.local_path).length} photos to cache`);
sessionId: session.id,
}; return {
} catch (error) { mediaItems,
logError('Pick Photos', error); nextPageToken: result.nextPageToken || null,
return EMPTY_PICK_RESULT; sessionId: session.id,
} };
} } catch (error) {
logError('Pick Photos', error);
return EMPTY_PICK_RESULT;
}
}
async getMorePhotos(pageSize = 100, pageToken, sessionId) { async getMorePhotos(pageSize = 100, pageToken, sessionId) {
try { try {
+14
View File
@@ -272,6 +272,7 @@ const HomeScreen = ({ navigation, route }) => {
const googleAccount = linkedAccounts.find((a) => a.service_type === 'GOOGLE_PHOTOS'); const googleAccount = linkedAccounts.find((a) => a.service_type === 'GOOGLE_PHOTOS');
if (!googleAccount) { if (!googleAccount) {
console.warn('No Google account linked'); console.warn('No Google account linked');
Alert.alert('Error', 'No Google account linked. Please link your Google account in Settings.');
return; return;
} }
@@ -297,6 +298,11 @@ const HomeScreen = ({ navigation, route }) => {
if (result?.error) { if (result?.error) {
logError('Import Google Photos', result.error.message); 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) { } else if (result?.mediaItems?.length) {
await Promise.all(result.mediaItems.map((item) => DatabaseService.saveMediaItem(userId, item))); 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])); setAllMedia((prev) => mergeMediaAcrossServices([...prev, ...result.mediaItems]));
console.log(`Imported ${result.mediaItems.length} photos from Google`); 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) { if (googleAuth.accessToken && googleAuth.accessToken !== data.accessToken) {
@@ -318,6 +327,11 @@ const HomeScreen = ({ navigation, route }) => {
} }
} catch (err) { } catch (err) {
logError('Import Google Photos', err); logError('Import Google Photos', err);
Alert.alert(
'Error',
`Failed to import from Google Photos: ${err.message}`,
[{ text: 'OK' }]
);
} finally { } finally {
setImporting(false); setImporting(false);
} }