From 2e867c6b2db2c99535d949accf8a9d029f8c0eee Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Mon, 3 Jun 2024 17:36:13 +0200
Subject: [PATCH] cleaner ci

---
 .gitea/workflows/frontend_build-android.yaml  | 26 +++----
 frontend/android/.gitignore                   |  1 +
 frontend/android/README.md                    | 48 +++++++++++++
 frontend/android/app/build.gradle             |  7 +-
 .../android/app/src/main/AndroidManifest.xml  |  2 +-
 frontend/android/build.gradle                 | 11 +++
 frontend/android/fallback.properties          |  1 +
 frontend/lib/modules/landmark_card.dart       | 72 +++++++++----------
 frontend/lib/structs/landmark.dart            |  2 +
 frontend/lib/utils/get_landmarks.dart         | 37 ++++++++--
 10 files changed, 150 insertions(+), 57 deletions(-)
 create mode 100644 frontend/android/README.md
 create mode 100644 frontend/android/fallback.properties

diff --git a/.gitea/workflows/frontend_build-android.yaml b/.gitea/workflows/frontend_build-android.yaml
index a1e2d7e..16c22fb 100644
--- a/.gitea/workflows/frontend_build-android.yaml
+++ b/.gitea/workflows/frontend_build-android.yaml
@@ -42,20 +42,20 @@ jobs:
     - run: flutter pub get
       working-directory: ./frontend
 
-    - run: flutter build apk --release --split-per-abi
+    - name: Add required secrets
+      run: |
+        echo ${{ secrets.ANDROID_SECRETS_BASE64 }} | base64 -d > android/secrets.properties
       working-directory: ./frontend
 
-    - name: Release APK
-      uses: https://gitea.com/akkuman/gitea-release-action@v1
+    - run: flutter build apk --release --split-per-abi --build-number=${{ gitea.run_number }}
+      working-directory: ./frontend
+
+    - name: Upload APKs to artifacts
+      uses: https://gitea.com/actions/upload-artifact@v3
       with:
