From d865708e28bc3ec0cc4fff7ae792a95df6cf7332 Mon Sep 17 00:00:00 2001 From: mudabbir-ahmad Date: Sun, 22 Feb 2026 22:35:57 +0000 Subject: [PATCH] refactor app configuration and improve Google OAuth handling; update .gitignore and enhance test documentation --- .gitignore | 2 ++ TEST/testGooglePhotosAPI.js | 39 +++++++++++++++++++------------------ app.json | 19 +++++++++++------- eas.json | 30 ++++++++++++++++++++++++++++ src/AUTH/GoogleAUTH.js | 20 +++++++++---------- src/screens/HomeScreen.js | 10 +++++----- 6 files changed, 79 insertions(+), 41 deletions(-) create mode 100644 eas.json diff --git a/.gitignore b/.gitignore index 61f1bf6..b626fb8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ !/Ignore files/ !/package-lock.json +!/.expo/ +!/.idea/ diff --git a/TEST/testGooglePhotosAPI.js b/TEST/testGooglePhotosAPI.js index 6c83a34..2bc4316 100644 --- a/TEST/testGooglePhotosAPI.js +++ b/TEST/testGooglePhotosAPI.js @@ -1,22 +1,23 @@ -/** - * Google Photos OAuth & API Test - * - * Usage: - * node TEST/testGooglePhotosAPI.js - * GOOGLE_ACCESS_TOKEN=ya29.xxx node TEST/testGooglePhotosAPI.js - * - * How to get a token for manual testing: - * 1. Go to https://developers.google.com/oauthplayground - * 2. Select "Photos Library API v1" → photoslibrary scope - * 3. Authorise the API - * 4. Exchange the authorization code for tokens - * 5. Copy the access token and pass it to this script - * - * Tests: - * 1. Validates the token against the userinfo endpoint - * 2. Lists media items from Google Photos - * 3. Lists albums from Google Photos - */ +// Google Photos API Test +// +// Usage: +// node TEST/testGooglePhotosAPI.js +// GOOGLE_ACCESS_TOKEN=ya29.xxx node TEST/testGooglePhotosAPI.js +// +// Getting a token from OAuth Playground (https://developers.google.com/oauthplayground): +// 1. Click the gear icon → check "Use your own OAuth credentials" +// 2. Enter your Client ID and Client Secret from Google Cloud Console +// 3. In the left panel select ALL of these scopes: +// https://www.googleapis.com/auth/photoslibrary +// https://www.googleapis.com/auth/photoslibrary.appendonly +// https://www.googleapis.com/auth/userinfo.email +// https://www.googleapis.com/auth/userinfo.profile +// 4. Click "Authorize APIs" and sign in with your test Google account +// 5. Click "Exchange authorization code for tokens" +// 6. Copy the Access token (starts with ya29.) and pass it here +// +// Note: if you only see 403 PERMISSION_DENIED, the token was issued without +// the photoslibrary scope — go back and re-authorise with all scopes above. const API_BASE = 'https://photoslibrary.googleapis.com/v1'; const USERINFO_URL = 'https://www.googleapis.com/oauth2/v2/userinfo'; diff --git a/app.json b/app.json index 368e1c3..d36fbab 100644 --- a/app.json +++ b/app.json @@ -1,12 +1,12 @@ { "expo": { - "name": "Media-Aggregation-and-Sorting-System", - "slug": "Media-Aggregation-and-Sorting-System", + "name": "MASS Photo App", + "slug": "mass-expo", + "owner": "bobthebob", "version": "1.0.0", "orientation": "portrait", "icon": "./assets/icon.png", - "userInterfaceStyle": "light", - "newArchEnabled": true, + "userInterfaceStyle": "automatic", "splash": { "image": "./assets/splash-icon.png", "resizeMode": "contain", @@ -16,11 +16,11 @@ "supportsTablet": true }, "android": { + "package": "com.bobthebob.massphotoapp", "adaptiveIcon": { "foregroundImage": "./assets/adaptive-icon.png", "backgroundColor": "#ffffff" - }, - "edgeToEdgeEnabled": true + } }, "web": { "favicon": "./assets/favicon.png" @@ -28,6 +28,11 @@ "scheme": "media-aggregation", "plugins": [ "expo-sqlite" - ] + ], + "extra": { + "eas": { + "projectId": "472bba14-1f7f-4cbe-b37b-3ec2c4077d03" + } + } } } diff --git a/eas.json b/eas.json new file mode 100644 index 0000000..1f7728b --- /dev/null +++ b/eas.json @@ -0,0 +1,30 @@ +{ + "cli": { + "version": ">= 16.0.0", + "appVersionSource": "local" + }, + "build": { + "development": { + "developmentClient": true, + "distribution": "internal", + "android": { + "buildType": "apk" + } + }, + "preview": { + "distribution": "internal", + "android": { + "buildType": "apk" + } + }, + "production": { + "android": { + "buildType": "app-bundle" + } + } + }, + "submit": { + "production": {} + } +} + diff --git a/src/AUTH/GoogleAUTH.js b/src/AUTH/GoogleAUTH.js index de77a25..9b624d8 100644 --- a/src/AUTH/GoogleAUTH.js +++ b/src/AUTH/GoogleAUTH.js @@ -4,16 +4,20 @@ import { AuthServiceBase } from './AuthServiceBase'; WebBrowser.maybeCompleteAuthSession(); -// Replace with your real Google Cloud OAuth Client ID (see ignorefiles/GOOGLE_OAUTH_SETUP.md) const GOOGLE_CLIENT_ID = '313090284964-rgq1u7np6ogucu9o97s134n5nc6nj7kf.apps.googleusercontent.com'; +// makeRedirectUri uses the scheme from app.json ("media-aggregation") to build +// the deep link URI that Android will route back into the app after OAuth. +// The resulting URI is: media-aggregation:// (registered in Google Cloud Console) +// For Expo Go dev testing the loopback http://localhost is used instead. +const REDIRECT_URI = AuthSession.makeRedirectUri({ scheme: 'media-aggregation' }); + const GOOGLE_DISCOVERY = { authorizationEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth', tokenEndpoint: 'https://oauth2.googleapis.com/token', revocationEndpoint: 'https://oauth2.googleapis.com/revoke', }; -// Google Photos Library API scopes — read, write, and user profile const SCOPES = [ 'https://www.googleapis.com/auth/photoslibrary', 'https://www.googleapis.com/auth/photoslibrary.appendonly', @@ -48,15 +52,12 @@ class GoogleAUTH extends AuthServiceBase { }; } - const redirectUri = AuthSession.makeRedirectUri({ - scheme: 'media-aggregation', - preferLocalhost: true, - }); + console.log('OAuth redirect URI:', REDIRECT_URI); const authRequest = new AuthSession.AuthRequest({ clientId: GOOGLE_CLIENT_ID, scopes: SCOPES, - redirectUri, + redirectUri: REDIRECT_URI, responseType: AuthSession.ResponseType.Code, usePKCE: true, extraParams: { access_type: 'offline', prompt: 'consent' }, @@ -72,7 +73,7 @@ class GoogleAUTH extends AuthServiceBase { { clientId: GOOGLE_CLIENT_ID, code: result.params.code, - redirectUri, + redirectUri: REDIRECT_URI, extraParams: { code_verifier: authRequest.codeVerifier }, }, GOOGLE_DISCOVERY @@ -80,7 +81,6 @@ class GoogleAUTH extends AuthServiceBase { this.accessToken = tokenResponse.accessToken; this.refreshToken = tokenResponse.refreshToken; - this.idToken = tokenResponse.idToken; this.expiresAt = tokenResponse.issuedAt ? (tokenResponse.issuedAt + (tokenResponse.expiresIn || 3600)) * 1000 : Date.now() + 3600000; @@ -91,7 +91,7 @@ class GoogleAUTH extends AuthServiceBase { return { success: true, accessToken: this.accessToken, - refreshToken: this.refreshToken, + refreshToken: null, email: this.email, }; } catch (error) { diff --git a/src/screens/HomeScreen.js b/src/screens/HomeScreen.js index 9a771ae..0e07533 100644 --- a/src/screens/HomeScreen.js +++ b/src/screens/HomeScreen.js @@ -199,13 +199,13 @@ const styles = StyleSheet.create({ centerContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 24 }, loadingText: { marginTop: 12, fontSize: 14 }, // Filter chips - filterRow: { paddingHorizontal: 12, paddingVertical: 8, gap: 8 }, + filterRow: { paddingHorizontal: 12, paddingVertical: 6, gap: 6 }, chip: { - flexDirection: 'row', alignItems: 'center', paddingHorizontal: 14, paddingVertical: 7, - borderRadius: 20, gap: 6, + flexDirection: 'row', alignItems: 'center', paddingHorizontal: 10, paddingVertical: 4, + borderRadius: 12, gap: 4, }, - chipIcon: { fontSize: 13 }, - chipText: { fontSize: 13, fontWeight: '500', color: '#3c4043' }, + chipIcon: { fontSize: 11 }, + chipText: { fontSize: 12, fontWeight: '500', color: '#3c4043' }, // Empty emptyTitle: { fontSize: 18, fontWeight: '600', marginBottom: 6 }, emptyText: { fontSize: 13, textAlign: 'center', marginBottom: 20 },