In this tutorial series you are building a location-aware photo saving app. Last time you implemented user login, this time you will display the user’s existing photo collection. The photos will display inside a dynamic Element at a small size, then the user will be able to select a photo to see it at a larger size in another page, along with its location marked on a map, annotated with the date the photo was taken and some additional information about the place.
When the user has no photos saved yet and while their photos are loading, the app will display some placeholder content. In the Collection page, add an Image near the center of the Canvas, naming it “Placeholder Image”, and using the empty collection image asset:
Under the Image, add a Text View, naming it “Placeholder Text View”, displaying the following text:
You haven't saved any pictures yet! Use the add button at the top to take a photo and save it at your current location.
You will display the photos on top of these Elements, so they’ll only be visible when there are no photos to show.
Add a Dynamic Element
Add a dynamic Element to display the photo collection – for example a Collection View on iOS or a Dynamic List on Android. Name the element e.g. “Photo Collection View” or “Photo List” and use Constraints to make it fill the page.
- Inside the dynamic Element add a relevant child Element – for example a Collection View Cell, Dynamic List Tile, or child View. Rename the child Element to “Photo Cell” or similar. Resize the child Element to whatever size you want the photos to display in this initial page, bearing in mind that they’ll display larger in the next page, with the images on this page acting like thumbnails.
- Add an Image inside the dynamic child Element, renaming it “Photo Image” and sizing it to occupy most of the available space (you can use border properties on iOS to create space around the Element). Set the Image scaling property to fill or aspect fill the Element.
Your page should look something like this:
Select the dynamic parent Element (e.g. Collection View, Dynamic List) and in Properties, check Hidden. You should now only be able to see the placeholder Elements on the Canvas (you can still select the hidden Elements in the Element Tree) – you will show the dynamic Element when the API response is received and there are photos to display.
Display the Photos
Last time you added the API request to retrieve the user’s photo collection, so now you can display that data in the page. In the API tab, open the GET request and select Responses.
The collection is returned from the API in an array, containing the URL for each photo together with its location co-ordinates and the date it was taken. The array is represented in Dropsource as a Data Source – bind the Data Source to the dynamic parent Element you added, by clicking the response field and making a selection in the Elements container.
This will allow you to display one of the photos in each dynamic child Element, and to access the location and date info when the user selects a photo to view more detail on it.
In the Element Tree, select the dynamic child Element (e.g. Cell, Tile, or child View) and open Properties > Events. Add an Action to the Load Event, choosing Display Image from URL. Select the Photo Image Element and pull the URL from the API response via the Data Source container – it’s the picture - Image field.
Since the Data Source is bound to the dynamic Element, when the data for each entry in the array loads into the dynamic child Element, the load Event will fire. Inside that Event, the app can access the array fields for the entry each particular child Element is loading, so it will display the image from the URL for each photo returned.
Tailor Display to Collection Status
When the collection response is received, it will either contain one or more user photos, or it will contain an empty array because the user hasn’t saved any yet. If there are photos in the collection, the app will show the dynamic Element you hid earlier. In the API tab, open the request Events and this time add an Action to the 200 Event, which will fire when a successful response is received.
Add an If Else Action to check how many photos there are in the collection – use the Event Data to test if the Results array Count or Length field is greater than 0 (enter 0 as a Static Input Int).
If the nested True Event fires, there are photos in the collection, so add a Set Value Action there to show the dynamic Element you hid.
In the False Event, add a Set Value hiding the same Element (in case the user collection has changed since the page first loaded).
You added the Run API Request Action for this request earlier in the Collection page Appear / Resume Event so it’s already set up to execute.
If you used an overlay or progress Element when you ran the request earlier make sure you include an Action here to hide it again.
At this point you can run the app again! Use the Test button to commit your changes to a new build, then launch it in the simulator when it’s ready. Enter your login credentials and the app should take you to the Collection page – at this stage you won’t have any photos so should just see the placeholder content – you’ll add photos later.
Show Photo Detail
The next page in the app is going to show more detail on a photo selected by the user in the Collection page. In this new page, the user will see the photo at a larger size, and the location it was taken marked on a map along with the date and some place information.
Add a new page to the app, choosing the Nav Bar / App Bar config and naming it “Photo”. Set the page nav Element title to “Photo”.
This page is going to receive the details for the photo selected by the user on the Collection page, including the URL for the photo, the latitude and longitude it was taken at, and the date it was taken, so in the Page Variables tab on the right, add the following variables, checking Is required during inbound navigation on each one:
- image_url – String
- date – String
- lat – Float
- lng – Float
Pass Photo Detail
Back in the Collection page, the user will navigate to the Photo page by tapping a photo in the collection, so select the child of the dynamic Element you added in the Element Tree (e.g. Cell, Tile, or child View) and open its Tapped Event. Add a Go To Page Action, selecting the Photo page, a push transition, and passing the page variables from the Data Source as follows:
- image_url = picture - Image
- lat = picture - Latitude
- lng = picture - Longitude
- date = picture - Created Date
Back in the Photo page, add back navigation to the Collection page:
- On iOS, select the page on the Canvas and in Properties, check Back Button Enabled.
- On Android, select the App Bar and in Properties, set a Nav Icon image, such as this back arrow:
Add an Action to the App Bar Nav Icon Tapped Event, choosing Go Back a Page.
Now add Elements to show the photo and location:
- An Image Element, named “Photo Image” and resized to occupy the top half of the page – choose a scale to fill or aspect fill scaling type in Properties.
- A Map Element, named “Map View”, and resized to occupy the remaining half of the page.
Your page should look something like this:
On Android you will need to enter a Google API Key to use location functionality – add yours in Settings > Location on the left of the editor.
On iOS, select the Photo page in the Element Tree (the parent Element) and click Add for its Loaded Event. On Android select the Map Element and open its Finished Loading Event. Here you will add the functionality to display the photo and map information.
First add a Display Image from URL Action, selecting the Image Element and the URL from the Page Variable.
Next you need to carry out some processing on the date – it’s generated by the Bubble API and returned in the response as a date-time string. To turn it into readable text, first add the Create a Date from a Date-Time String Action:
- For the Date String parameter, select the Page Variable.
- For the Date Format, enter yyyy-MM-dd'T'HH:mm:ss.SSS'Z' on iOS and EEE MMM dd HH:mm:ss 'GMT'z yyyy on Android.
- Select a Locale, such as English.
This Action will return a Date that you can then use to display the date in a more readable format. Add a Format Date to String Action next:
- Select the Date returned by the previous Action via the Action Data container.
- Enter dd MMMM yyyy 'at' HH:mm for the Date Format.
- Choose a Locale, such as English.
You may experience issues formatting and displaying dates on the simulator for Android, so for best results download your code and run it from Android Studio, or run it on a mobile device.
You will be able to display the date returned from this Action in the marker you place on the map. To display the location, add another Action – this time Create a Location / LatLng Object. Select the latitude and longitude Page Variables.
Next add a Set Visible Map Region Action:
- Select the Map Element.
- Enter a Distance / Zoom Int value such as 5000 meters (iOS) / Float value such as 12 (Android).
- The Location returned from the previous Action via the Action Data.
So that you can display some additional info about the location, add a Reverse Geocode Location Action, selecting the location returned from the Action that created the location object.
In the nested Address / Placemark Found Event, add the Add Pin to Map / Create Marker Action.
- Select the Map Element.
- For the Title, use the placemark - Name (iOS) / address - Line One (Android) field from the Reverse Geocode Action via the Event Data.
- For the Subtitle, use the formatted date returned from the Format Date to String Event via the Action Data.
- Select the Location returned from the Action that created a location object.
You won’t be able to see the Photo page in action until you’re able to add some photos to a user collection. Next time you will add the ability to upload photos together with the user’s current location.