diff --git a/app.json b/app.json
index 37f0a5c..eb8cebb 100644
--- a/app.json
+++ b/app.json
@@ -34,6 +34,15 @@
"eas": {
"projectId": "1275f90e-33c6-4af1-942e-ca29a309f8c8"
}
- }
+ },
+ "plugins": [
+ [
+ "expo-image-picker",
+ {
+ "photosPermission": "Allow Luggage List to access your photos for trip and item images.",
+ "cameraPermission": "Allow Luggage List to use your camera to take trip and item photos."
+ }
+ ]
+ ]
}
}
diff --git a/src/AppRoot.js b/src/AppRoot.js
index ab2fa93..29e5c5a 100644
--- a/src/AppRoot.js
+++ b/src/AppRoot.js
@@ -169,6 +169,23 @@ export default function AppRoot() {
}
}
+ async function takeImage(onPicked) {
+ const perm = await ImagePicker.requestCameraPermissionsAsync();
+ if (!perm.granted) {
+ Alert.alert('Permission needed', 'Allow camera access to take photos.');
+ return;
+ }
+
+ const result = await ImagePicker.launchCameraAsync({
+ allowsEditing: false,
+ quality: 0.85,
+ });
+
+ if (!result.canceled && result.assets?.[0]?.uri) {
+ onPicked(result.assets[0].uri);
+ }
+ }
+
function createTrip() {
if (!tripForm.name.trim()) {
Alert.alert('Missing name', 'Trip name is required.');
@@ -526,6 +543,7 @@ export default function AppRoot() {
tripForm={tripForm}
updateTripForm={updateTripForm}
pickTripImage={() => pickImage((uri) => updateTripForm('imageUri', uri))}
+ takeTripImage={() => takeImage((uri) => updateTripForm('imageUri', uri))}
templateTrip={templateTrip}
createTrip={createTrip}
trips={data.trips}
@@ -587,6 +605,7 @@ export default function AppRoot() {
setItemModalVisible={setItemModalVisible}
updateItemForm={updateItemForm}
pickItemImage={() => pickImage((uri) => updateItemForm('imageUri', uri))}
+ takeItemImage={() => takeImage((uri) => updateItemForm('imageUri', uri))}
saveItemFromModal={saveItemFromModal}
/>
diff --git a/src/modals/ItemModal.js b/src/modals/ItemModal.js
index 18020b9..d1efbb0 100644
--- a/src/modals/ItemModal.js
+++ b/src/modals/ItemModal.js
@@ -11,6 +11,7 @@ export default function ItemModal({
setItemModalVisible,
updateItemForm,
pickItemImage,
+ takeItemImage,
saveItemFromModal,
}) {
return (
@@ -81,9 +82,14 @@ export default function ItemModal({
) : null}
-
- {itemForm.imageUri ? 'Change image' : 'Add image'}
-
+
+
+ Take photo
+
+
+ {itemForm.imageUri ? 'From gallery (change)' : 'From gallery'}
+
+
{!!itemForm.imageUri && }
diff --git a/src/styles.js b/src/styles.js
index 78b5c1e..f87c42a 100644
--- a/src/styles.js
+++ b/src/styles.js
@@ -211,6 +211,11 @@ export const styles = StyleSheet.create({
color: '#dbeafe',
fontWeight: '700',
},
+ actionRow: {
+ flexDirection: 'row',
+ gap: 8,
+ marginTop: 4,
+ },
inlineToggle: {
marginTop: 2,
diff --git a/src/tabs/TripsTab.js b/src/tabs/TripsTab.js
index e509b49..542f6d1 100644
--- a/src/tabs/TripsTab.js
+++ b/src/tabs/TripsTab.js
@@ -17,6 +17,7 @@ export default function TripsTab({
tripForm,
updateTripForm,
pickTripImage,
+ takeTripImage,
templateTrip,
createTrip,
trips,
@@ -58,9 +59,14 @@ export default function TripsTab({
openDatePicker('startDate')} />
openDatePicker('endDate')} />
-
- {tripForm.imageUri ? 'Change trip image' : 'Add trip image'}
-
+
+
+ Take photo
+
+
+ {tripForm.imageUri ? 'From gallery (change)' : 'From gallery'}
+
+
{tripForm.imageUri ? : null}