Compare commits
	
		
			1 Commits
		
	
	
		
			v0.0.25
			...
			8d1677d78b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8d1677d78b | 
| @@ -42,20 +42,20 @@ jobs: | |||||||
|     - run: flutter pub get |     - run: flutter pub get | ||||||
|       working-directory: ./frontend |       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 |       working-directory: ./frontend | ||||||
|  |  | ||||||
|     - name: Release APK |     - run: flutter build apk --release --split-per-abi --build-number=${{ gitea.run_number }} | ||||||
|       uses: https://gitea.com/akkuman/gitea-release-action@v1 |       working-directory: ./frontend | ||||||
|       with: |  | ||||||
|         files: ./frontend/build/app/outputs/flutter-apk/*.apk |     - name: Upload APKs to artifacts | ||||||
|         name: Testing release |       uses: https://gitea.com/actions/upload-artifact@v3 | ||||||
|         release_name: testing |       with: | ||||||
|         tag: testing |         name: app-release | ||||||
|         tag_name: testing |         path: frontend/build/app/outputs/flutter-apk/ | ||||||
|         release_body: "This is a testing release." |         if-no-files-found: error | ||||||
|         prerelease: true |         retention-days: 15 | ||||||
|         token: ${{ secrets.GITEA_TOKEN }} |  | ||||||
|       env: |  | ||||||
|         NODE_OPTIONS: '--experimental-fetch' |  | ||||||
|        |        | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								frontend/android/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								frontend/android/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -4,6 +4,7 @@ gradle-wrapper.jar | |||||||
| /gradlew | /gradlew | ||||||
| /gradlew.bat | /gradlew.bat | ||||||
| /local.properties | /local.properties | ||||||
|  | /secrets.properties | ||||||
| GeneratedPluginRegistrant.java | GeneratedPluginRegistrant.java | ||||||
|  |  | ||||||
| # Remember to never publicly share your keystore. | # 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 "com.android.application" | ||||||
|     id "kotlin-android" |     id "kotlin-android" | ||||||
|     id "dev.flutter.flutter-gradle-plugin" |     id "dev.flutter.flutter-gradle-plugin" | ||||||
|  |     id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| def localProperties = new Properties() | def localProperties = new Properties() | ||||||
| def localPropertiesFile = rootProject.file('local.properties') | def localPropertiesFile = rootProject.file('secrets.properties') | ||||||
| if (localPropertiesFile.exists()) { | if (localPropertiesFile.exists()) { | ||||||
|     localPropertiesFile.withReader('UTF-8') { reader -> |     localPropertiesFile.withReader('UTF-8') { reader -> | ||||||
|         localProperties.load(reader) |         localProperties.load(reader) | ||||||
| @@ -52,6 +54,9 @@ android { | |||||||
|         targetSdkVersion flutter.targetSdkVersion |         targetSdkVersion flutter.targetSdkVersion | ||||||
|         versionCode flutterVersionCode.toInteger() |         versionCode flutterVersionCode.toInteger() | ||||||
|         versionName flutterVersionName |         versionName flutterVersionName | ||||||
|  |         // Placeholders of keys that are replaced by the build system. | ||||||
|  |         manifestPlaceholders += [MAPS_API_KEY: "some value"] | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     buildTypes { |     buildTypes { | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ | |||||||
|         /> |         /> | ||||||
|         <meta-data |         <meta-data | ||||||
|             android:name="com.google.android.geo.API_KEY" |             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) { | tasks.register("clean", Delete) { | ||||||
|     delete rootProject.buildDir |     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( |       child: Row( | ||||||
|         children: [ |         children: [ | ||||||
|           Container( |           // Container( | ||||||
|             width: 160, |           //   width: 160, | ||||||
|             height: 160, |           //   height: 160, | ||||||
|             decoration: BoxDecoration( |           //   decoration: BoxDecoration( | ||||||
|               borderRadius: BorderRadius.only( |           //     borderRadius: BorderRadius.only( | ||||||
|                 topLeft: Radius.circular(15.0), |           //       topLeft: Radius.circular(15.0), | ||||||
|                 bottomLeft: Radius.circular(15.0), |           //       bottomLeft: Radius.circular(15.0), | ||||||
|               ), |           //     ), | ||||||
|               image: DecorationImage( |           //     image: DecorationImage( | ||||||
|                 image: NetworkImage('https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/1037px-Tour_Eiffel_Wikimedia_Commons.jpg'), |           //       image: NetworkImage(widget.landmark.imageURL), | ||||||
|                 fit: BoxFit.cover, |           //       fit: BoxFit.cover, | ||||||
|               ), |           //     ), | ||||||
|             ), |           //   ), | ||||||
|           ), |           // ), | ||||||
|           Padding( |           Padding( | ||||||
|             padding: EdgeInsets.all(10), |             padding: EdgeInsets.all(10), | ||||||
|             child: Expanded( |              | ||||||
|               child: Column( |             child: Column( | ||||||
|                 crossAxisAlignment: CrossAxisAlignment.start, |               crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                 children: [ |               children: [ | ||||||
|                   Row( |                 Row( | ||||||
|                     mainAxisAlignment: MainAxisAlignment.spaceBetween, |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|                     children: [ |                   children: [ | ||||||
|                       Text( |                     Text( | ||||||
|                         widget.landmark.name, |                       widget.landmark.name, | ||||||
|                         style: TextStyle( |                       style: TextStyle( | ||||||
|                           fontSize: 18, |                         fontSize: 18, | ||||||
|                           fontWeight: FontWeight.bold, |                         fontWeight: FontWeight.bold, | ||||||
|                         ), |  | ||||||
|                       ), |                       ), | ||||||
|                     ], |                     ), | ||||||
|                   ), |                   ], | ||||||
|                   SizedBox(height: 5), |                 ), | ||||||
|                   Text( |                 SizedBox(height: 5), | ||||||
|                     "${widget.landmark.name} (${widget.landmark.type.name})", |                 Text( | ||||||
|                     style: TextStyle(fontSize: 14), |                   "${widget.landmark.name} (${widget.landmark.type.name})", | ||||||
|                   ), |                   style: TextStyle(fontSize: 14), | ||||||
|                 ], |                 ), | ||||||
|               ), |               ], | ||||||
|             ), |             ), | ||||||
|           ), |           ), | ||||||
|  |  | ||||||
|           // Align( |           // Align( | ||||||
|           //   alignment: Alignment.topRight, |           //   alignment: Alignment.topRight, | ||||||
|           //   child: Icon(Icons.push_pin, color: theme.primaryColor), |           //   child: Icon(Icons.push_pin, color: theme.primaryColor), | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ class Landmark { | |||||||
|   final String name; |   final String name; | ||||||
|   final List location; |   final List location; | ||||||
|   final LandmarkType type; |   final LandmarkType type; | ||||||
|  |   final String imageURL; | ||||||
|   // final String description; |   // final String description; | ||||||
|   // final Duration duration; |   // final Duration duration; | ||||||
|   // final bool visited; |   // final bool visited; | ||||||
| @@ -10,6 +11,7 @@ class Landmark { | |||||||
|     required this.name, |     required this.name, | ||||||
|     required this.location, |     required this.location, | ||||||
|     required this.type, |     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.description, | ||||||
|     // required this.duration, |     // required this.duration, | ||||||
|     // required this.visited, |     // required this.visited, | ||||||
|   | |||||||
| @@ -10,14 +10,39 @@ Future<List<Landmark>> fetchLandmarks() async { | |||||||
|     // If the server did return a 200 OK response, |     // If the server did return a 200 OK response, | ||||||
|     // then parse the JSON. |     // then parse the JSON. | ||||||
|     List<Landmark> landmarks = [ |     List<Landmark> landmarks = [ | ||||||
|       Landmark(name: "Landmark 1", location: [48.85, 2.35], type: LandmarkType(name: "Type 1")), |       // 48°51′29.6″N 2°17′40.2″E | ||||||
|       Landmark(name: "Landmark 2", location: [48.86, 2.36], type: LandmarkType(name: "Type 2")), |       Landmark( | ||||||
|       Landmark(name: "Landmark 3", location: [48.75, 2.3], type: LandmarkType(name: "Type 3")), |         name: "Eiffel Tower", | ||||||
|       Landmark(name: "Landmark 4", location: [48.9, 2.4], type: LandmarkType(name: "Type 4")), |         location: [48.51296, 2.17402], | ||||||
|       Landmark(name: "Landmark 5", location: [48.91, 2.45], type: LandmarkType(name: "Type 5")), |         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 |     // sleep 10 seconds | ||||||
|     await Future.delayed(Duration(seconds: 10)); |     await Future.delayed(Duration(seconds: 5)); | ||||||
|     return landmarks; |     return landmarks; | ||||||
|   // } else { |   // } else { | ||||||
|   //   // If the server did not return a 200 OK response, |   //   // If the server did not return a 200 OK response, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user