cleaner ci
Some checks failed
Build and push docker image / Build (pull_request) Failing after 2m10s
Build and release APK / Build APK (pull_request) Successful in 6m34s
Build web / Build Web (pull_request) Successful in 1m42s

This commit is contained in:
Remy Moll 2024-06-03 17:36:13 +02:00
parent d5e0b7d51a
commit 040e5c9f83
10 changed files with 148 additions and 50 deletions

View File

@ -42,20 +42,24 @@ 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
- name: Sanity check
run: |
ls
ls -lah android
working-directory: ./frontend
- 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

View File

@ -4,6 +4,7 @@ gradle-wrapper.jar
/gradlew
/gradlew.bat
/local.properties
/secrets.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.

View 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
```

View File

@ -2,14 +2,18 @@ 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)
}
} else {
throw new GradleException("Secrets file secrets.properties not found")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
@ -52,6 +56,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 {

View File

@ -1,4 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Required to fetch data from the internet. -->
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:label="fast_network_navigation"
android:name="${applicationName}"
@ -32,11 +35,10 @@
/>
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyCeWk_D2xvfOHLidvV56EZeQCUybypEntw"
android:value="${MAPS_API_KEY}"
/>
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility?hl=en and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
@ -48,7 +50,4 @@
<data android:mimeType="text/plain"/>
</intent>
</queries>
<!-- Required to fetch data from the internet. -->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -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"
}
}

View File

@ -0,0 +1 @@
MAPS_API_KEY=Key

View File

@ -30,38 +30,38 @@ class _LandmarkCardState extends State<LandmarkCard> {
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'),
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),

View File

@ -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,

View File

@ -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°5129.6N 2°1740.2E
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,