Compare commits
	
		
			1 Commits
		
	
	
		
			v0.0.24
			...
			8d1677d78b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8d1677d78b | 
| @@ -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 | ||||
|  | ||||
|        | ||||
|   | ||||
							
								
								
									
										1
									
								
								frontend/android/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								frontend/android/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -4,6 +4,7 @@ gradle-wrapper.jar | ||||
| /gradlew | ||||
| /gradlew.bat | ||||
| /local.properties | ||||
| /secrets.properties | ||||
| GeneratedPluginRegistrant.java | ||||
|  | ||||
| # Remember to never publicly share your keystore. | ||||
|   | ||||
							
								
								
									
										48
									
								
								frontend/android/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								frontend/android/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
|     ``` | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -32,7 +32,7 @@ | ||||
|         /> | ||||
|         <meta-data | ||||
|             android:name="com.google.android.geo.API_KEY" | ||||
|             android:value="AIzaSyCeWk_D2xvfOHLidvV56EZeQCUybypEntw" | ||||
|             android:value="${MAPS_API_KEY}" | ||||
|         /> | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -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" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								frontend/android/fallback.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								frontend/android/fallback.properties
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| MAPS_API_KEY=Key | ||||
| @@ -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), | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user