Make nightly builds a separate app
This allows users to have nightly builds alongside the production builds
8
.github/workflows/main.yaml
vendored
@ -51,7 +51,7 @@ jobs:
|
||||
echo "MELONDS_KEY_ALIAS=melonds" >> local.properties
|
||||
echo "MELONDS_KEY_PASSWORD=$MELONDS_KEYSTORE_PASSWORD" >> local.properties
|
||||
chmod +x ./gradlew
|
||||
./gradlew :app:assembleGitHubRelease
|
||||
./gradlew :app:assembleGitHubNightlyRelease
|
||||
git tag -m "Nightly Release" -f -a nightly-release
|
||||
git push -f origin refs/tags/nightly-release
|
||||
|
||||
@ -64,12 +64,12 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: nightly-release
|
||||
name: 'Nightly Build'
|
||||
body: 'The currently Nightly Build. Whenever new changes are pushed, you can find the latest build here.'
|
||||
artifacts: app/build/outputs/apk/gitHub/release/app-gitHub-release.apk
|
||||
body: 'The currently Nightly Build. Whenever new changes are pushed, you can find the latest build here. You can keep this installation alongside your main one.'
|
||||
artifacts: app/build/outputs/apk/gitHubNightly/release/app-gitHub-nightly-release.apk
|
||||
artifactContentType: application/vnd.android.package-archive
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: melonDS-android
|
||||
path: app/build/outputs/apk/gitHub/release/app-gitHub-release.apk
|
||||
path: app/build/outputs/apk/gitHubNightly/release/app-gitHub-nightly-release.apk
|
||||
|
14
.github/workflows/release-playstore.yaml
vendored
@ -35,7 +35,7 @@ jobs:
|
||||
echo "MELONDS_KEY_ALIAS=melonds-playstore" >> local.properties
|
||||
echo "MELONDS_KEY_PASSWORD=$MELONDS_KEY_PASSWORD" >> local.properties
|
||||
chmod +x ./gradlew
|
||||
./gradlew :app:assemblePlayStoreRelease
|
||||
./gradlew :app:assemblePlayStoreProdRelease
|
||||
|
||||
- name: Get Version
|
||||
id: release_params
|
||||
@ -47,19 +47,19 @@ jobs:
|
||||
serviceAccountJsonPlainText: ${{ secrets.MELONDS_PLAYSTORE_ACCOUNT_JSON }}
|
||||
packageName: me.magnum.melonds
|
||||
releaseName: ${{ steps.release_params.outputs.VERSION }}
|
||||
releaseFiles: app/build/outputs/apk/playStore/release/app-playStore-release.apk
|
||||
releaseFiles: app/build/outputs/apk/playStoreProd/release/app-playStore-prod-release.apk
|
||||
track: beta
|
||||
inAppUpdatePriority: 2
|
||||
status: draft
|
||||
whatsNewDirectory: ./.github/changelog/playStore
|
||||
mappingFile: app/build/outputs/mapping/playStoreRelease/mapping.txt
|
||||
debugSymbols: app/build/outputs/native-debug-symbols/playStoreRelease/native-debug-symbols.zip
|
||||
mappingFile: app/build/outputs/mapping/playStoreProdRelease/mapping.txt
|
||||
debugSymbols: app/build/outputs/native-debug-symbols/playStoreProdRelease/native-debug-symbols.zip
|
||||
|
||||
- name: Upload APK, Mapping and Debug Symbols
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: playstore-release
|
||||
path: |
|
||||
app/build/outputs/apk/playStore/release/app-playStore-release.apk
|
||||
app/build/outputs/mapping/playStoreRelease/mapping.txt
|
||||
app/build/outputs/native-debug-symbols/playStoreRelease/native-debug-symbols.zip
|
||||
app/build/outputs/apk/playStoreProd/release/app-playStore-prod-release.apk
|
||||
app/build/outputs/mapping/playStoreProdRelease/mapping.txt
|
||||
app/build/outputs/native-debug-symbols/playStoreProdRelease/native-debug-symbols.zip
|
24
.github/workflows/release.yaml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
echo "MELONDS_KEY_ALIAS=melonds" >> local.properties
|
||||
echo "MELONDS_KEY_PASSWORD=$MELONDS_KEYSTORE_PASSWORD" >> local.properties
|
||||
chmod +x ./gradlew
|
||||
./gradlew :app:assembleGitHubRelease
|
||||
./gradlew :app:assembleGitHubProdRelease
|
||||
|
||||
- name: Get Tag and Version
|
||||
id: release_params
|
||||
@ -52,7 +52,7 @@ jobs:
|
||||
tag: ${{ steps.release_params.outputs.TAG }}
|
||||
name: ${{ steps.release_params.outputs.VERSION }}
|
||||
bodyFile: ./.github/changelog/gitHub.md
|
||||
artifacts: app/build/outputs/apk/gitHub/release/app-gitHub-release.apk
|
||||
artifacts: app/build/outputs/apk/gitHubProd/release/app-gitHub-prod-release.apk
|
||||
artifactContentType: application/vnd.android.package-archive
|
||||
|
||||
- name: Upload APK, Mapping and Debug Symbols
|
||||
@ -60,9 +60,9 @@ jobs:
|
||||
with:
|
||||
name: github-release
|
||||
path: |
|
||||
app/build/outputs/apk/gitHub/release/app-gitHub-release.apk
|
||||
app/build/outputs/mapping/gitHubRelease/mapping.txt
|
||||
app/build/outputs/native-debug-symbols/gitHubRelease/native-debug-symbols.zip
|
||||
app/build/outputs/apk/gitHubProd/release/app-gitHub-prod-release.apk
|
||||
app/build/outputs/mapping/gitHubProdRelease/mapping.txt
|
||||
app/build/outputs/native-debug-symbols/gitHubProdRelease/native-debug-symbols.zip
|
||||
|
||||
playstore-release:
|
||||
runs-on: ubuntu-latest
|
||||
@ -93,7 +93,7 @@ jobs:
|
||||
echo "MELONDS_KEY_ALIAS=melonds-playstore" >> local.properties
|
||||
echo "MELONDS_KEY_PASSWORD=$MELONDS_KEY_PASSWORD" >> local.properties
|
||||
chmod +x ./gradlew
|
||||
./gradlew :app:assemblePlayStoreRelease
|
||||
./gradlew :app:assemblePlayStoreProdRelease
|
||||
|
||||
- name: Get Version
|
||||
id: release_params
|
||||
@ -105,19 +105,19 @@ jobs:
|
||||
serviceAccountJsonPlainText: ${{ secrets.MELONDS_PLAYSTORE_ACCOUNT_JSON }}
|
||||
packageName: me.magnum.melonds
|
||||
releaseName: ${{ steps.release_params.outputs.VERSION }}
|
||||
releaseFiles: app/build/outputs/apk/playStore/release/app-playStore-release.apk
|
||||
releaseFiles: app/build/outputs/apk/playStoreProd/release/app-playStore-prod-release.apk
|
||||
track: beta
|
||||
inAppUpdatePriority: 2
|
||||
status: draft
|
||||
whatsNewDirectory: ./.github/changelog/playStore
|
||||
mappingFile: app/build/outputs/mapping/playStoreRelease/mapping.txt
|
||||
debugSymbols: app/build/outputs/native-debug-symbols/playStoreRelease/native-debug-symbols.zip
|
||||
mappingFile: app/build/outputs/mapping/playStoreProdRelease/mapping.txt
|
||||
debugSymbols: app/build/outputs/native-debug-symbols/playStoreProdRelease/native-debug-symbols.zip
|
||||
|
||||
- name: Upload APK, Mapping and Debug Symbols
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: playstore-release
|
||||
path: |
|
||||
app/build/outputs/apk/playStore/release/app-playStore-release.apk
|
||||
app/build/outputs/mapping/playStoreRelease/mapping.txt
|
||||
app/build/outputs/native-debug-symbols/playStoreRelease/native-debug-symbols.zip
|
||||
app/build/outputs/apk/playStoreProd/release/app-playStore-prod-release.apk
|
||||
app/build/outputs/mapping/playStoreProdRelease/mapping.txt
|
||||
app/build/outputs/native-debug-symbols/playStoreProdRelease/native-debug-symbols.zip
|
12
README.md
@ -27,6 +27,12 @@ third-party frontend with the following configuration:
|
||||
* `uri` (preferred) - a string with the [SAF](https://developer.android.com/guide/topics/providers/create-document-provider) URI of the NDS ROM (ZIP files are supported)
|
||||
* `PATH` - a string with the absolute path to the NDS ROM (ZIP files are supported)
|
||||
|
||||
# Nightly Builds
|
||||
|
||||
To have access to the latest changes, you can install nightly builds that you can find [here](https://github.com/rafaelvcaetano/melonDS-android/releases/tag/nightly-release).
|
||||
|
||||
Be aware that these builds can contain more bugs than usual and you may need to clear your app data to get it to work properly.
|
||||
|
||||
# Building
|
||||
To build the project you will need Android SDK, NDK and CMake.
|
||||
|
||||
@ -36,9 +42,9 @@ To build the project you will need Android SDK, NDK and CMake.
|
||||
`git clone --recurse-submodules https://github.com/rafaelvcaetano/melonDS-android.git`
|
||||
2. Install the Android SDK, NDK and CMake
|
||||
3. Build with:
|
||||
1. Unix: `./gradlew :app:assembleGitHubDebug`
|
||||
2. Windows: `gradlew.bat :app:assembleGitHubDebug`
|
||||
4. The generated APK can be found at `app/gitHub/debug`
|
||||
1. Unix: `./gradlew :app:assembleGitHubProdDebug`
|
||||
2. Windows: `gradlew.bat :app:assembleGitHubProdDebug`
|
||||
4. The generated APK can be found at `app/gitHubProd/debug`
|
||||
|
||||
If you want to create a release build, you will need to modify your `local.properties` file to include the following fields:
|
||||
* `MELONDS_KEYSTORE=<path_to_your_keystore>`
|
||||
|
@ -63,6 +63,7 @@ android {
|
||||
}
|
||||
|
||||
flavorDimensions.add("version")
|
||||
flavorDimensions.add("build")
|
||||
productFlavors {
|
||||
create("playStore") {
|
||||
dimension = "version"
|
||||
@ -70,8 +71,19 @@ android {
|
||||
}
|
||||
create("gitHub") {
|
||||
dimension = "version"
|
||||
isDefault = true
|
||||
versionNameSuffix = " GH"
|
||||
}
|
||||
|
||||
create("prod") {
|
||||
dimension = "build"
|
||||
isDefault = true
|
||||
}
|
||||
create("nightly") {
|
||||
dimension = "build"
|
||||
applicationIdSuffix = ".nightly"
|
||||
versionNameSuffix = " (NIGHTLY)"
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
|
@ -7,10 +7,8 @@ import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import me.magnum.melonds.domain.repositories.UpdatesRepository
|
||||
import me.magnum.melonds.domain.services.UpdateInstallManager
|
||||
import me.magnum.melonds.github.GitHubApi
|
||||
import me.magnum.melonds.github.repositories.GitHubUpdatesRepository
|
||||
import me.magnum.melonds.github.services.GitHubUpdateInstallManager
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
|
||||
@ -32,13 +30,6 @@ object GitHubModule {
|
||||
return retrofit.create(GitHubApi::class.java)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUpdatesRepository(@ApplicationContext context: Context, gitHubApi: GitHubApi): UpdatesRepository {
|
||||
val gitHubPreferences = context.getSharedPreferences("preferences-github", Context.MODE_PRIVATE)
|
||||
return GitHubUpdatesRepository(context, gitHubApi, gitHubPreferences)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUpdateInstallManager(@ApplicationContext context: Context): UpdateInstallManager {
|
||||
|
@ -7,4 +7,7 @@ import retrofit2.http.GET
|
||||
interface GitHubApi {
|
||||
@GET("/repos/rafaelvcaetano/melonDS-android/releases/latest")
|
||||
fun getLatestRelease(): Single<ReleaseDto>
|
||||
|
||||
@GET("/repos/rafaelvcaetano/melonDS-android/releases/tags/nightly-release")
|
||||
fun getLatestNightlyRelease(): Single<ReleaseDto>
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package me.magnum.melonds.github
|
||||
|
||||
const val APK_CONTENT_TYPE = "application/vnd.android.package-archive"
|
||||
|
||||
const val PREF_KEY_GITHUB_CHECK_FOR_UPDATES = "github_check_for_updates"
|
@ -6,5 +6,6 @@ data class ReleaseDto(
|
||||
@SerializedName("tag_name") val tagName: String,
|
||||
@SerializedName("name") val name: String,
|
||||
@SerializedName("body") val body: String,
|
||||
@SerializedName("created_at") val createdAt: String,
|
||||
@SerializedName("assets") val assets: List<AssetDto>
|
||||
)
|
@ -10,7 +10,7 @@ import android.net.Uri
|
||||
import androidx.core.content.getSystemService
|
||||
import io.reactivex.Observable
|
||||
import me.magnum.melonds.common.providers.UpdateContentProvider
|
||||
import me.magnum.melonds.domain.model.AppUpdate
|
||||
import me.magnum.melonds.domain.model.appupdate.AppUpdate
|
||||
import me.magnum.melonds.domain.model.DownloadProgress
|
||||
import me.magnum.melonds.domain.services.UpdateInstallManager
|
||||
import java.io.File
|
||||
|
12
app/src/gitHub/res/xml/pref_general_updates.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<SwitchPreference
|
||||
android:key="github_check_for_updates"
|
||||
android:title="@string/check_for_updates"
|
||||
android:summary="@string/check_for_updates_summary"
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="true" />
|
||||
</PreferenceScreen>
|
@ -0,0 +1,24 @@
|
||||
package me.magnum.melonds.di
|
||||
|
||||
import android.content.Context
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import me.magnum.melonds.domain.repositories.UpdatesRepository
|
||||
import me.magnum.melonds.github.GitHubApi
|
||||
import me.magnum.melonds.github.repositories.GitHubNightlyUpdatesRepository
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object GitHubNightlyModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUpdatesRepository(@ApplicationContext context: Context, gitHubApi: GitHubApi): UpdatesRepository {
|
||||
val gitHubPreferences = context.getSharedPreferences("preferences-github", Context.MODE_PRIVATE)
|
||||
return GitHubNightlyUpdatesRepository(gitHubApi, gitHubPreferences)
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
package me.magnum.melonds.github.repositories
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.net.toUri
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import me.magnum.melonds.domain.model.Version
|
||||
import me.magnum.melonds.domain.model.appupdate.AppUpdate
|
||||
import me.magnum.melonds.domain.repositories.UpdatesRepository
|
||||
import me.magnum.melonds.github.APK_CONTENT_TYPE
|
||||
import me.magnum.melonds.github.GitHubApi
|
||||
import me.magnum.melonds.github.PREF_KEY_GITHUB_CHECK_FOR_UPDATES
|
||||
import me.magnum.melonds.github.dtos.ReleaseDto
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
|
||||
class GitHubNightlyUpdatesRepository(private val api: GitHubApi, private val preferences: SharedPreferences) : UpdatesRepository {
|
||||
companion object {
|
||||
private const val KEY_NEXT_CHECK_DATE = "github_updates_nightly_next_check_date"
|
||||
private const val KEY_LAST_RELEASE_DATE = "github_updates_nightly_last_release_date"
|
||||
}
|
||||
|
||||
override fun checkNewUpdate(): Maybe<AppUpdate> {
|
||||
return shouldCheckUpdates()
|
||||
.flatMapMaybe { checkUpdates ->
|
||||
if (checkUpdates) {
|
||||
api.getLatestNightlyRelease().flatMapMaybe { release ->
|
||||
if (shouldUpdate(release)) {
|
||||
val apkBinary = release.assets.firstOrNull { it.contentType == APK_CONTENT_TYPE }
|
||||
if (apkBinary != null) {
|
||||
val update = AppUpdate(
|
||||
AppUpdate.Type.NIGHTLY,
|
||||
apkBinary.id,
|
||||
apkBinary.url.toUri(),
|
||||
Version.fromString(release.tagName),
|
||||
release.body,
|
||||
apkBinary.size,
|
||||
Instant.parse(release.createdAt),
|
||||
)
|
||||
Maybe.just(update)
|
||||
} else {
|
||||
Maybe.empty()
|
||||
}
|
||||
} else {
|
||||
Maybe.empty()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Maybe.empty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun skipUpdate(update: AppUpdate) {
|
||||
scheduleNextUpdate()
|
||||
}
|
||||
|
||||
override fun notifyUpdateDownloaded(update: AppUpdate) {
|
||||
// This doesn't mean that the user has actually installed the update, but we have no way to determine that. As such, just assume that the update will be installed and
|
||||
// store the date of the update
|
||||
preferences.edit {
|
||||
putLong(KEY_LAST_RELEASE_DATE, update.updateDate.toEpochMilli())
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldCheckUpdates(): Single<Boolean> {
|
||||
return Single.create { emitter ->
|
||||
val updateCheckEnabled = preferences.getBoolean(PREF_KEY_GITHUB_CHECK_FOR_UPDATES, true)
|
||||
if (!updateCheckEnabled) {
|
||||
emitter.onSuccess(false)
|
||||
return@create
|
||||
}
|
||||
|
||||
val nextUpdateCheckTime = preferences.getLong(KEY_NEXT_CHECK_DATE, -1)
|
||||
if (nextUpdateCheckTime == (-1).toLong()) {
|
||||
emitter.onSuccess(true)
|
||||
return@create
|
||||
}
|
||||
|
||||
val now = Instant.now()
|
||||
val shouldCheckUpdates = now.toEpochMilli() > nextUpdateCheckTime
|
||||
|
||||
emitter.onSuccess(shouldCheckUpdates)
|
||||
}
|
||||
}
|
||||
|
||||
private fun scheduleNextUpdate() {
|
||||
val now = Instant.now()
|
||||
val nextUpdateDate = now + Duration.ofDays(1)
|
||||
|
||||
preferences.edit {
|
||||
putLong(KEY_NEXT_CHECK_DATE, nextUpdateDate.toEpochMilli())
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldUpdate(releaseDto: ReleaseDto): Boolean {
|
||||
val lastReleaseDate = preferences.getLong(KEY_LAST_RELEASE_DATE, -1)
|
||||
if (lastReleaseDate == -1L) {
|
||||
// If there is no last release date, then it's the first time the user is running the app and checking for updates. Ignore this release since we can't check if
|
||||
// it's actually different from the one the user has installed, and save the release date in the preferences so that we can have a future reference
|
||||
|
||||
val releaseDate = Instant.parse(releaseDto.createdAt)
|
||||
preferences.edit {
|
||||
putLong(KEY_LAST_RELEASE_DATE, releaseDate.toEpochMilli())
|
||||
}
|
||||
scheduleNextUpdate()
|
||||
return false
|
||||
}
|
||||
|
||||
val thisReleaseDate = Instant.parse(releaseDto.createdAt)
|
||||
|
||||
return thisReleaseDate.toEpochMilli() > lastReleaseDate
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package me.magnum.melonds.di
|
||||
|
||||
import android.content.Context
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import me.magnum.melonds.domain.repositories.UpdatesRepository
|
||||
import me.magnum.melonds.github.GitHubApi
|
||||
import me.magnum.melonds.github.repositories.GitHubProdUpdatesRepository
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object GitHubProdModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUpdatesRepository(@ApplicationContext context: Context, gitHubApi: GitHubApi): UpdatesRepository {
|
||||
val gitHubPreferences = context.getSharedPreferences("preferences-github", Context.MODE_PRIVATE)
|
||||
return GitHubProdUpdatesRepository(context, gitHubApi, gitHubPreferences)
|
||||
}
|
||||
}
|
@ -6,17 +6,19 @@ import androidx.core.content.edit
|
||||
import androidx.core.net.toUri
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import me.magnum.melonds.domain.model.AppUpdate
|
||||
import me.magnum.melonds.domain.model.appupdate.AppUpdate
|
||||
import me.magnum.melonds.domain.model.Version
|
||||
import me.magnum.melonds.domain.repositories.UpdatesRepository
|
||||
import me.magnum.melonds.github.GitHubApi
|
||||
import me.magnum.melonds.github.PREF_KEY_GITHUB_CHECK_FOR_UPDATES
|
||||
import me.magnum.melonds.github.dtos.ReleaseDto
|
||||
import me.magnum.melonds.utils.PackageManagerCompat
|
||||
import me.magnum.melonds.utils.enumValueOfIgnoreCase
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class GitHubUpdatesRepository(private val context: Context, private val api: GitHubApi, private val preferences: SharedPreferences) : UpdatesRepository {
|
||||
class GitHubProdUpdatesRepository(private val context: Context, private val api: GitHubApi, private val preferences: SharedPreferences) : UpdatesRepository {
|
||||
companion object {
|
||||
private const val APK_CONTENT_TYPE = "application/vnd.android.package-archive"
|
||||
private const val KEY_SKIP_VERSION = "github_updates_skip_version"
|
||||
@ -35,11 +37,13 @@ class GitHubUpdatesRepository(private val context: Context, private val api: Git
|
||||
val apkBinary = release.assets.firstOrNull { it.contentType == APK_CONTENT_TYPE }
|
||||
if (apkBinary != null) {
|
||||
val update = AppUpdate(
|
||||
AppUpdate.Type.PRODUCTION,
|
||||
apkBinary.id,
|
||||
apkBinary.url.toUri(),
|
||||
Version.fromString(release.tagName),
|
||||
release.body,
|
||||
apkBinary.size
|
||||
apkBinary.size,
|
||||
Instant.parse(release.createdAt),
|
||||
)
|
||||
Maybe.just(update)
|
||||
} else {
|
||||
@ -61,8 +65,18 @@ class GitHubUpdatesRepository(private val context: Context, private val api: Git
|
||||
}
|
||||
}
|
||||
|
||||
override fun notifyUpdateDownloaded(update: AppUpdate) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
private fun shouldCheckUpdates(): Single<Boolean> {
|
||||
return Single.create { emitter ->
|
||||
val updateCheckEnabled = preferences.getBoolean(PREF_KEY_GITHUB_CHECK_FOR_UPDATES, true)
|
||||
if (!updateCheckEnabled) {
|
||||
emitter.onSuccess(false)
|
||||
return@create
|
||||
}
|
||||
|
||||
val lastCheckUpdateTimestamp = preferences.getLong(KEY_LAST_UPDATE_CHECK, -1)
|
||||
if (lastCheckUpdateTimestamp == (-1).toLong()) {
|
||||
emitter.onSuccess(true)
|
@ -1,11 +0,0 @@
|
||||
package me.magnum.melonds.domain.model
|
||||
|
||||
import android.net.Uri
|
||||
|
||||
data class AppUpdate(
|
||||
val id: Long,
|
||||
val downloadUri: Uri,
|
||||
val newVersion: Version,
|
||||
val description: String,
|
||||
val binarySize: Long
|
||||
)
|
@ -0,0 +1,21 @@
|
||||
package me.magnum.melonds.domain.model.appupdate
|
||||
|
||||
import android.net.Uri
|
||||
import me.magnum.melonds.domain.model.Version
|
||||
import java.time.Instant
|
||||
|
||||
data class AppUpdate(
|
||||
val type: Type,
|
||||
val id: Long,
|
||||
val downloadUri: Uri,
|
||||
val newVersion: Version,
|
||||
val description: String,
|
||||
val binarySize: Long,
|
||||
val updateDate: Instant,
|
||||
) {
|
||||
|
||||
enum class Type {
|
||||
PRODUCTION,
|
||||
NIGHTLY,
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package me.magnum.melonds.domain.repositories
|
||||
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Observable
|
||||
import me.magnum.melonds.domain.model.AppUpdate
|
||||
import me.magnum.melonds.domain.model.appupdate.AppUpdate
|
||||
|
||||
interface UpdatesRepository {
|
||||
fun checkNewUpdate(): Maybe<AppUpdate>
|
||||
fun skipUpdate(update: AppUpdate)
|
||||
fun notifyUpdateDownloaded(update: AppUpdate)
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package me.magnum.melonds.domain.services
|
||||
|
||||
import io.reactivex.Observable
|
||||
import me.magnum.melonds.domain.model.AppUpdate
|
||||
import me.magnum.melonds.domain.model.appupdate.AppUpdate
|
||||
import me.magnum.melonds.domain.model.DownloadProgress
|
||||
|
||||
interface UpdateInstallManager {
|
||||
|
@ -27,6 +27,7 @@ import me.magnum.melonds.common.Permission
|
||||
import me.magnum.melonds.common.contracts.DirectoryPickerContract
|
||||
import me.magnum.melonds.databinding.ActivityRomListBinding
|
||||
import me.magnum.melonds.domain.model.*
|
||||
import me.magnum.melonds.domain.model.appupdate.AppUpdate
|
||||
import me.magnum.melonds.ui.dsiwaremanager.DSiWareManagerActivity
|
||||
import me.magnum.melonds.ui.emulator.EmulatorActivity
|
||||
import me.magnum.melonds.ui.settings.SettingsActivity
|
||||
@ -98,7 +99,10 @@ class RomListActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
updatesViewModel.getAppUpdate().observe(this) {
|
||||
showUpdateAvailableDialog(it)
|
||||
when (it.type) {
|
||||
AppUpdate.Type.PRODUCTION -> showProdUpdateAvailableDialog(it)
|
||||
AppUpdate.Type.NIGHTLY -> showNightlyUpdateAvailableDialog(it)
|
||||
}
|
||||
}
|
||||
updatesViewModel.getDownloadProgress().observe(this) {
|
||||
onDownloadProgressUpdated(it)
|
||||
@ -199,7 +203,7 @@ class RomListActivity : AppCompatActivity() {
|
||||
romListFragment.setRomSelectedListener { rom -> loadRom(rom) }
|
||||
}
|
||||
|
||||
private fun showUpdateAvailableDialog(update: AppUpdate) {
|
||||
private fun showProdUpdateAvailableDialog(update: AppUpdate) {
|
||||
val message = markwon.toMarkdown(update.description)
|
||||
|
||||
AlertDialog.Builder(this)
|
||||
@ -215,6 +219,19 @@ class RomListActivity : AppCompatActivity() {
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun showNightlyUpdateAvailableDialog(update: AppUpdate) {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.nightly_update_available))
|
||||
.setMessage(getString(R.string.nightly_update_available_message))
|
||||
.setPositiveButton(R.string.update) { _, _ ->
|
||||
startUpdateDownload(update)
|
||||
}
|
||||
.setNegativeButton(R.string.remind_later_update) { _, _ ->
|
||||
updatesViewModel.skipUpdate(update)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun startUpdateDownload(update: AppUpdate) {
|
||||
downloadProgressDialog?.dismiss()
|
||||
downloadProgressDialog = AlertDialog.Builder(this)
|
||||
|
@ -5,7 +5,7 @@ import androidx.lifecycle.ViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import me.magnum.melonds.common.Schedulers
|
||||
import me.magnum.melonds.domain.model.AppUpdate
|
||||
import me.magnum.melonds.domain.model.appupdate.AppUpdate
|
||||
import me.magnum.melonds.domain.model.DownloadProgress
|
||||
import me.magnum.melonds.domain.repositories.UpdatesRepository
|
||||
import me.magnum.melonds.domain.services.UpdateInstallManager
|
||||
@ -47,6 +47,9 @@ class UpdatesViewModel @Inject constructor(
|
||||
.subscribeOn(schedulers.backgroundThreadScheduler)
|
||||
.subscribe {
|
||||
updateDownloadProgressLiveData.postValue(it)
|
||||
if (it is DownloadProgress.DownloadComplete) {
|
||||
updatesRepository.notifyUpdateDownloaded(update)
|
||||
}
|
||||
}
|
||||
.addTo(disposables)
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ class GeneralPreferencesFragment : PreferenceFragmentCompat(), PreferenceFragmen
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.pref_general, rootKey)
|
||||
addPreferencesFromResource(R.xml.pref_general_updates)
|
||||
|
||||
rewindPreference = findPreference("enable_rewind")!!
|
||||
val sustainedPerformancePreference = findPreference<SwitchPreference>("enable_sustained_performance")!!
|
||||
|
@ -49,7 +49,10 @@
|
||||
<string name="action_refresh_rom_list">Refresh ROM list</string>
|
||||
<string name="hint_search_roms">Search ROMs…</string>
|
||||
<string name="update_available">Update available: %1$s</string>
|
||||
<string name="nightly_update_available">Nightly update available</string>
|
||||
<string name="nightly_update_available_message">Do you want to download it now?</string>
|
||||
<string name="skip_update">Skip</string>
|
||||
<string name="remind_later_update">Later</string>
|
||||
<string name="downloading_update">Downloading update…</string>
|
||||
<string name="starting_download">Starting download…</string>
|
||||
<string name="download_progress_sizes">%1$.1fMB/%2$.1fMB</string>
|
||||
@ -148,6 +151,8 @@
|
||||
<string name="rewind_memory_usage_above_recommended_limit">Memory usage above recommended limit</string>
|
||||
<string name="sustained_performance_mode">Sustained performance mode</string>
|
||||
<string name="sustained_performance_mode_summary">When enabled, peak performance will be lower but thermal throttling will be less pronounced.</string>
|
||||
<string name="check_for_updates">Check for updates</string>
|
||||
<string name="check_for_updates_summary">When enabled, the app will periodically check for available updates</string>
|
||||
<string name="rom_icon_filtering">Icon filtering</string>
|
||||
<string name="max_rom_cache_size">Max. ROM cache size</string>
|
||||
<string name="clear_extracted_rom_cache">Clear extracted ROM cache</string>
|
||||
|
4
app/src/main/res/xml/pref_general_updates.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen>
|
||||
<!-- Empty on purpose since not all builds have update options -->
|
||||
</PreferenceScreen>
|
BIN
app/src/nightly/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
app/src/nightly/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
app/src/nightly/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/nightly/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
app/src/nightly/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
app/src/nightly/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
app/src/nightly/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
app/src/nightly/res/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
app/src/nightly/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
app/src/nightly/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 23 KiB |
4
app/src/nightly/res/values/strings.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">melonDS Nightly</string>
|
||||
</resources>
|
@ -1,7 +1,7 @@
|
||||
package me.magnum.melonds.playstore
|
||||
|
||||
import io.reactivex.Maybe
|
||||
import me.magnum.melonds.domain.model.AppUpdate
|
||||
import me.magnum.melonds.domain.model.appupdate.AppUpdate
|
||||
import me.magnum.melonds.domain.repositories.UpdatesRepository
|
||||
|
||||
class PlayStoreUpdatesRepository : UpdatesRepository {
|
||||
@ -12,4 +12,8 @@ class PlayStoreUpdatesRepository : UpdatesRepository {
|
||||
override fun skipUpdate(update: AppUpdate) {
|
||||
// Do nothing. Update checking not supported in the Play Store version
|
||||
}
|
||||
|
||||
override fun notifyUpdateDownloaded(update: AppUpdate) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package me.magnum.melonds.services
|
||||
|
||||
import io.reactivex.Observable
|
||||
import me.magnum.melonds.domain.model.AppUpdate
|
||||
import me.magnum.melonds.domain.model.DownloadProgress
|
||||
import me.magnum.melonds.domain.model.appupdate.AppUpdate
|
||||
import me.magnum.melonds.domain.services.UpdateInstallManager
|
||||
|
||||
class PlayStoreUpdateInstallManager : UpdateInstallManager {
|
||||
|