-        files: ./frontend/build/app/outputs/flutter-apk/*.apk
-        name: Testing release
-        release_name: testing
-        tag: testing
-        tag_name: testing
-        release_body: "This is a testing release."
-        prerelease: true
-        token: ${{ secrets.GITEA_TOKEN }}
-      env:
-        NODE_OPTIONS: '--experimental-fetch'
+        name: app-release
+        path: frontend/build/app/outputs/flutter-apk/
+        if-no-files-found: error
+        retention-days: 15
+
       
diff --git a/frontend/android/.gitignore b/frontend/android/.gitignore
index 6f56801..3592eab 100644
--- a/frontend/android/.gitignore
+++ b/frontend/android/.gitignore
@@ -4,6 +4,7 @@ gradle-wrapper.jar
 /gradlew
 /gradlew.bat
 /local.properties
+/secrets.properties
 GeneratedPluginRegistrant.java
 
 # Remember to never publicly share your keystore.
diff --git a/frontend/android/README.md b/frontend/android/README.md
new file mode 100644
index 0000000..1e3354e
--- /dev/null
+++ b/frontend/android/README.md
@@ -0,0 +1,48 @@
+## Android Setup
+
+### Keystore setup
+```bash
+keytool -genkey -v -keystore release.keystore -keyalg RSA -keysize 2048 -validity 10000 -alias release
+```
+- This is required to store local credentials securely (not used for now).
+- But necesseary in order to restrict the particular api key to a particular app (through the sha1 of the associated keystore).
+
+
+### Building and secret credentials
+Following the guide under [https://developers.google.com/maps/flutter-package/config#android_1](https://developers.google.com/maps/flutter-package/config#android_1).
+- Add the following to `android/build.gradle`:
+    ```gradle
+    buildscript {
+        dependencies {
+            classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1"
+        }
+    }
+    ```
+- Add the following to `android/app/build.gradle`:
+    ```gradle
+    plugins {
+        // ...
+        id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
+    }
+    ```
+- Add the credentials to `android/secrets.properties`:
+    ```properties
+    MAPS_API_KEY=YOUR_API_KEY
+    ```
+- Reference the credentials in `android/app/src/main/AndroidManifest.xml`:
+    ```xml
+    <meta-data
+        android:name="com.google.android.geo.API_KEY"
+        android:value="${MAPS_API_KEY}" />
+    ```
+
+
+### Using the credentials in CI
+- Add the base64 encoded credentials to the repository secrets (e.g. `ANDROID_SECRETS`).
+    ```bash
+    base64 -i android/secrets.properties
+    ```
+- Use the following in the CI script:
+    ```bash
+    echo {{ secrets.ANDROID_SECRETS }} | base64 -d > android/secrets.properties
+    ```
\ No newline at end of file
diff --git a/frontend/android/app/build.gradle b/frontend/android/app/build.gradle
index f6b499e..a2e13a5 100644
--- a/frontend/android/app/build.gradle
+++ b/frontend/android/app/build.gradle
@@ -2,10 +2,12 @@ plugins {
     id "com.android.application"
     id "kotlin-android"
     id "dev.flutter.flutter-gradle-plugin"
+    id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
+
 }
 
 def localProperties = new Properties()
-def localPropertiesFile = rootProject.file('local.properties')
+def localPropertiesFile = rootProject.file('secrets.properties')
 if (localPropertiesFile.exists()) {
     localPropertiesFile.withReader('UTF-8') { reader ->
         localProperties.load(reader)
@@ -52,6 +54,9 @@ android {
         targetSdkVersion flutter.targetSdkVersion
         versionCode flutterVersionCode.toInteger()
         versionName flutterVersionName
+        // Placeholders of keys that are replaced by the build system.
+        manifestPlaceholders += [MAPS_API_KEY: "some value"]
+
     }
 
     buildTypes {
diff --git a/frontend/android/app/src/main/AndroidManifest.xml b/frontend/android/app/src/main/AndroidManifest.xml
index b38e92b..b6c8a2a 100644
--- a/frontend/android/app/src/main/AndroidManifest.xml
+++ b/frontend/android/app/src/main/AndroidManifest.xml
@@ -32,7 +32,7 @@
         />
         <meta-data
             android:name="com.google.android.geo.API_KEY"
-            android:value="AIzaSyCeWk_D2xvfOHLidvV56EZeQCUybypEntw"
+            android:value="${MAPS_API_KEY}"
         />
 
 
diff --git a/frontend/android/build.gradle b/frontend/android/build.gradle
index bc157bd..98e49ef 100644
--- a/frontend/android/build.gradle
+++ b/frontend/android/build.gradle
@@ -16,3 +16,14 @@ subprojects {
 tasks.register("clean", Delete) {
     delete rootProject.buildDir
 }
+
+buildscript {
+    repositories {
+        google()
+        mavenCentral()
+    }
+
+    dependencies {
+        classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1"
+    }
+}
\ No newline at end of file
diff --git a/frontend/android/fallback.properties b/frontend/android/fallback.properties
new file mode 100644
index 0000000..f7ee9e9
--- /dev/null
+++ b/frontend/android/fallback.properties
@@ -0,0 +1 @@
+MAPS_API_KEY=Key
\ No newline at end of file
diff --git a/frontend/lib/modules/landmark_card.dart b/frontend/lib/modules/landmark_card.dart
index 8b42b7a..7caf76b 100644
--- a/frontend/lib/modules/landmark_card.dart
+++ b/frontend/lib/modules/landmark_card.dart
@@ -21,47 +21,47 @@ class _LandmarkCardState extends State<LandmarkCard> {
       ),
       child: Row(
         children: [
-          Container(
-            width: 160,
-            height: 160,
-            decoration: BoxDecoration(
-              borderRadius: BorderRadius.only(
-                topLeft: Radius.circular(15.0),
-                bottomLeft: Radius.circular(15.0),
-              ),
-              image: DecorationImage(
-                image: NetworkImage('https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/1037px-Tour_Eiffel_Wikimedia_Commons.jpg'),
-                fit: BoxFit.cover,
-              ),
-            ),
-          ),
+          // Container(
+          //   width: 160,
+          //   height: 160,
+          //   decoration: BoxDecoration(
+          //     borderRadius: BorderRadius.only(
+          //       topLeft: Radius.circular(15.0),
+          //       bottomLeft: Radius.circular(15.0),
+          //     ),
+          //     image: DecorationImage(
+          //       image: NetworkImage(widget.landmark.imageURL),
+          //       fit: BoxFit.cover,
+          //     ),
+          //   ),
+          // ),
           Padding(
             padding: EdgeInsets.all(10),
-            child: Expanded(
-              child: Column(
-                crossAxisAlignment: CrossAxisAlignment.start,
-                children: [
-                  Row(
-                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                    children: [
-                      Text(
-                        widget.landmark.name,
-                        style: TextStyle(
-                          fontSize: 18,
-                          fontWeight: FontWeight.bold,
-                        ),
+            
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                Row(
+                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                  children: [
+                    Text(
+                      widget.landmark.name,
+                      style: TextStyle(
+                        fontSize: 18,
+                        fontWeight: FontWeight.bold,
                       ),
-                    ],
-                  ),
-                  SizedBox(height: 5),
-                  Text(
-                    "${widget.landmark.name} (${widget.landmark.type.name})",
-                    style: TextStyle(fontSize: 14),
-                  ),
-                ],
-              ),
+                    ),
+                  ],
+                ),
+                SizedBox(height: 5),
+                Text(
+                  "${widget.landmark.name} (${widget.landmark.type.name})",
+                  style: TextStyle(fontSize: 14),
+                ),
+              ],
             ),
           ),
+
           // Align(
           //   alignment: Alignment.topRight,
           //   child: Icon(Icons.push_pin, color: theme.primaryColor),
diff --git a/frontend/lib/structs/landmark.dart b/frontend/lib/structs/landmark.dart
index 14d1b5b..1e9bf26 100644
--- a/frontend/lib/structs/landmark.dart
+++ b/frontend/lib/structs/landmark.dart
@@ -2,6 +2,7 @@ class Landmark {
   final String name;
   final List location;
   final LandmarkType type;
+  final String imageURL;
   // final String description;
   // final Duration duration;
   // final bool visited;
@@ -10,6 +11,7 @@ class Landmark {
     required this.name,
     required this.location,
     required this.type,
+    this.imageURL = 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/1037px-Tour_Eiffel_Wikimedia_Commons.jpg',
     // required this.description,
     // required this.duration,
     // required this.visited,
diff --git a/frontend/lib/utils/get_landmarks.dart b/frontend/lib/utils/get_landmarks.dart
index 5390849..53e7314 100644
--- a/frontend/lib/utils/get_landmarks.dart
+++ b/frontend/lib/utils/get_landmarks.dart
@@ -10,14 +10,39 @@ Future<List<Landmark>> fetchLandmarks() async {
     // If the server did return a 200 OK response,
     // then parse the JSON.
     List<Landmark> landmarks = [
-      Landmark(name: "Landmark 1", location: [48.85, 2.35], type: LandmarkType(name: "Type 1")),
-      Landmark(name: "Landmark 2", location: [48.86, 2.36], type: LandmarkType(name: "Type 2")),
-      Landmark(name: "Landmark 3", location: [48.75, 2.3], type: LandmarkType(name: "Type 3")),
-      Landmark(name: "Landmark 4", location: [48.9, 2.4], type: LandmarkType(name: "Type 4")),
-      Landmark(name: "Landmark 5", location: [48.91, 2.45], type: LandmarkType(name: "Type 5")),
+      // 48°51′29.6″N 2°17′40.2″E
+      Landmark(
+        name: "Eiffel Tower",
+        location: [48.51296, 2.17402],
+        type: LandmarkType(name: "Tower"),
+        imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/1037px-Tour_Eiffel_Wikimedia_Commons.jpg"
+        ),
+      Landmark(
+        name: "Notre Dame Cathedral",
+        location: [48.8530, 2.3498],
+        type: LandmarkType(name: "Monument"),
+        imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Notre-Dame_de_Paris%2C_4_October_2017.jpg/440px-Notre-Dame_de_Paris%2C_4_October_2017.jpg"
+        ),
+      Landmark(
+        name: "Louvre palace",
+        location: [48.8606, 2.3376],
+        type: LandmarkType(name: "Museum"),
+        imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/66/Louvre_Museum_Wikimedia_Commons.jpg/540px-Louvre_Museum_Wikimedia_Commons.jpg"
+        ),
+      Landmark(
+        name: "Pont-des-arts",
+        location: [48.5130, 2.2015],
+        type: LandmarkType(name: "Bridge"),
+        imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Pont_des_Arts%2C_6e_Arrondissement%2C_Paris_%28HDR%29_20140320_1.jpg/560px-Pont_des_Arts%2C_6e_Arrondissement%2C_Paris_%28HDR%29_20140320_1.jpg"),
+      Landmark(
+        name: "Panthéon",
+        location: [48.5046, 2.2046],
+        type: LandmarkType(name: "Monument"),
+        imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Pantheon_of_Paris_007.JPG/1280px-Pantheon_of_Paris_007.JPG"
+        ),
     ];
     // sleep 10 seconds
-    await Future.delayed(Duration(seconds: 10));
+    await Future.delayed(Duration(seconds: 5));
     return landmarks;
   // } else {
   //   // If the server did not return a 200 OK response,