diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 59760470f..f78629c51 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -95,6 +95,20 @@ android { } } + flavorDimensions += "distribution" + productFlavors { + create("full") { + dimension = "distribution" + isDefault = true + } + create("foss") { + dimension = "distribution" + // Steam integration relies on the JavaSteam library, which is only available as a + // prebuilt binary (not on Maven Central). The FOSS flavor -- used for the F-Droid + // build -- ships without it; see app/src/foss for no-op Steam stubs. + } + } + compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 @@ -245,8 +259,9 @@ dependencies { implementation(libs.xz) implementation(libs.zstd.jni) { artifact { type = "aar" } } - // Steam (JavaSteam) - implementation(libs.bundles.steam) + // Steam (JavaSteam) -- prebuilt, non-Maven-Central; limited to the "full" flavor. + // The "foss" flavor builds without it (app/src/foss stubs) for F-Droid. + "fullImplementation"(libs.bundles.steam) // argosy-sigil — title id / serial extraction (replaces in-tree :libchdr + // Iso9660Utils + AesXts + ZArchiveReader + GameCubeHeaderParser.parseRomHeader) diff --git a/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamAuthManager.kt b/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamAuthManager.kt new file mode 100644 index 000000000..2cd6ffaae --- /dev/null +++ b/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamAuthManager.kt @@ -0,0 +1,36 @@ +package com.nendo.argosy.data.steam + +import com.nendo.argosy.data.local.entity.SteamAccountEntity +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject +import javax.inject.Singleton + +/** + * FOSS-flavor no-op stub. The `full` flavor implements Steam QR authentication via the + * JavaSteam library; the FOSS build ships without Steam, so this exposes the same public + * surface consumed by shared code while doing nothing. + */ +@Singleton +class SteamAuthManager @Inject constructor() { + val qrAuthState: StateFlow = MutableStateFlow(QrAuthState.Idle) + val authEvents: SharedFlow = MutableSharedFlow() + val isLoggedIn: StateFlow = MutableStateFlow(false) + + @Volatile + var sessionDead: Boolean = false + + var connectingForAuth: Boolean = false + + suspend fun getActiveAccount(): SteamAccountEntity? = null + + suspend fun deleteAccount(accountId: Long) {} + + fun startQrAuth() {} + + fun cancelQrAuth() {} + + fun logout() {} +} diff --git a/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamContentManager.kt b/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamContentManager.kt new file mode 100644 index 000000000..aa2ae8d4d --- /dev/null +++ b/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamContentManager.kt @@ -0,0 +1,40 @@ +package com.nendo.argosy.data.steam + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject +import javax.inject.Singleton + +/** + * FOSS-flavor no-op stub. The `full` flavor implements Steam library discovery and depot + * downloads via the JavaSteam library. The FOSS build ships without Steam, so downloads + * never start and queues stay empty; this exposes the same public surface consumed by + * shared code (download/queue state flows and control methods) as no-ops. + */ +@Singleton +class SteamContentManager @Inject constructor() { + val downloadState: StateFlow = MutableStateFlow(SteamDownloadState.Idle) + val activeDownload: StateFlow = MutableStateFlow(null) + val downloadQueue: StateFlow> = MutableStateFlow(emptyList()) + val completedDownloads: StateFlow> = MutableStateFlow(emptyList()) + + suspend fun hasPendingDownloads(): Boolean = false + + suspend fun discoverLocalSteamGames(): Int = 0 + + fun queueDownloadOptimistic(appId: Long, gameName: String, coverPath: String?) {} + + fun pauseDownload() {} + + fun cancelDownload() {} + + fun cancelQueuedDownload(appId: Long) {} + + fun clearCompletedDownloads() {} + + fun hasActiveSteamDownload(): Boolean = false + + fun onDownloadSlotFreed() {} + + fun cleanup() {} +} diff --git a/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamLibraryManager.kt b/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamLibraryManager.kt new file mode 100644 index 000000000..b219600c8 --- /dev/null +++ b/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamLibraryManager.kt @@ -0,0 +1,37 @@ +package com.nendo.argosy.data.steam + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject +import javax.inject.Singleton + +/** + * FOSS-flavor no-op stub. The `full` flavor syncs the user's Steam library via the JavaSteam + * library. The FOSS build ships without Steam, so sync is inert; this exposes the same public + * surface consumed by shared code (sync state flow and control methods) as no-ops. + */ +@Singleton +class SteamLibraryManager @Inject constructor() { + private val _syncState = MutableStateFlow(LibrarySyncState.Idle) + val syncState: StateFlow = _syncState + + fun forceSync() { + reportUnavailable() + } + + fun forceSyncWithOverwrite() { + reportUnavailable() + } + + suspend fun resetLibrary(): Int = 0 + + fun requestLibrarySync() { + reportUnavailable() + } + + fun cleanup() {} + + private fun reportUnavailable() { + _syncState.value = LibrarySyncState.Error("Steam is not available in this build") + } +} diff --git a/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamModels.kt b/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamModels.kt new file mode 100644 index 000000000..dcf20acbb --- /dev/null +++ b/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamModels.kt @@ -0,0 +1,94 @@ +package com.nendo.argosy.data.steam + +/** + * FOSS-flavor shared Steam value types. + * + * In the `full` flavor these types are declared inside the JavaSteam-backed manager + * implementations (see app/src/full/.../data/steam/). The `foss` flavor ships no Steam + * integration, but shared code in src/main still references and pattern-matches on these + * types, so identical definitions are provided here. Keep them in sync with the `full` + * declarations. `KeyValue` (a JavaSteam type) is replaced with `Any?` since no shared code + * reads that field. + */ + +enum class SteamConnectionState { + DISCONNECTED, + CONNECTING, + CONNECTED, + LOGGING_IN, + LOGGED_IN, + LOGGED_OUT +} + +data class SteamServiceState( + val connectionState: SteamConnectionState = SteamConnectionState.DISCONNECTED, + val username: String? = null, + val steamId: Long? = null, + val error: String? = null +) + +sealed class QrAuthState { + data object Idle : QrAuthState() + data object Starting : QrAuthState() + data class WaitingForScan(val challengeUrl: String) : QrAuthState() + data object Polling : QrAuthState() + data class Success(val username: String, val steamId: Long) : QrAuthState() + data class Error(val message: String) : QrAuthState() +} + +sealed class SteamAuthEvent { + data class LoggedIn(val steamId: Long, val username: String) : SteamAuthEvent() + data object LoggedOut : SteamAuthEvent() + data class LoginFailed(val reason: String) : SteamAuthEvent() +} + +sealed class SteamDownloadState { + data object Idle : SteamDownloadState() + data class Preparing(val appId: Long, val gameName: String) : SteamDownloadState() + data class Connecting(val appId: Long, val gameName: String) : SteamDownloadState() + data class FetchingManifest(val appId: Long, val gameName: String, val depotId: Int) : SteamDownloadState() + data class Validating(val appId: Long, val gameName: String, val statusDetail: String = "") : SteamDownloadState() + data class Downloading( + val appId: Long, + val gameName: String, + val progress: Float, + val currentDepot: Int, + val totalDepots: Int + ) : SteamDownloadState() + data class Moving(val appId: Long, val gameName: String) : SteamDownloadState() + data class Completed(val appId: Long, val gameName: String, val installPath: String) : SteamDownloadState() + data class Failed(val appId: Long, val gameName: String, val error: String) : SteamDownloadState() + data class Paused(val appId: Long, val gameName: String, val progress: Float, val needsVerification: Boolean = false) : SteamDownloadState() + data class Cleaning(val appId: Long, val gameName: String) : SteamDownloadState() +} + +data class SteamDownloadProgress( + val appId: Long, + val gameName: String, + val coverPath: String?, + val progress: Float, + val totalBytes: Long, + val bytesDownloaded: Long, + val state: SteamDownloadState, + val bytesPerSecond: Long = 0L +) { + val progressPercent: Int get() = (progress * 100).toInt() +} + +data class QueuedSteamDownload( + val appId: Long, + val gameName: String, + val coverPath: String?, + val appInfo: Any? = null, + val targetInstallPath: String? = null +) + +sealed class LibrarySyncState { + data object Idle : LibrarySyncState() + data object SyncingLicenses : LibrarySyncState() + data class FetchingPackages(val current: Int, val total: Int) : LibrarySyncState() + data class FetchingApps(val current: Int, val total: Int) : LibrarySyncState() + data class FetchingProtonDbRatings(val current: Int, val total: Int) : LibrarySyncState() + data class Complete(val gamesAdded: Int, val gamesUpdated: Int) : LibrarySyncState() + data class Error(val message: String) : LibrarySyncState() +} diff --git a/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamService.kt b/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamService.kt new file mode 100644 index 000000000..6017d6690 --- /dev/null +++ b/app/src/foss/kotlin/com/nendo/argosy/data/steam/SteamService.kt @@ -0,0 +1,40 @@ +package com.nendo.argosy.data.steam + +import android.app.Service +import android.content.Intent +import android.os.Binder +import android.os.IBinder +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +/** + * FOSS-flavor no-op stub. The `full` flavor runs a foreground Service that maintains the + * Steam client connection via the JavaSteam library. The FOSS build ships without Steam, so + * this Service does nothing: it never connects and stops itself immediately if started. It + * keeps the same public surface (state flow, disconnect, LocalBinder, extras) so shared code + * and the manifest entry continue to compile and bind. + */ +class SteamService : Service() { + val state: StateFlow = MutableStateFlow(SteamServiceState()) + + private val binder = LocalBinder() + + inner class LocalBinder : Binder() { + fun getService(): SteamService = this@SteamService + } + + override fun onBind(intent: Intent?): IBinder = binder + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + stopSelf() + return START_NOT_STICKY + } + + fun disconnect() {} + + companion object { + const val EXTRA_AUTO_CONNECT = "auto_connect" + const val EXTRA_FORCE_CONNECT = "force_connect" + const val EXTRA_CONNECT_FOR_AUTH = "connect_for_auth" + } +} diff --git a/app/src/main/java/com/nendo/argosy/data/steam/ProgressLogListener.java b/app/src/full/java/com/nendo/argosy/data/steam/ProgressLogListener.java similarity index 100% rename from app/src/main/java/com/nendo/argosy/data/steam/ProgressLogListener.java rename to app/src/full/java/com/nendo/argosy/data/steam/ProgressLogListener.java diff --git a/app/src/main/kotlin/com/nendo/argosy/data/steam/LicenseSerializer.kt b/app/src/full/kotlin/com/nendo/argosy/data/steam/LicenseSerializer.kt similarity index 100% rename from app/src/main/kotlin/com/nendo/argosy/data/steam/LicenseSerializer.kt rename to app/src/full/kotlin/com/nendo/argosy/data/steam/LicenseSerializer.kt diff --git a/app/src/main/kotlin/com/nendo/argosy/data/steam/SteamAuthManager.kt b/app/src/full/kotlin/com/nendo/argosy/data/steam/SteamAuthManager.kt similarity index 100% rename from app/src/main/kotlin/com/nendo/argosy/data/steam/SteamAuthManager.kt rename to app/src/full/kotlin/com/nendo/argosy/data/steam/SteamAuthManager.kt diff --git a/app/src/main/kotlin/com/nendo/argosy/data/steam/SteamContentManager.kt b/app/src/full/kotlin/com/nendo/argosy/data/steam/SteamContentManager.kt similarity index 100% rename from app/src/main/kotlin/com/nendo/argosy/data/steam/SteamContentManager.kt rename to app/src/full/kotlin/com/nendo/argosy/data/steam/SteamContentManager.kt diff --git a/app/src/main/kotlin/com/nendo/argosy/data/steam/SteamDepotManager.kt b/app/src/full/kotlin/com/nendo/argosy/data/steam/SteamDepotManager.kt similarity index 100% rename from app/src/main/kotlin/com/nendo/argosy/data/steam/SteamDepotManager.kt rename to app/src/full/kotlin/com/nendo/argosy/data/steam/SteamDepotManager.kt diff --git a/app/src/main/kotlin/com/nendo/argosy/data/steam/SteamLibraryManager.kt b/app/src/full/kotlin/com/nendo/argosy/data/steam/SteamLibraryManager.kt similarity index 100% rename from app/src/main/kotlin/com/nendo/argosy/data/steam/SteamLibraryManager.kt rename to app/src/full/kotlin/com/nendo/argosy/data/steam/SteamLibraryManager.kt diff --git a/app/src/main/kotlin/com/nendo/argosy/data/steam/SteamService.kt b/app/src/full/kotlin/com/nendo/argosy/data/steam/SteamService.kt similarity index 100% rename from app/src/main/kotlin/com/nendo/argosy/data/steam/SteamService.kt rename to app/src/full/kotlin/com/nendo/argosy/data/steam/SteamService.kt diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt new file mode 100644 index 000000000..ac9969a80 --- /dev/null +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -0,0 +1,51 @@ +Argosy Launcher is a gamepad-first Android home screen for retro gaming handhelds. Sync your entire game library from your self-hosted RomM server, download games and BIOS files on demand, track your achievements, and play across devices with automatic save sync — all from a controller-native interface designed for Anbernic, Retroid Pocket, Odin, AYN, and similar devices. + +Native RomM client +First-class integration with RomM. Sync your whole library with rich IGDB metadata: cover art, descriptions, genres, franchises, player counts, and more. Your collection, your server, your handheld. + +Automatic downloads +Download ROMs and BIOS files directly from your RomM server. Games are sorted by platform automatically. Queue multiple downloads and let Argosy handle the rest. + +Save sync +Continue playing across devices. Bidirectional save sync keeps your progress up to date, with conflict detection so you never lose data. + +RetroAchievements +View earned achievements and track your progress, synced from your RomM server. + +Collections +Organize your library your way with custom collections or smart ones like Top Unplayed, Recently Added, and Most Played. Pin favorites to the home screen for quick access. + +Gamepad-first design +Built for controllers from the ground up. Navigate the whole library, manage downloads, and launch games without touching the screen. Full D-pad, analog stick, and button support. + +Smart emulator management +
    +
  • Auto-detects installed emulators and assigns them per platform
  • +
  • Per-platform RetroArch core selection
  • +
  • Automatic multi-disc handling with a disc picker
  • +
  • Works with RetroArch, PPSSPP, DuckStation, AetherSX2, Dolphin, DraStic, melonDS, Mupen64Plus FZ, Pizza Boy, Lime3DS, Azahar, Flycast, Redream, and more
  • +
+ +Make it yours +
    +
  • Video wallpaper: YouTube previews as dynamic backgrounds
  • +
  • Ambient audio: background music while you browse
  • +
  • Themes: light, dark, or system-matched
  • +
  • Background blur, saturation, and opacity controls
  • +
  • Box art styles, grid density, and navigation sound effects
  • +
+ +Quick Menu (L3) — press the left stick anywhere to search, pick a random game, or jump to Most Played, Top Unplayed, Recent, and Favorites. + +Quick Settings (R3) — press the right stick anywhere to switch theme, toggle haptics, UI sounds, and background music. On supported Odin, AYN, and Retroid devices it also exposes Performance Mode and Fan Control. + +More +
    +
  • Offline mode with full access to downloaded games and cached metadata
  • +
  • Local image caching for fast, offline browsing
  • +
  • Library filtering by genre, player count, franchise, or region
  • +
  • User ratings synced back to RomM
  • +
  • App launcher, in-app updates, first-run setup wizard, favorites, and hide games
  • +
+ +Requires Android 8.0 (Oreo) or higher. A RomM server is optional and only needed for sync features. Argosy runs on any Android device, but the gamepad-first interface is optimized for handheld gaming and Android TV. diff --git a/fastlane/metadata/android/en-US/images/featureGraphic.png b/fastlane/metadata/android/en-US/images/featureGraphic.png new file mode 100644 index 000000000..fc0d7e6b9 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/featureGraphic.png differ diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png new file mode 100644 index 000000000..d7e4cd18b Binary files /dev/null and b/fastlane/metadata/android/en-US/images/icon.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png new file mode 100644 index 000000000..edd5c274c Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png new file mode 100644 index 000000000..adb5c08cc Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png new file mode 100644 index 000000000..87a8d4a83 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png new file mode 100644 index 000000000..9f6cd72ec Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png new file mode 100644 index 000000000..8fb911760 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png new file mode 100644 index 000000000..6ec2e1be5 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png new file mode 100644 index 000000000..c24859984 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png new file mode 100644 index 000000000..6b1b625a3 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png differ diff --git a/fastlane/metadata/android/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt new file mode 100644 index 000000000..0235773f7 --- /dev/null +++ b/fastlane/metadata/android/en-US/short_description.txt @@ -0,0 +1 @@ +Gamepad-first retro-gaming launcher with native RomM library sync diff --git a/fastlane/metadata/android/en-US/title.txt b/fastlane/metadata/android/en-US/title.txt new file mode 100644 index 000000000..d3899ba05 --- /dev/null +++ b/fastlane/metadata/android/en-US/title.txt @@ -0,0 +1 @@ +Argosy Launcher diff --git a/fdroid/README.md b/fdroid/README.md new file mode 100644 index 000000000..817988342 --- /dev/null +++ b/fdroid/README.md @@ -0,0 +1,56 @@ +# F-Droid submission — handoff notes + +This directory holds the **F-Droid build recipe** for Argosy Launcher and the notes +needed to submit it. Nothing here ships in the app; it is packaging material. + +- `com.nendo.argosy.yml` — the build-metadata recipe. It belongs in the + [`fdroiddata`](https://gitlab.com/fdroid/fdroiddata) repo at + `metadata/com.nendo.argosy.yml`, **not** in this app repo. It lives here only as a + reviewed, ready-to-copy artifact. + +The media metadata (descriptions, icon, feature graphic, screenshots) already lives in +this repo under `fastlane/metadata/android/en-US/` and F-Droid pulls it automatically. + +## App facts the recipe encodes + +| Field | Value | Source | +|-------|-------|--------| +| Application ID | `com.nendo.argosy` | `app/build.gradle.kts` | +| versionName / base versionCode | `1.18.0` / `298` | `app/build.gradle.kts` | +| License | `GPL-3.0-only` (confirmed) | `LICENSE` (verbatim GPLv3, no "or later") | +| minSdk / targetSdk | 26 / 35 | `app/build.gradle.kts` | +| Release tag | `v1.18.0` | `git tag` | +| Submodules | `sigil`, `libretrodroid/.../rcheevos` | `.gitmodules` | + +## Submission steps (fdroiddata lives on GitLab: gitlab.com/fdroid/fdroiddata) + +Per fdroiddata's `CONTRIBUTING.md`: + +1. Register on GitLab, **fork** `gitlab.com/fdroid/fdroiddata`, clone your fork: + ```shell + git clone https://gitlab.com/YOUR_USERNAME/fdroiddata.git + cd fdroiddata + ``` +2. Create a branch **named after the app id** — do NOT work on `master` (it is protected + and you cannot open an MR from it): + ```shell + git checkout -b com.nendo.argosy + ``` +3. Add the recipe as `metadata/com.nendo.argosy.yml` (copy this repo's + `fdroid/com.nendo.argosy.yml`). Optionally scaffold instead with + `fdroid import --url https://github.com/rommapp/argosy-launcher --subdir app`. +4. With `fdroidserver` installed (`pip install git+https://gitlab.com/fdroid/fdroiddata.git`), + run the local checks: + ```shell + fdroid readmeta # syntax + fdroid rewritemeta com.nendo.argosy # canonical formatting + fdroid checkupdates com.nendo.argosy # fills Auto Name / Current Version + fdroid lint com.nendo.argosy # fix all warnings + fdroid build -v -l com.nendo.argosy # must produce at least one working build + ``` +5. Commit with a clear message (the "New App: com.nendo.argosy" convention is common), + push the branch to your fork, and check **CI/CD → Pipelines** passes; fix metadata until + it does. +6. Open a **merge request** against fdroiddata from your `com.nendo.argosy` branch and + **fill in the MR template**. Squash is on by default. Reply promptly to packager + questions. diff --git a/fdroid/RFP.md b/fdroid/RFP.md new file mode 100644 index 000000000..7c6392867 --- /dev/null +++ b/fdroid/RFP.md @@ -0,0 +1,76 @@ + + +* [x] The app complies with the [inclusion criteria](https://f-droid.org/docs/Inclusion_Policy/?title=Inclusion_Policy). +* [x] The app is not already [listed](https://gitlab.com/search?scope=issues&group_id=28397) in the repo or issue tracker. +* [x] The app has not already [been requested](https://gitlab.com/search?scope=issues&project_id=2167965) +* [x] The upstream app source code repo contains the app metadata _(summary/description/images/changelog/etc)_ in a [Fastlane](https://gitlab.com/snippets/1895688) or [Triple-T](https://gitlab.com/snippets/1901490) folder structure +* [x] The original app author has been notified, and does not oppose the inclusion. +* [ ] Optionally [donated](https://f-droid.org/donate/) to support the maintenance of this app in F-Droid. + +--------------------- + +#### APPLICATION ID: com.nendo.argosy + +```yaml +Categories: + - Games + +License: GPL-3.0-only + +AuthorName: nendo +AuthorEmail: +AuthorWebSite: + +WebSite: +SourceCode: https://github.com/rommapp/argosy-launcher + +IssueTracker: https://github.com/rommapp/argosy-launcher/issues + +Donate: +Bitcoin: +LiberaPay: + +AutoName: Argosy Launcher + +RepoType: git + +Repo: https://github.com/rommapp/argosy-launcher.git +``` + +Why do you want this app added to F-Droid: + +> It is a gamepad-first home-screen launcher built for retro gaming handhelds (Anbernic, Retroid Pocket, Odin, AYN, Android TV). It integrates with self-hosted RomM game servers, so users can browse and manage their own game libraries entirely on their own infrastructure. There is currently no comparable controller-native launcher on F-Droid, and its audience of handheld-Linux/Android tinkerers overlaps strongly with F-Droid's. + +Summary: + +> Gamepad-first retro-gaming launcher with native RomM library sync + +Description: + +> Argosy Launcher is a gamepad-first home screen for retro gaming handhelds. It syncs a game library from a self-hosted RomM server, downloads games and BIOS files on demand, tracks achievements, and keeps save files in sync across devices — all from a controller-native interface designed for Anbernic, Retroid Pocket, Odin, AYN, and Android TV devices. +> +> * Native RomM client with rich IGDB metadata (cover art, genres, franchises, player counts) +> * On-demand ROM and BIOS downloads, sorted by platform, with a download queue +> * Bidirectional save-file sync with conflict detection +> * Achievement tracking synced from RomM +> * Custom and smart collections (Top Unplayed, Recently Added, Most Played) +> * Automatic emulator detection and per-platform RetroArch core selection +> * Automatic multi-disc handling with a disc picker +> * Full D-pad, analog-stick, and button navigation; Quick Menu (L3) and Quick Settings (R3) +> * Offline mode with local cover-art caching +> * Customization: video wallpaper, ambient audio, themes, and box-art styles +> +> Requires Android 8.0 or higher. A RomM server is optional and only needed for sync features. + +--------------------- + +### Packaging notes (for the reviewer/packager) + +* A build recipe is already prepared and will be submitted as a `fdroiddata` merge request: two ABI-split builds (`armeabi-v7a`, `arm64-v8a`) with `submodules: true` and stable-tag autoupdate. +* The app is built in a **`foss` product flavor** that excludes an optional Steam integration. Steam relies on a prebuilt JavaSteam jar that is not on Maven Central, so it is confined to the non-F-Droid `full` flavor; the `foss` flavor F-Droid builds contains no prebuilt binaries (`scandelete: [libs/maven]` as a safety net). +* Optional social features (friends, activity feed, presence, netplay matchmaking) connect to the developer's `api.argosy.dev` backend, so the recipe declares **`AntiFeatures: NonFreeNet`**. The core launcher and self-hosted RomM sync work without it. +* Native components build from source: `libretrodroid` (C++/Oboe, CMake/NDK), the `rcheevos` submodule (C), and `sigil` (C, MPL-2.0). No Rust toolchain is required. diff --git a/fdroid/com.nendo.argosy.yml b/fdroid/com.nendo.argosy.yml new file mode 100644 index 000000000..c9615b310 --- /dev/null +++ b/fdroid/com.nendo.argosy.yml @@ -0,0 +1,55 @@ +AntiFeatures: + NonFreeNet: The optional social features (friends, activity feed, presence, and netplay matchmaking) connect to the proprietary api.argosy.dev backend. The core launcher and self-hosted RomM library sync work without it; the service is only contacted after the user signs in via QR code. +Categories: + - Games +License: GPL-3.0-only +AuthorName: nendo +SourceCode: https://github.com/rommapp/argosy-launcher +IssueTracker: https://github.com/rommapp/argosy-launcher/issues +Changelog: https://github.com/rommapp/argosy-launcher/releases + +RepoType: git +Repo: https://github.com/rommapp/argosy-launcher.git + +# FIXME (finalize when v2.0.0 stable is tagged with the foss flavor + fastlane merged in): +# The base versionCode for 2.0.0 is not final yet — beta.3 is 301, so stable will be >= 302. +# Set BASE below to 2.0.0's app/build.gradle.kts versionCode, then the split codes are +# armeabi-v7a = 1_000_000 + BASE and arm64-v8a = 2_000_000 + BASE. The 302-based values +# here are placeholders; a wrong value fails F-Droid's versionCode check loudly (safe). +Builds: + - versionName: 2.0.0 + versionCode: 1000302 + commit: v2.0.0 + subdir: app + submodules: true + gradle: + - foss + gradleprops: + - allAbis + scandelete: + - libs/maven + # armeabi-v7a split => abiCode 1 => 1_000_000 + BASE (placeholder BASE=302 => 1000302). + # See app/build.gradle.kts (splits { abi } + applicationVariants override). + + - versionName: 2.0.0 + versionCode: 2000302 + commit: v2.0.0 + subdir: app + submodules: true + gradle: + - foss + gradleprops: + - allAbis + scandelete: + - libs/maven + # arm64-v8a split => abiCode 2 => 2_000_000 + BASE (placeholder BASE=302 => 2000302). + +# Autoupdate builds future stable tags automatically. The regex excludes -beta tags, +# so v2.0.0-beta.N are ignored and only v2.0.0 (and later stable v*) are packaged. +AutoUpdateMode: Version +UpdateCheckMode: Tags ^v[0-9.]+$ +VercodeOperation: + - "%c + 1000000" + - "%c + 2000000" +CurrentVersion: 2.0.0 +CurrentVersionCode: 2000302